Purge internal reconciliation prompts from portable records

Hop-State: A_06FN83ZZSBQMQG8WN406CY8
Hop-Proposal: R_06FN83YD6CMFSR5CTE0ZWHR
Hop-Task: T_06FN83DN7SMZB9WJRZNZMTR
Hop-Attempt: AT_06FN83DN7VHVF5BVW6DEJ8R
This commit is contained in:
Hop
2026-07-11 19:02:42 -07:00
parent 74ba06de91
commit 787acb2330
3 changed files with 49 additions and 0 deletions
@@ -0,0 +1,17 @@
{
"id": "P_06FN83DN7R0B9X5TEV3YDC0",
"task_id": "T_06FN83DN7SMZB9WJRZNZMTR",
"attempt_id": "AT_06FN83DN7VHVF5BVW6DEJ8R",
"state_id": "P_06FN83DN7R0B9X5TEV3YDC0",
"prompt": "# Files mentioned by the user:\n\n## Screenshot 2026-07-11 at 6.58.29PM.png: /var/folders/58/b6yn15tx3jb7_6lw9m67f89m0000gn/T/TemporaryItems/NSIRD_screencaptureui_vyA0oe/Screenshot 2026-07-11 at 6.58.29PM.png\n\n## My request for Codex:\nonce again, there are prompts here that arent mine!",
"agent_name": "codex",
"status": "proposed",
"response_summary": "Purge internal reconciliation prompts from portable records",
"created_at": "2026-07-12T02:00:12.350322Z",
"metadata": {
"source_tree": "27e94b6d19eb7e4107b127e3cec0ca41718053dc",
"git_commit": "74ba06de917236754f6146aca0e2d6e10438e455",
"attempt_head": "C_06FN83MVSDWQH772HR663SR",
"attempt_head_kind": "checkpoint"
}
}
+9
View File
@@ -81,6 +81,7 @@ func (s *Service) exportPromptLedger(ctx context.Context, destinationRoot string
wantedAttempts[attemptID] = struct{}{}
}
lastPromptByAttempt := make(map[string]string)
excludedPromptIDs := make(map[string]struct{})
for _, row := range graph {
if row.State.Kind == StatePrompt && row.State.Prompt != "" && row.State.AttemptID != "" {
lastPromptByAttempt[row.State.AttemptID] = row.State.ID
@@ -92,9 +93,11 @@ func (s *Service) exportPromptLedger(ctx context.Context, destinationRoot string
continue
}
if _, hidden := suppressed[state.ID]; hidden {
excludedPromptIDs[state.ID] = struct{}{}
continue
}
if _, reconciliation := decodeReconciliationConflicts(state.Summary); reconciliation || strings.HasPrefix(state.Prompt, "Resolve proposal ") {
excludedPromptIDs[state.ID] = struct{}{}
continue
}
if len(wantedAttempts) > 0 {
@@ -156,6 +159,12 @@ func (s *Service) exportPromptLedger(ctx context.Context, destinationRoot string
if err := os.MkdirAll(outputDir, 0o755); err != nil {
return PortablePromptLedger{}, fmt.Errorf("create prompt ledger directory: %w", err)
}
for promptID := range excludedPromptIDs {
outputPath := filepath.Join(outputDir, promptID+".json")
if err := os.Remove(outputPath); err != nil && !os.IsNotExist(err) {
return PortablePromptLedger{}, fmt.Errorf("remove excluded prompt record %s: %w", promptID, err)
}
}
for _, record := range ledger.Prompts {
outputPath := filepath.Join(outputDir, record.ID+".json")
_, statErr := os.Stat(outputPath)
+23
View File
@@ -279,6 +279,29 @@ func TestExportOmitsActiveInternalAttempt(t *testing.T) {
}
}
func TestExportRemovesPreviouslyPublishedReconciliationPrompt(t *testing.T) {
ctx := context.Background()
service, _ := newTestProject(t, map[string]string{"base.txt": "base\n"})
result, err := service.CreatePrompt(ctx, "Resolve proposal R_TEST against accepted state A_TEST", "", "codex")
if err != nil {
t.Fatal(err)
}
recordDir := filepath.Join(service.Root, ".hop", "records", "prompts")
if err := os.MkdirAll(recordDir, 0o755); err != nil {
t.Fatal(err)
}
recordPath := filepath.Join(recordDir, result.Prompt.ID+".json")
if err := os.WriteFile(recordPath, []byte("{}\n"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := service.ExportPromptLedger(ctx, service.Root); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(recordPath); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("internal reconciliation record still exists: %v", err)
}
}
func TestProposeRespectsSuppressedPromptManifest(t *testing.T) {
ctx := context.Background()
service, _ := newTestProject(t, map[string]string{"base.txt": "base\n"})