docs(sprint): record #307, #304, #309, #306

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgDL1v3GuQ9RZnYR6fDT95
This commit is contained in:
2026-07-26 23:30:35 +04:00
parent f78c7f15ad
commit 4a730084f1
+42
View File
@@ -121,6 +121,48 @@ every flat alias still pointed at npm, so a Kotlin run's auto-gate would have ru
`ProjectProfileLoader`; the gate prefers `<toolchain>.<alias>` and falls back to flat. #267's "re-scope
#40" is now just the live confirmation.
### Goal 3 + Goal 2 progress — 2026-07-26
- **#307 ✅** (commits `c742656e`, `68b5392e`). `ContextAssembledEvent` records the injected manifest —
`{sourceType, sourceId, tokenEstimate, layer, role}` per entry, no content (that stays in CAS). Scope
check confirmed nothing existing carried it; `ContextTruncatedEvent` only reports drop counts. Emitted
at **all four** `contextPackBuilder.build` sites, not just the stage's first: the motivating question
("did the steer-away hint fire on 7 consecutive turns?") is a per-rebuild question, and one event per
stage couldn't answer it. Turned out to be the delivery-tracking substrate #306 needed.
- **#304 ✅** (commit `2b13f610`). Chose option (b) — recovery is a real second chance.
`detectRepeatedToolFailure` windows its fold to events after the most recent `FailureTicketOpenedEvent`
naming the stage. Route budgets are charged off the ticket event by the reducer, so the reset can't
open an infinite route-in/route-out cycle: 2+2 route cycles, each needing 6 fresh failures to re-trip.
- **#309 ✅** (commits `ee69f9be`, `9db4e3dd`). `RecoveryFileLoopBreak.kt``fileRepairOutcomes`
correlates each `FileWrittenEvent` with the next `LspDiagnosticsCompletedEvent` per path, feeding both
consumers off one fold: the in-recovery guard (a path rewritten 3x without clearing opens
`FailureTicketOpened(gate=recovery_loop_break, escalated=true)` and fails terminally instead of
looping) and the ledger annotation in `buildRetryFeedbackEntry`, still `EntryRole.USER` with #313's
precedence untouched. **Correction landed on top:** the fold conflated "no diagnostic run since this
write" with "ran clean" — so the ledger said *"done, leave it"* about unverified files, and the breaker
could kill a run on the *absence* of evidence. Now a distinct `unchecked` state; the breaker requires
`!unchecked`.
- Left deliberately: the guard is terminal, not an operator-approval pause. Recovery is the last tier,
so there is nowhere to route; it opens the ticket for the record, then fails. Human-in-the-loop there
is a follow-up if wanted.
- **#306 ✅** (commits `bc5afa51`, `f78c7f15`). Two halves, and only both together fix the report.
*Across stage entries:* the hint is keyed to its `RetryAttemptedEvent` occurrence, delivery derived by
folding prior `ContextAssembledEvent` manifests (`sourceType="unconfirmedFix"`, `sourceId=classKey`) —
no new state, pure fold (invariant #9). *Within one stage entry:* the guard alone was not enough —
`unconfirmedFixEntries` is called once at stage entry and its result folded into `accumulatedEntries`,
which every `pushBack` rebuild re-uses, so the hint rode into every turn regardless. That is the actual
7-turn symptom; the entry is now dropped once its first pack is built.
- Directions 2/3 from the ticket needed no code: `classKey` already derives from the current retry's
own class, and routing dead-ends carry `gate="stage"` while every other path carries its real gate,
so `"$gate:$signature"` can't collapse them. Locked in with a regression test rather than a rewrite.
**Goal 3 remaining:** #299 + #300 (provider-death path). #308 partly pre-empted by `ac460156` — a shell
timeout is now recoverable and coaches `nohup &` detach, so there is no background-process registry to
build unless a real gate needs one.
**Goal 2 remaining:** #261 (impl decomposition), plus status calls on #260 and #305 — both have landed
commits (`516af1ca`; `5df35879`/`8806de16`/`12775d56`/`f5aaa255`) but neither ticket is closed.
---
## Landed out-of-band — context message-type sweep (#312, #313)