feat: bounded Build & Test → Code Generation failure loop-back (2.5.16) - #616
feat: bounded Build & Test → Code Generation failure loop-back (2.5.16)#616jstrunk wants to merge 3 commits into
Conversation
Review: bounded Build & Test -> Code Generation loop-backReviewed at head 579dd58. Since the PR is protocol prose + tests with no engine changes, every engine claim in the prose was verified against the tools it names, and they hold up well:
Deterministic tiers reproduce the PR's numbers in my checkout: smoke+unit 173 files / 4256 assertions green, t245 24/24, the pinned-prose suites (t34/t76/t44/t87/t68) and protocol readers green, Findings, in severity order. Must-fix1. Gated "Retry with fix" collides with the engine's settle-to-gate routing, so the fix is never applied on the replay. Because jumps preserve artifacts, every code-generation unit is still "covered" on disk after the backward jump. The off-swarm per-unit router therefore finds no uncovered unit and settles straight to a 2. Version slot is stale and the PR is CONFLICTING. The body's assumption (companion PRs taking 2.5.1/2.5.2) is already broken: v2 is at 2.5.2 today (#595 merged as 2.5.1, #576 as 2.5.2). Per the CHANGELOG conflict policy this needs a rebase onto v2 plus a re-bump with the 3. The PR falsifies a sentence it does not update. Should-fix4. The no-fix branch cannot render the pinned template honestly. Rung 4 explicitly fires when "no identifiable fix exists" ( 5. 6. The crash-resume bullet is in the wrong recovery section. It was appended under "Stage re-run" ( 7. The swarm cheap path hides two unenforced premises. (a) Nits
Happy to re-review after the rebase; the engine-claim verification above should carry over unchanged since no tool code moves. |
| fix):** | ||
|
|
||
| ```question | ||
| prompt: "Build and Test failed: [short error]. Root cause: [diagnosis]. Candidate fix: [fix] — estimated price: [effort/cost/risk]. Loop-backs used: [N]/3. How would you like to proceed?" |
There was a problem hiding this comment.
UX: “price” normally implies a monetary value, but this prompt defines it as a combined estimate of effort, cost, and risk. Users may reasonably look for a dollar amount or misread what is being compared. Please rename this to estimated impact and expose the dimensions separately, for example: Estimated impact — effort: [...]; financial cost: [...]; risk: [...]. The related price / priced / unpriced wording and the Loop-Back Log’s Price field should be changed consistently.
Implements awslabs#611. Build and Test's Step 10 "On failure" handling becomes a 4-rung failure-escalation ladder: (1) in-stage fix, max 2 attempts, for root causes in the stage's own remit; (2) classify and price a candidate fix in a swappable dimension - never write a feasible path off on an unpriced effort assumption; (3) under Construction Autonomy Mode: autonomous, a bounded autonomous loop-back (max 3 per intent) that records the diagnosis + priced fix and replays through code-generation; (4) a priced 3-option halt-and-ask (Retry with fix [price] / Accept failure / Abort). - stage-protocol.md gains the sibling S1 subsection "Build-and-Test failure loop-back (3.6 -> 3.5)": the sanctioned carve-outs on the NO EMERGENT BEHAVIOR RULE and checklist item 5, the crash-safe append-only `## Loop-Back Log` artifact ledger in test-results.md (entry count IS the bound; STAGE_JUMPED rows stay the audit cross-check; human-directed jumps don't count), the ENGINE-routed jump procedure (next --stage code-generation emits the validated aidlc-jump.ts execute print), the Artifact Re-use auto-decision rule (Modify targeted units / Keep others / Modify build-and-test itself; Redo forbidden - it erases the ledger), the swarm check-first cheap path, and the priced halt-and-ask template. - stage-protocol-recovery.md: crash-resume bullet - a logged planned fix with no matching STAGE_JUMPED (Target: code-generation) after it means the session died between logging and jumping; re-execute the jump, don't re-diagnose; resume count is the ledger's entry count. - All five conductor SKILLs gain the parenthetical exception on the STAGE RITUAL IS ATOMIC bullet (codex gains the bullet itself, previously absent). - Single-stage (--single) runs stop at rung 2: no main-workflow position to move; priced options are logged and presented at that run's gate. - New prose-pin test tests/integration/t243-build-test-loopback-prose.test.ts (t34-style, mechanism none) pins the ladder, the S1 subsection + ledger paragraph, the recovery bullet, and the SKILL exception across authored + dist copies of every harness. - Docs: construction reference chapter Build and Test section rewritten to the ladder; stage-protocol + orchestrator reference No Emergent Behavior mentions name the second carve-out. - Version 2.5.4 + CHANGELOG entry + README badge; dist regenerated via bun scripts/package.ts (byte-parity --check green).
Addresses apackeer's review on PR awslabs#616 (a field engagement's build-and-test failure loop-back), rebased onto v2 at 9f91454 and re-bumped 2.5.4 -> 2.5.16 to avoid colliding with sibling PRs rebasing in parallel. Must-fix: - A gated "Retry with fix" replay hits the same engine routing as the autonomous path: because a backward jump preserves artifacts, every code-generation unit is still "covered" on disk, so the re-entry `next` call answers with `gate: true` straight to the approval gate, skipping the stage body and the ordinary Artifact Re-use question. stage-protocol.md now spells out the same override for the gated case (a new "Gated failure loop-back" paragraph mirroring "Autonomous failure loop-back"): the planned fix (Modify on the targeted unit(s), via the Artifact Re-use mechanism) must be applied BEFORE that gate is presented. - Rung 4 (autonomous run, bound exhausted or no identifiable fix) is now named as a second case, alongside the Bolt halt-and-ask, where `autonomous` mode stops to consult the user. Should-fix: - Added a no-fix halt-and-ask template variant (Accept failure / Abort, no "Candidate fix" slot, no "Retry with fix" option) for when rung 2 finds no identifiable fix; the priced 3-option template is used only when it did. - Reworded "presented at this/that run's gate" to "in this/that run's isolated-run summary" (build-and-test.md, docs/reference/04-stages/ construction.md, the CHANGELOG bullet) - isolated `--single` runs never present a workflow gate. - Moved the crash-resume ("logged-but-not-jumped") detection bullet from stage-protocol-recovery.md's "Stage re-run" section (user-requested changes after approval - the wrong scenario) to "Session resume" (session died mid-jump); left a cross-reference behind. - Swarm cheap-path prose now names the two unenforced premises: `prepare` hard-errors on a replay if a prior attempt's worktrees/branches still exist (discard or adopt them first), and the "already-green" claim holds only once the prior attempt's code merge actually completed (otherwise every `check` comes back red and the path degrades to full re-dispatch). Nit: - Spelled out the abbreviated `aidlc-state.ts reuse-artifact` audit call in full (positional slug + `--artifacts`) in both the autonomous and new gated paragraphs. - Renamed tests/integration/t245-build-test-loopback-prose.test.ts to t250 (t245 collided with unrelated merged work) and added assertions pinning every fix above; the commit-message/file-number mismatch nit is resolved by this rename. - dist regenerated via bun scripts/package.ts; byte-parity --check green.
579dd58 to
fdf801a
Compare
|
Thanks for the thorough review — addressed all of it. Summary below, plus the rebase. Rebase + re-bump: rebased onto current Test rename: Must-fix #1 (gated "Retry with fix" collides with settle-to-gate routing): Confirmed the issue — a backward jump preserves artifacts, so every code-generation unit is still "covered" on disk, and the re-entry Must-fix #2 (version slot): Done — 2.5.16, per above. Must-fix #3 (Bolt halt-and-ask "one case" sentence): Updated Should-fix #4 (no-fix halt-and-ask variant): Added a distinct no-fix template in Should-fix #5 ("presented at this run's gate" vs. isolated runs): Reworded to "in this/that run's isolated-run summary" in Should-fix #6 (crash-resume bullet in the wrong section): Moved the logged-but-not-jumped detection bullet from "Stage re-run" (wrong scenario — that's for user-requested changes after approval) to "Session resume" (the actual scenario — session died mid-jump). Left a short cross-reference in "Stage re-run" so a reader landing there isn't stranded. Should-fix #7 (swarm cheap-path unenforced premises): Added both sentences to the swarm-interaction paragraph: (a) check for and discard/adopt a prior attempt's leftover worktrees/ Nit (abbreviated audit call): Spelled out Nit (t243/t245 mismatch): Resolved by the rename above. Nit (unenforced bound/append-only/no-Redo rules): Left as-is per your note — consistent with the PR's declared scope. Verification:
Force-pushed to |
Re-review at fdf801aAll three must-fix and all four should-fix items from the round-1 comment body are verified fixed at this head, and the deterministic gates reproduce green in my checkout. One round-1 item is still open, though: the inline review comment on the "price" wording was not addressed, so I'm holding approval on that one item (details at the end). Everything else is done. Must-fix 1 (gated "Retry with fix" vs settle-to-gate routing) - fixed as asked, prose route. The new "Gated failure loop-back" paragraph sits as a sibling of the autonomous override in stage-protocol.md's Artifact Re-use tail, states the Must-fix 2 (version slot) - fixed. 2.5.16 across Must-fix 3 ("the one case" sentence) - fixed; no "one case where" phrasing remains anywhere in core/docs/harness, and the replacement names rung 4 precisely (bound exhausted or no identifiable fix, under Should-fix 4 (no-fix variant) - fixed. The no-fix template drops both the Should-fix 5 (isolated-run summary) - fixed; zero "at this/that run's gate" hits remain in core, docs, harness, or CHANGELOG, and the negative assertion in t250 guards regressions. Should-fix 6 (crash-resume placement) - fixed; the detection bullet now lives under "Session resume" (where a resuming conductor actually reads) with a cross-reference left in "Stage re-run". t250 pins the ordering structurally. Should-fix 7 (swarm premises) - fixed. The prepare-collision sentence is executable as written ( Nits - the audit call is spelled out in full in both override paragraphs (matches the tool's real usage line, My gate runs at fdf801a (worktree checkout): smoke+unit 178 files / 4396 assertions green (matches your numbers exactly), t250 36/36, the pinned-prose suites (t34/t44/t76/t87) + t68 + t181 conductor-skill parity green, Two small observations, neither blocking:
Outstanding: the "price" -> "estimated impact" rename (round-1 inline comment)The inline review comment on stage-protocol.md from round 1 asked to rename "price" (which reads as a monetary value) to estimated impact with the dimensions exposed separately ( Holding approval on that one item - everything else is resolved, so it should be a quick mechanical sweep. Happy to approve as soon as it lands. One process item: CI shows |
Follow-up to the allowlist review. Three things: Version slot: 2.5.16 was already claimed by #616 with an identical "## [2.5.16] - 2026-07-28" heading, so this re-bumps to 2.5.17 per the CHANGELOG conflict-trap rule (version file, README badge, heading). t252 permission model: evaluate() refused any command containing a separator or metacharacter before consulting the allowlist. That was wrong in both directions. Live kiro-cli 2.12.1 RUNS a chain whose every segment is allowlisted (`bun .kiro/tools/<t>.ts && date -u` executed unprompted), so the model reported "ask" for something the binary allows; and because the refusal was unconditional, six MUST_ASK entries passed without exercising a shipped pattern at all - they would stay green against an allowlist of `.*`, which is the failure mode this test exists to prevent. evaluate() now splits on `&&`/`;`/`|`/`&`/newline (quote-aware, and newline included because Rust's negated classes match it) and requires every segment to be allowed. Adds MUST_ALLOW_CHAINS for the live-verified all-segments-allowed case, newline and background-operator cases to MUST_ASK, and a meta-test asserting no MUST_ASK entry passes under a wide-open allowlist. Verified by mutation: re-adding the removed absolute-path pattern turns t252 red. TAIL_METACHARACTERS narrows to `$(`, backtick, `<`, `>` - the forms live 2.12.1 actually gates. A bare `$` is excluded because `bun $KIRO_PROJECT_DIR/.kiro/tools/<t>.ts` ran unprompted under a config that allowlisted it, so expansion alone does not gate. Rationale wording: the comment, doc note, and CHANGELOG said absolute paths stay gated because a regex "cannot prove those forms still target this project across supported Kiro releases". The real reason is that a pattern checks a path's shape, not its trustworthiness - a grant for any /.../.kiro/tools/*.ts also pre-approves a script planted in a world-writable directory, which is the verified finding. Also rewrites the stale 2.5.16 summary paragraph, which still described the superseded wider-allowlist approach.
Follow-up to the allowlist review. Three things: Version slot: 2.5.16 was already claimed by #616 with an identical "## [2.5.16] - 2026-07-28" heading, so this re-bumps to 2.5.17 per the CHANGELOG conflict-trap rule (version file, README badge, heading). t252 permission model: evaluate() refused any command containing a separator or metacharacter before consulting the allowlist. That was wrong in both directions. Live kiro-cli 2.12.1 RUNS a chain whose every segment is allowlisted (`bun .kiro/tools/<t>.ts && date -u` executed unprompted), so the model reported "ask" for something the binary allows; and because the refusal was unconditional, six MUST_ASK entries passed without exercising a shipped pattern at all - they would stay green against an allowlist of `.*`, which is the failure mode this test exists to prevent. evaluate() now splits on `&&`/`;`/`|`/`&`/newline (quote-aware, and newline included because Rust's negated classes match it) and requires every segment to be allowed. Adds MUST_ALLOW_CHAINS for the live-verified all-segments-allowed case, newline and background-operator cases to MUST_ASK, and a meta-test asserting no MUST_ASK entry passes under a wide-open allowlist. Verified by mutation: re-adding the removed absolute-path pattern turns t252 red. TAIL_METACHARACTERS narrows to `$(`, backtick, `<`, `>` - the forms live 2.12.1 actually gates. A bare `$` is excluded because `bun $KIRO_PROJECT_DIR/.kiro/tools/<t>.ts` ran unprompted under a config that allowlisted it, so expansion alone does not gate. Rationale wording: the comment, doc note, and CHANGELOG said absolute paths stay gated because a regex "cannot prove those forms still target this project across supported Kiro releases". The real reason is that a pattern checks a path's shape, not its trustworthiness - a grant for any /.../.kiro/tools/*.ts also pre-approves a script planted in a world-writable directory, which is the verified finding. Also rewrites the stale 2.5.16 summary paragraph, which still described the superseded wider-allowlist approach.
* fix(kiro): harden the execute_bash permission lists (2.5.16)
Kiro wraps every `toolsSettings.execute_bash` pattern as `\A<pat>\z` (upstream
crates/chat-cli/src/cli/chat/tools/execute/mod.rs:130), so matching is
full-string, not prefix. The shipped patterns were written as if they were
prefixes, which made them simultaneously too narrow and, in one place, too
broad. Verified live against kiro-cli 2.12.1.
Too narrow (each of these needed an interactive approval, and a session with no
approver -- `--no-interactive`, or an ACP client that ignores
`session/request_permission` -- refuses them outright and stalls the workflow):
- `bun run .kiro/tools/<tool>.ts`
- `bun ".kiro/tools/<tool>.ts"` (quoted path)
- `bun /abs/path/to/project/.kiro/tools/<tool>.ts`
- `cd <dir> && bun .kiro/tools/<tool>.ts`, the form a conductor reaches for
when the session cwd is not the project root
- a bare `date -u`, which the stage prose instructs but `date -u .*` could
never match
Too broad: `bun \.kiro/tools/.*` let the trailing wildcard swallow path
traversal. `bun .kiro/tools/../../outside-tool.ts` executed unprompted, i.e.
any file on the machine was reachable through the pre-approved prefix.
Approved script paths are now a single filename (`[A-Za-z0-9._-]+\.ts`, no
slash in the class), so `../` cannot appear. `.kiro/tools/` is flat in every
dist tree, so no real tool call is lost.
Also fixed:
- The Kiro IDE conductor's `KIRO_PROJECT_DIR` pattern had unescaped braces
(`\${?...}?`), an invalid regex that upstream silently drops via
`.filter(Result::is_ok)`. It was inert: that command form was never
actually pre-approved. Braces are now escaped.
- The 14 delegated personas carried a narrower list than the conductor (no
KIRO_PROJECT_DIR, absolute-path, or cd forms) and could be refused
mid-stage. They now share the conductor's shell surface on both harnesses.
- `deniedCommands` was anchored too, so `rm -rf /.*` missed `rm -rf ~/x`,
`rm -rf *`, and `rm -fr <path>`, and `git push .*` missed a bare
`git push`. Broadened to catch all of them.
Allowing a bare `cd <path>` is safe because 2.12.1 evaluates each `&&`/`;`/`|`
segment separately: `cd /tmp && curl example.com` is still refused on the curl
segment (live-verified, as is `cd /tmp && rm -f ...`).
t252 asserts this behaviourally -- it re-implements Kiro's matcher and runs
real command strings through it, rather than pinning literal regex text, since
a literal-text assertion cannot distinguish a working pattern from an inert
one (exactly how the IDE pattern above shipped dead). Its validity check
models the Rust regex crate's stricter brace handling, because JS RegExp
accepts `{?` as a literal and would call the broken pattern valid. t148 grows
a narrower guard against the traversal wildcard returning.
* fix(kiro): address allowlist review findings
* fix(kiro): model chain segmentation in t252, re-bump to 2.5.17
Follow-up to the allowlist review. Three things:
Version slot: 2.5.16 was already claimed by #616 with an identical
"## [2.5.16] - 2026-07-28" heading, so this re-bumps to 2.5.17 per the
CHANGELOG conflict-trap rule (version file, README badge, heading).
t252 permission model: evaluate() refused any command containing a
separator or metacharacter before consulting the allowlist. That was
wrong in both directions. Live kiro-cli 2.12.1 RUNS a chain whose every
segment is allowlisted (`bun .kiro/tools/<t>.ts && date -u` executed
unprompted), so the model reported "ask" for something the binary
allows; and because the refusal was unconditional, six MUST_ASK entries
passed without exercising a shipped pattern at all - they would stay
green against an allowlist of `.*`, which is the failure mode this test
exists to prevent.
evaluate() now splits on `&&`/`;`/`|`/`&`/newline (quote-aware, and
newline included because Rust's negated classes match it) and requires
every segment to be allowed. Adds MUST_ALLOW_CHAINS for the live-verified
all-segments-allowed case, newline and background-operator cases to
MUST_ASK, and a meta-test asserting no MUST_ASK entry passes under a
wide-open allowlist. Verified by mutation: re-adding the removed
absolute-path pattern turns t252 red.
TAIL_METACHARACTERS narrows to `$(`, backtick, `<`, `>` - the forms live
2.12.1 actually gates. A bare `$` is excluded because
`bun $KIRO_PROJECT_DIR/.kiro/tools/<t>.ts` ran unprompted under a config
that allowlisted it, so expansion alone does not gate.
Rationale wording: the comment, doc note, and CHANGELOG said absolute
paths stay gated because a regex "cannot prove those forms still target
this project across supported Kiro releases". The real reason is that a
pattern checks a path's shape, not its trustworthiness - a grant for any
/.../.kiro/tools/*.ts also pre-approves a script planted in a
world-writable directory, which is the verified finding. Also rewrites
the stale 2.5.16 summary paragraph, which still described the superseded
wider-allowlist approach.
|
Thanks, Jeff. The previous re-review confirmed that you addressed all of the substantive findings from that pass. The one requested change still open is the terminology sweep from @leandrodamascena, could you take the second review pass on this PR? There is one interaction I would particularly like independently verified before final approval: a backward jump invalidates the existing per-unit Code Generation review receipts, while preserved artifacts make the replay route directly to the all-covered settle gate. Does the current replay protocol reliably produce fresh review receipts for every applicable unit before approval? This is a verification question, not a new redesign request for Jeff. If the existing protocol already covers it, the terminology rename remains the only contributor change. If it exposes a real gap, we should identify the narrowest fix and handle the current- |
Addresses the one outstanding review item on awslabs#616 (apackeer's round-1 inline comment on stage-protocol.md:227). "price" reads as a monetary value while the loop-back defines it as a combined estimate of effort, cost, and risk. Rename to "estimated impact" and expose the dimensions separately in the halt-and-ask prompt: Candidate fix: [fix] — estimated impact — effort: [effort]; financial cost: [cost]; risk: [risk]. Consistently changed across every surface the wording reached: - core/aidlc-common/protocols/stage-protocol.md (priced/no-fix halt-and-ask variants, ledger Estimated-impact field, autonomous procedure, give-up-violation sentence) - core/aidlc-common/stages/construction/build-and-test.md (rung 2 "Classify and estimate impact", rungs 3/4, single-stage carve-out, Loop-Back Log field) - docs/reference/03-orchestrator.md, 04-stage-protocol.md, 04-stages/construction.md - CHANGELOG.md 2.5.16 entry - tests/integration/t250-build-test-loopback-prose.test.ts (16 pinned assertions updated to the new wording) - dist/<harness>/ regenerated for all five harnesses Prose-only refinement of the already-listed 2.5.16 entry; no version bump. Unrelated aws-pricing / pricing-model / price-performance text left untouched. Verification: bun run check (package --check + typecheck + biome) clean; bun tests/gen-coverage-registry.ts --check fresh; t250 36/36; t68 7/7; smoke + unit tiers 178 files / 4396 assertions / 0 failures.
|
Addressed the one outstanding item — the The halt-and-ask prompt now exposes the three dimensions separately, in the form you specified:
and the "Retry with fix" option description carries the same expanded form. The
Unrelated Verification:
No functional change; only the terminology. Happy to fold this into the maintainer-led |
leandrodamascena
left a comment
There was a problem hiding this comment.
Re-review at 9d532d8. The requested “price” to “estimated impact” terminology change is complete and consistent.
[P1] Recreate every per-unit review receipt before the replayed settle gate
A backward jump emits STAGE_JUMPED, invalidating all prior Code Generation review receipts. Because artifacts remain covered, replay routes directly to a settle directive naming only the final Unit. The loop-back override applies the fix and then presents or auto-approves the gate without requiring fresh §12a reviews for every applicable Unit. The engine consequently refuses completion. Require fresh reviews for every applicable Unit after all fixes/reuse decisions and before the settle gate, with a behavioral receipt test.
Relevant locations: core/aidlc-common/protocols/stage-protocol.md:189-196, :260-267, and :1282-1295.
[P2] The swarm check-first path cannot finalize already-green Units without fresh reviews
prepare creates a new BOLT_STARTED boundary, and finalize requires a terminal REVIEW_COMPLETED after that boundary. The proposed cheap path claims already-green Units without a worker turn but never instructs a fresh reviewer dispatch, so finalize rejects those claims. Require a reviewer pass in each claimed Unit’s worktree after check; this can remain “without a builder turn,” but not without review.
Relevant locations: core/aidlc-common/protocols/stage-protocol.md:201-219 and core/tools/aidlc-swarm.ts:273-330.
Verification:
t250-build-test-loopback-prose: 36/36 passedt205-gate-revision-backstop: 14/14 passedbun scripts/package.ts --check: passedgit diff --check: passed
The branch conflicts with current v2; these fixes should be included in the maintainer-led integration rather than requiring another contributor rebase.
Closes #611.
What
Gives Build & Test a sanctioned, bounded path back to Code Generation when the root cause of a failure lies in the generated code or an approach chosen there — replacing today's dead end ("2 attempts, then log and present the failed gate").
The 4-rung failure-escalation ladder (
build-and-test.mdStep 10):Construction Autonomy Mode: autonomous, with a priced fix and fewer than 3 entries in the ledger: record the diagnosis + plan, jump back to code-generation via the engine, apply the fix to the unit(s) the diagnosis names, replay forward. The failed run's gate is NOT presented; its learnings ritual defers to the passing run.The counter is a crash-safe artifact ledger: an append-only
## Loop-Back Login test-results.md — the entry count IS the bound (max 3 per intent). It survives the backward jump (jumps reset checkboxes, never artifacts), is colocated with the diagnosis, and is readable at the final gate;STAGE_JUMPEDaudit rows remain the deterministic cross-check. Human-directed jumps don't count.Design decisions (vs. the field predecessor)
aidlc-orchestrate.ts next --stage code-generationand executes the exactaidlc-jump.ts executecommand the engine prints — never a hand-composed jump call.Construction Autonomy Mode: autonomousgrant; the replayed code-generation gate is auto-approved with an explicit--user-input "Autonomous loop-back N per stage-protocol §1"marker — a repair of the approved shape, not a new autonomy inference (checklist item 6 intact).invoke-swarm, runcheckon every unit first and claim already-green units atfinalizewithout a worker turn; dispatch workers only for units the planned fix targets or that fail the check.reuse-artifact.--singleruns stop at rung 2 (no main-workflow position to move); priced options are logged and presented at that run's gate.Changes
core/aidlc-common/stages/construction/build-and-test.md— Step 10 ladder +## Loop-Back Logartifact shape.core/aidlc-common/protocols/stage-protocol.md— new §1 subsection "Build-and-Test failure loop-back (3.6 → 3.5)" (purely additive sibling of the pinned Halt-and-ask block; t34/t76 green), carve-out sentence on the NO EMERGENT BEHAVIOR RULE, EXCEPTION sentence on checklist item 5, Artifact Re-use auto-decision rule.core/aidlc-common/protocols/stage-protocol-recovery.md— crash-resume bullet (logged fix without a matchingSTAGE_JUMPED⇒ re-execute the jump, don't re-diagnose; resume count = ledger rows).harness/{claude,kiro,kiro-ide,codex,opencode}/skills/aidlc/SKILL.md— exception on the STAGE RITUAL IS ATOMIC principle (codex had no such bullet; it gains the full bullet with the exception).tests/integration/t245-build-test-loopback-prose.test.ts— 24 tests / 73 assertions pinning the ladder, §1 subsection, ledger paragraph, engine routing, swarm path, halt-and-ask template, recovery bullet, and the SKILL exception across authored + dist copies of all five harnesses.docs/reference/04-stages/construction.md,04-stage-protocol.md,03-orchestrator.md.Testing
bun scripts/package.ts --checkand the coverage-registry check both clean.Notes for review
STAGE_JUMPEDevent, checkbox resets, and Artifact Re-use replay all exist today; this PR is protocol prose + stage definition + tests.