Skip to content

fix(investigation): the symptom interview never ran for work shaped in discovery#575

Open
leeovery wants to merge 1 commit into
test/prose-declare-what-walksfrom
fix/investigation-symptom-guard
Open

fix(investigation): the symptom interview never ran for work shaped in discovery#575
leeovery wants to merge 1 commit into
test/prose-declare-what-walksfrom
fix/investigation-symptom-guard

Conversation

@leeovery

@leeovery leeovery commented Jul 27, 2026

Copy link
Copy Markdown
Owner

The defect

Step 3 asks whether the Symptoms section is already populated, treating that as "a previous session gathered these — don't re-interview".

But Step 1 populates Symptoms itself, from the discovery carrier and the seed, precisely so the user isn't asked to repeat what they already said. So every path into Step 3 arrives with the section populated:

Path Symptoms at Step 3
fresh (no file) populated by Step 1 from the carrier
restart file deleted, Step 1 rebuilds and populates again
continue earlier session's content stands

The guard is true in all three, so the interview is skipped in all three. For a bugfix shaped in discovery — which is how bugfixes reach investigation — symptom gathering never runs. It only works when there was no carrier and the section was left as template placeholders.

The fix

The guard was asking about the file when the question is about the session.

Step 0 already knows which it is: no file means fresh; a continue returns for Step 2 with the earlier session's symptoms standing; a restart deletes the file and returns for Step 1 to rebuild it. That distinction is now held as resumed, and Step 3 branches on it.

An engine fact couldn't serve here. After Step 1 the topic status is in-progress on both paths, so manifest get can't discriminate. Which arm Step 0 took is the only thing that can.

Scope — checked, not assumed

Contained to this skill. Discussion and research load the same shared resume reference, but their equivalent steps are unconditional guidance loads rather than an interview, so they have nothing to distinguish.

The other four "already populated" guards are sound. discovery_map non-empty, a key in items, review_cycle set — all engine state, none of it writable by the step immediately before. Only this one keyed on content.

Nothing downstream reads it. Symptoms appears only at this guard and in initialisation.

Also

Step 0's file-exists arm gains the routing footer it lacked. resume-detection.md routes every exit itself, which is exactly the shape that takes → On return, proceed as the reference directed. (#570) — its second instance, found incidentally.

Test plan and its limit

  • Conventions lint 29/29; prose gate 19/19
  • investigation-initialises-the-phase re-run to confirm the fresh arm and new footer walk cleanly

Not proven by test: the case stops before Step 3, so the resumed arm is unexercised. Catching this defect requires a case that starts with an existing investigation file and takes the continue path — a different fixture, and the one that would actually fail on the old prose. Worth adding; not in this PR.

🤖 Generated with Claude Code

Stack

  1. docs(design): prose-tests programme design log #544
  2. feat(prose-tests): the framework — cases, worlds, runner, skill #545
  3. test(prose): feature happy-path corpus — five worlds, seven cases #546
  4. test(prose): bugfix corpus — the investigation-centric surfaces #548
  5. test: retry recursive teardown removals — kill a class of phantom failures #549
  6. fix(entry-skills): close the handoff fences — six files render their arms wrong #550
  7. docs: a contributing page for working on the system #551
  8. fix(entry-skills): every handoff arm says to invoke the skill #552
  9. fix(implementation): environment setup belongs to the setup reference alone #553
  10. fix(prose-tests): the asserter is told which substitutions were armed #554
  11. feat(prose-tests): the mid-flow substitution, and a world only prose can describe #555
  12. test(prose): claims assert consequences, not what was displayed #556
  13. feat(prose-tests): record everything the agents do, results included #557
  14. fix(discussion-entry): the handoff reports the source it actually had #558
  15. fix(prose-tests): the stop hook records, and names the model that walked #559
  16. fix(prose-tests): command output was never actually recorded #560
  17. feat(prose-tests): judge the walk as told, not the summary returned #561
  18. feat(prose-tests): decide in code what an agent should not be deciding #562
  19. test(prose): a case starts where a session starts #563
  20. feat(prose-tests): walk on Sonnet, judge on Opus, escalate a failure #564
  21. test(prose): give the eight read-only cases something that can fail #565
  22. test(prose): only walks that can be observed, and checks that survive the trip #566
  23. fix(prose-tests): the verdict names only the model the record names #567
  24. test(prose): discovery, walked to the point where work first exists #568
  25. fix(prose-tests): the asserter judges which of prose or walker was at fault #569
  26. docs(conventions): a step whose reference routes every exit still signposts #570
  27. test(prose): discovery's epic arm, to the same durability boundary #571
  28. fix(prose-tests): keep the walk's closing turn, and name the one live difference #572
  29. fix(prose-tests): prescribe the cross-check, drop a check that cannot fire, lint the scope #573
  30. test(prose): declare the prose each case actually walks #574
  31. fix(investigation): the symptom interview never ran for work shaped in discovery #575 👈 current
  32. feat(prose-tests): conduct — playing a person where a script cannot reach #576
  33. fix(prose-tests): what a write put in a file is evidence, not incident #577
  34. fix(investigation): the interview starts from the carrier, not over it #578
  35. test(prose): quick-fix scoping, the whole definition stage in one walk #579
  36. fix(prose-tests): the world log is the walker's record #580
  37. fix(prose-tests): a confirmed failure reports both runs' checks #581
  38. fix(prose-tests): each prescribed command runs as written #582
  39. fix(scoping): context gathering reads the whole carrier, asks only the gaps #583

