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.json and 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_LESSON is 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_examples map. The task's loop_count increments by one.
- If
loop_count reaches the task's loop_cap, the task is escalated (status escalated) 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 /ship gate.
criterion_id: the contract criterion that guarded against the gap (the one that passed Verify and whose statement becomes the lesson's remediation).
source_intent: the original /start intent string.
patterns: the pattern tags extracted during contract drafting.
ledger-write.retroactive enforces structural non-null:
confirmed_gap_note must be a non-empty string (rejects null-lesson smuggling).
criterion_id MUST exist in contract.criteria. If the user cannot name one, the retroactive path refuses (E_INVALID_LESSON, rule: unknown_criterion_id) and /ship proceeds without a lesson.
source_intent must be non-empty.
ledger-write.retroactive runs a Jaccard similarity check against existing lessons. If any existing lesson's contract_gap is >= 0.7 similar to the new one, the new lesson writes supersedes: [<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,
/ship continues to the PR open. The lesson is visible in the next anvil ledger query run.
- If the user replies
skip at the /ship gate, NO retroactive lesson is written. /ship proceeds 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
remediation is fine as a placeholder." cli/lib/ledger-write.js refuses 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, or remediation field is null or empty; this is a null lesson and is refused by ledger-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's remediation has 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_examples map was updated with the new lesson's id and remediation text.
- The task's
loop_count incremented by exactly one.
- If the task reached
loop_cap, the task's status became escalated and no append occurred.
1---2name: resetting3description: 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.4---56## Overview78This 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.910## When to Use1112Invoked 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.1314## Process1516Two 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`.1718### Reactive (Verify or Court fail)19201. Read the Verify result at `<worktreePath>/anvil/verify/verify-result.json` and the per-criterion failures.212. Read the contract to identify which criterion's gap the reset is closing.223. 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.234. Call `ledger-write.append(lesson)`. If any required field is null or empty, `E_NULL_LESSON` is thrown; the reset path catches this and escalates the task instead of appending a null lesson.245. On successful append, re-queue the task with the fresh counter-example injected into the contract's `counter_examples` map. The task's `loop_count` increments by one.256. If `loop_count` reaches the task's `loop_cap`, the task is escalated (status `escalated`) rather than re-queued. The escalation surface presents the options to the user.2627### Retroactive (post-ship bug-fix, fix passed cleanly)2829The `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:30311. Call `ledger-write.retroactive({ contract, confirmed_gap_note, criterion_id, source_intent, patterns })` where:32 - `confirmed_gap_note`: the user-confirmed (or user-edited) gap note from the `/ship` gate.33 - `criterion_id`: the contract criterion that guarded against the gap (the one that passed Verify and whose statement becomes the lesson's `remediation`).34 - `source_intent`: the original `/start` intent string.35 - `patterns`: the pattern tags extracted during contract drafting.362. `ledger-write.retroactive` enforces structural non-null:37 - `confirmed_gap_note` must be a non-empty string (rejects null-lesson smuggling).38 - `criterion_id` MUST exist in `contract.criteria`. If the user cannot name one, the retroactive path refuses (`E_INVALID_LESSON, rule: unknown_criterion_id`) and `/ship` proceeds without a lesson.39 - `source_intent` must be non-empty.403. `ledger-write.retroactive` runs a Jaccard similarity check against existing lessons. If any existing lesson's `contract_gap` is >= 0.7 similar to the new one, the new lesson writes `supersedes: [<oldId>]` (up to three) instead of appending a near-duplicate. This prevents Ledger flood.414. Structural tags are added automatically: `[shipped_gap, post_hoc]` plus normalized pattern tags.425. On successful append, `/ship` continues to the PR open. The lesson is visible in the next `anvil ledger query` run.436. If the user replies `skip` at the `/ship` gate, NO retroactive lesson is written. `/ship` proceeds normally.4445## Rationalizations4647Reject the following shortcuts:4849- "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).50- "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).51- "Appending a lesson with empty `remediation` is fine as a placeholder." `cli/lib/ledger-write.js` refuses the append; placeholders are denied at the write path (structural guard; `E_NULL_LESSON`).5253## Red Flags5455If any of these conditions obtain, the reset is refused:5657- The lesson's `contract_gap`, `evidence`, or `remediation` field is null or empty; this is a null lesson and is refused by `ledger-write.append` (failure-taxonomy row 20: Null-lesson escape hatch).58- The task has reached `loop_cap`; no further reset is attempted; the task is escalated.59- The proposed lesson duplicates an existing lesson's id without superseding it (`E_INVALID_SUPERSESSION`).60- A retroactive lesson is proposed without a named `criterion_id`. Without a structural criterion reference, the lesson's `remediation` has no passing-evidence bar and the write is refused.6162## Verification6364Each reset checks:65661. `ledger-write.append(lesson)` returned `{ appended: true }` with a valid lesson id.672. The contract's `counter_examples` map was updated with the new lesson's id and `remediation` text.683. The task's `loop_count` incremented by exactly one.694. If the task reached `loop_cap`, the task's status became `escalated` and no append occurred.