# 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.

- Skill: `forsonny/resetting` (Agent Skill)
- Install (CLI): `npx skillmds@latest add forsonny/resetting`
- Raw SKILL.md: https://api.skillmd.com/api/skills/forsonny/resetting/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: forsonny (https://skillmd.com/u/forsonny)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/forsonny/resetting

---


## 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)

1. Read the Verify result at `<worktreePath>/anvil/verify/verify-result.json` and the per-criterion failures.
2. Read the contract to identify which criterion's gap the reset is closing.
3. 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.
4. 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.
5. 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.
6. 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:

1. 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.
2. `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.
3. `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.
4. Structural tags are added automatically: `[shipped_gap, post_hoc]` plus normalized pattern tags.
5. On successful append, `/ship` continues to the PR open. The lesson is visible in the next `anvil ledger query` run.
6. 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:

1. `ledger-write.append(lesson)` returned `{ appended: true }` with a valid lesson id.
2. The contract's `counter_examples` map was updated with the new lesson's id and `remediation` text.
3. The task's `loop_count` incremented by exactly one.
4. If the task reached `loop_cap`, the task's status became `escalated` and no append occurred.