This was referenced Jul 27, 2026
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from efa86fb to 0299954 Compare July 27, 2026 15:44
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 9a1439c to 73376d3 Compare July 27, 2026 15:46
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 0299954 to d4ba2c2 Compare July 27, 2026 15:46
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 73376d3 to f73fabc Compare July 27, 2026 15:47
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from d4ba2c2 to 492bab7 Compare July 27, 2026 15:47
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from f73fabc to d6902fc Compare July 27, 2026 15:49
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 492bab7 to 232ea8a Compare July 27, 2026 15:49
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from d6902fc to 29ea473 Compare July 27, 2026 15:50
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 232ea8a to 6103e42 Compare July 27, 2026 15:50
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 29ea473 to 9b65f33 Compare July 27, 2026 15:52
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 6103e42 to 4e42b65 Compare July 27, 2026 15:52
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 9b65f33 to e1768aa Compare July 27, 2026 15:53
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 4e42b65 to f290f6c Compare July 27, 2026 15:53
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from e1768aa to f183907 Compare July 27, 2026 15:54
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from f290f6c to a5fc301 Compare July 27, 2026 15:54
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from f183907 to 0d521e0 Compare July 27, 2026 15:56
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from a5fc301 to 399540b Compare July 27, 2026 15:56
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 0d521e0 to 2898e16 Compare July 27, 2026 15:57
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 399540b to 1518746 Compare July 27, 2026 15:57
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 2898e16 to 191def2 Compare July 27, 2026 15:58
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 1518746 to 0c550a2 Compare July 27, 2026 15:58
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 191def2 to f0538ab Compare July 27, 2026 15:59
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 0c550a2 to 8070b75 Compare July 27, 2026 15:59
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from f0538ab to 2bdd2b0 Compare July 27, 2026 16:00
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from 8070b75 to dfb167e Compare July 27, 2026 16:00
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 2bdd2b0 to 55c5f21 Compare July 27, 2026 16:01
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from dfb167e to f20123d Compare July 27, 2026 16:01
…n discovery

Step 3 asks whether the Symptoms section is already populated and takes
that as "a previous session gathered these — don't re-interview". But
Step 1 populates Symptoms itself, from the discovery carrier and the
seed, precisely so the user is not asked to repeat what they already
said. Every path into Step 3 therefore arrives with the section
populated: a fresh start, a restart that deletes and rebuilds the file,
and a continue where an earlier session's content stands.

So the guard is true in all three, and the interview is skipped in all
three. For a bugfix shaped in discovery — which is how bugfixes reach
investigation — the symptom gathering step never runs at all. It works
only when there was no carrier to seed from and the section was left as
template placeholders.

The guard was asking about the file when the question is about the
session. Step 0 already knows: no file means fresh, a continue returns
for Step 2 with the earlier session's symptoms standing, a restart
deletes the file and returns for Step 1 to rebuild it. That distinction
is now held as `resumed` and Step 3 branches on it, so a resumed session
skips the interview and a seeded one still has it.

An engine fact could not have served here: after Step 1 the topic status
is in-progress on both paths, so it cannot tell them apart. Which arm
Step 0 took is the only thing that can.

Contained to this skill. Discussion and research load the same shared
resume reference but their equivalent steps are unconditional guidance
loads rather than an interview, so they have nothing to distinguish. The
four other "already populated" guards in the system key on engine state —
a non-empty map, a key in items, a set review cycle — which cannot be
written by the step that precedes them. Only this one keyed on content.

Step 0's file-exists arm also gains the routing footer it lacked. The
resume reference routes every exit itself, which is the shape that takes
`→ On return, proceed as the reference directed.`

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@leeovery
leeovery force-pushed the test/prose-declare-what-walks branch from 55c5f21 to 8f006ce Compare July 27, 2026 16:02
@leeovery
leeovery force-pushed the fix/investigation-symptom-guard branch from f20123d to 88b3b1a Compare July 27, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant