resetting
On verify or judge fail, append a non-null lesson to the Ledger and re-queue the task. Null lessons are refused; the task escalates instead.
Overview
This skill closes the failure loop. When Verify or the Court reports fail, the skill composes a lesson from the captured Verify evidence and appends it to the global Ledger at ~/.anvil/ledger.jsonl. The task is then re-queued with the injected counter-example in the contract's counter_examples map. A reset that cannot produce a non-null lesson escalates the task rather than appending a null lesson.
When to Use
Invoked by the orchestrator when verifying.allGreen === false or when the Court returns request-changes with a non-empty gap. Not invoked by user prompts directly. Runs at most loop_cap times per task before the task is escalated.
Process
Two entry points: reactive (fires when Verify or Court fails during a run) and retroactive (fires at /ship for post-ship bug-fix intents that passed cleanly). Both route through cli/lib/ledger-write.js - it remains the single writer to ~/.anvil/ledger.jsonl.
Reactive (Verify or Court fail)
- Read the Verify result at
<worktreePath>/anvil/verify/verify-result.jsonand the per-criterion failures. - Read the contract to identify which criterion's gap the reset is closing.
- Compose a lesson with the required non-null fields:
contract_gap(the criterion the contract failed to constrain),evidence(the Verify probe output that demonstrated the gap),remediation(the one-sentence counter-example the next contract should inject). All three must be non-null and non-empty. - Call
ledger-write.append(lesson). If any required field is null or empty,E_NULL_LESSONis thrown; the reset path catches this and escalates the task instead of appending a null lesson. - On successful append, re-queue the task with the fresh counter-example injected into the contract's
counter_examplesmap. The task'sloop_countincrements by one. - If
loop_countreaches the task'sloop_cap, the task is escalated (statusescalated) rather than re-queued. The escalation surface presents the options to the user.
Retroactive (post-ship bug-fix, fix passed cleanly)
The contract-drafter agent may have populated contract.shipped_gap_note_draft because source_intent referenced an existing file. At /ship, after the whole-branch Court returns green, the orchestrator presents the draft note to the user for binary-ish confirmation. If the user confirms (or edits), this retroactive entry point fires:
- Call
ledger-write.retroactive({ contract, confirmed_gap_note, criterion_id, source_intent, patterns })where:confirmed_gap_note: the user-confirmed (or user-edited) gap note from the/shipgate.criterion_id: the contract criterion that guarded against the gap (the one that passed Verify and whose statement becomes the lesson'sremediation).source_intent: the original/startintent string.patterns: the pattern tags extracted during contract drafting.
ledger-write.retroactiveenforces structural non-null:confirmed_gap_notemust be a non-empty string (rejects null-lesson smuggling).criterion_idMUST exist incontract.criteria. If the user cannot name one, the retroactive path refuses (E_INVALID_LESSON, rule: unknown_criterion_id) and/shipproceeds without a lesson.source_intentmust be non-empty.
ledger-write.retroactiveruns a Jaccard similarity check against existing lessons. If any existing lesson'scontract_gapis >= 0.7 similar to the new one, the new lesson writessupersedes: [<oldId>](up to three) instead of appending a near-duplicate. This prevents Ledger flood.- Structural tags are added automatically:
[shipped_gap, post_hoc]plus normalized pattern tags. - On successful append,
/shipcontinues to the PR open. The lesson is visible in the nextanvil ledger queryrun. - If the user replies
skipat the/shipgate, NO retroactive lesson is written./shipproceeds normally.
Rationalizations
Reject the following shortcuts:
- "The gap is obvious; I'll write a short remediation and move on." A short remediation that doesn't name the observable counter-example is a null lesson; the Ledger rejects it. Null lessons poison future contracts (failure-taxonomy row 20: Null-lesson escape hatch).
- "One more reset will fix it; push past the loop cap." The loop cap is binding; past it the task escalates. Repeated resets without a new lesson signal a contract defect, not an implementation defect (failure-taxonomy row 20).
- "Appending a lesson with empty
remediationis fine as a placeholder."cli/lib/ledger-write.jsrefuses the append; placeholders are denied at the write path (structural guard;E_NULL_LESSON).
Red Flags
If any of these conditions obtain, the reset is refused:
- The lesson's
contract_gap,evidence, orremediationfield is null or empty; this is a null lesson and is refused byledger-write.append(failure-taxonomy row 20: Null-lesson escape hatch). - The task has reached
loop_cap; no further reset is attempted; the task is escalated. - The proposed lesson duplicates an existing lesson's id without superseding it (
E_INVALID_SUPERSESSION). - A retroactive lesson is proposed without a named
criterion_id. Without a structural criterion reference, the lesson'sremediationhas no passing-evidence bar and the write is refused.
Verification
Each reset checks:
ledger-write.append(lesson)returned{ appended: true }with a valid lesson id.- The contract's
counter_examplesmap was updated with the new lesson's id andremediationtext. - The task's
loop_countincremented by exactly one. - If the task reached
loop_cap, the task's status becameescalatedand no append occurred.