From 6d780e3595eb02826381d933b61b66424cf83578 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:18:02 +0200 Subject: [PATCH 001/126] docs: background-verdict-dispatch spec, plan, and glossary terms --- docs/domain/glossary.md | 16 + .../2026-08-17-background-verdict-dispatch.md | 688 ++++++++++++++++++ ...8-17-background-verdict-dispatch-design.md | 247 +++++++ 3 files changed, 951 insertions(+) create mode 100644 docs/plans/2026-08-17-background-verdict-dispatch.md create mode 100644 docs/specs/2026-08-17-background-verdict-dispatch-design.md diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 8dace8d..21905dc 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -253,6 +253,22 @@ the repo's own rules means something else, a document location where a statement lives. _Avoid_: mode, channel, entrypoint +**Verdict agent**: +An agent whose report ends in a verdict the dispatcher stamps into the +reviewed document's frontmatter — `architect` and `plan-adversary`. +Orthogonal to Persona: the architect is a persona surface, the +plan-adversary a plain reviewer. Consult agents are not verdict agents — +a consultation returns a Contribution and stamps nothing. +_Avoid_: review agent (unqualified), reviewer agent + +**Relay**: +The delivery of a background agent's result to the developer before any +further action on it — a verdict agent's report before its stamp (the +verdict, the model self-report, and every finding in substance), a +consultation's Contribution attributed and substantially verbatim. The +developer's standing veto point. +_Avoid_: report back, forward (as the term) + **Session skill**: A skill whose content is an open-ended conversation, named `*-session` — `architect-session`, `grilling-session`, `memory-review-session` among diff --git a/docs/plans/2026-08-17-background-verdict-dispatch.md b/docs/plans/2026-08-17-background-verdict-dispatch.md new file mode 100644 index 0000000..13ac89e --- /dev/null +++ b/docs/plans/2026-08-17-background-verdict-dispatch.md @@ -0,0 +1,688 @@ +--- +ticket: none +date: 2026-08-17 +status: approved +adversary: concerns (resolved 2026-08-17) +branch: feature/background-verdict-dispatch +base: develop +--- + +# Background Verdict Dispatch Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Verdict agents (`architect`, `plan-adversary`) dispatch in the background with notification→relay→stamp mechanics, per `docs/specs/2026-08-17-background-verdict-dispatch-design.md`. + +**Architecture:** One canonical dispatcher sequence lands as an end-of-file subsection of the always-on workflow rule; both agent files gain `background: true` (exactly the spec's enumeration), a pointer phrase in the description, and a self-describing report subject; the lifecycle rule's closing sentence gains the relay-then-stamp ordering with an edited-together marker; the README's agent bullets and model-selection section follow. Content lands first, the dogfood version bump last, so the cache never serves pre-edit content under the first-pass string — any later content fix re-mints the discriminator (Task 8). No code — every deliverable is rule text, agent frontmatter, or README prose. + +**Tech Stack:** Claude Code plugin content (Markdown rules, agent frontmatter), `claude plugin validate`, git. + +## Global Constraints + +- Public repo: English only, no machine paths, no company names (repo-hygiene rule). +- Commits: one line, conventional prefix `type(scope):`, no body, no trailers (no `Co-Authored-By`). +- Frontmatter safety: any YAML scalar containing `: ` stays double-quoted; `claude plugin validate` does NOT check `rules/` files — review their frontmatter by hand. +- Rule text mentions skills/agents conditionally ("when available") — rules load for people without the plugin. +- Never force-add ignored files; tracked `docs/` documents ride the closing commit (Task 9), not per-task commits. +- `claude plugin validate .` and `claude plugin validate plugins/working-process` must pass before every commit. +- The spec is the contract: wording below is copied from it; on a conflict the spec wins. The spec's change enumeration binds shipped BEHAVIOR; user-facing docs (the README, Task 6) follow the repo convention that they match shipped behavior, extending the enumeration without amending it. +- Prescribed tiers for this plan's own review rounds: the architect on the most capable available family; the plan-adversary one family below it (a small mechanical plan) — rounds 1–3 ran exactly there (opus, below fable), so no fallback record applies. A dispatch below these tiers lands the `*-fallback: (chosen )` record in the same stamp edit, resolved or waived before Task 9's flip. +- Rollout pairing: the plugin version delivers agent frontmatter immediately; the dispatcher sequence reaches a project only through a rules re-sync. The reverse window degrades sanely — the previously installed rules still carry the old "record the verdict" obligation, so no round is lost — and Task 6 states the pairing where users see it. + +--- + +### Task 1: Topic branch and frontmatter branch fields + +**Files:** +- Modify: `docs/specs/2026-08-17-background-verdict-dispatch-design.md` (frontmatter: `branch`, `base`) +- Modify: `docs/plans/2026-08-17-background-verdict-dispatch.md` (frontmatter: `branch`, `base`) + +**Interfaces:** +- Consumes: `develop` at its current head. +- Produces: branch `feature/background-verdict-dispatch` (base `develop`) that every later task commits to. No commit in this task — `docs/` changes ride Task 9's closing commit. + +- [ ] **Step 1: Create the topic branch off develop** + +```bash +git checkout develop +git checkout -b feature/background-verdict-dispatch +``` + +- [ ] **Step 2: Record branch and base in the spec and plan frontmatter** + +Append to BOTH documents' YAML frontmatter as the LAST fields — the documented field order puts `branch`/`base` after the review fields (spec-plan-lifecycle rule): + +```yaml +branch: feature/background-verdict-dispatch +base: develop +``` + +- [ ] **Step 3: Verify placement** + +Run: `rg -n "^(branch|base):" docs/specs/2026-08-17-background-verdict-dispatch-design.md docs/plans/2026-08-17-background-verdict-dispatch.md` +Expected: two matches per file, with line numbers inside each YAML frontmatter block — the block's final fields, directly above the closing `---`. + +- [ ] **Step 4: Cross the implementation-ready gate** + +Gate: this plan's standing `adversary:` verdict must first be `LGTM` +or carry the `(resolved )` annotation with its body note — a +document is never approved-and-blocking. Then, with the developer's +explicit go-ahead (never silently), flip BOTH documents' frontmatter +to `status: approved` — the lifecycle's implementation-ready gate: the +plan is approved and implementation is about to start. This is also +where the process suggests committing the `docs/` documents; +committing stays with the developer, and the documents otherwise ride +Task 9's closing commit. + +--- + +### Task 2: Dispatcher-sequence subsection in the workflow rule + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` + +**Interfaces:** +- Consumes: the rule's current structure — numbered steps 1–6, a standalone paragraph "After every round of the `architect` agent or plan-adversary, record the verdict…", then model-selection, consultation-dispatch, glossary, and elements-of-style paragraphs. +- Produces: a `## Dispatching a verdict agent` subsection at the END of the file (so the unrelated trailing paragraphs stay outside it); the standalone verdict-recording paragraph REMOVED (folded — no third restatement); steps 3 and 5 referencing the subsection. + +- [ ] **Step 1: Delete the standalone verdict-recording paragraph** + +Delete this paragraph (currently after step 6), including its trailing blank line: + +```markdown +After every round of the `architect` agent or plan-adversary, record the +verdict (`LGTM` | `concerns` | `blocking`) in the reviewed document's +`architect:` / `adversary:` frontmatter field. A consultation +(`*-consult`) produces no verdict and nothing to record. +``` + +- [ ] **Step 2: Append the subsection at the end of the file** + +After the elements-of-style paragraph (the file's current last paragraph), append: + +```markdown +## Dispatching a verdict agent + +Dispatching a verdict agent (`architect`, `plan-adversary`), when +available: + +- From an interactive session the dispatch always runs in the + background — a review never blocks the session, mirroring the + review-reports rule's precedent. A run with no interactive + dispatcher cannot relay, so it never stamps; the next interactive + touch closes the round through the lifecycle rule's re-offer loop. +- Before dispatch, resolve any undecided Process directory + (`docs/specs/`, `docs/plans/`) so the first-create question cannot + interrupt the stamp turn. +- At dispatch, tell the developer the round is running in the + background and its result will arrive as a task notification, with + progress visible in the session's task list. (This bullet is part of + the spec's sequence — added there 2026-08-17, routed from this + plan's adversary round 4.) +- On the completion notification, in one turn and in this order: + verify the agent's model self-report (the comparison the lifecycle + rule defines), relay the report to the developer, then stamp the + verdict (`LGTM` | `concerns` | `blocking`) into the reviewed + document's `architect:` / `adversary:` frontmatter field. +- The relay carries the verdict, the model self-report, and every + finding in substance — condense narrative prose, never drop a + finding or its severity. +- The stamp — the field, any fallback record, and the round record + the lifecycle rule defines — lands as one edit, body record first + where edit granularity forces separate writes, and goes to the + document named in the report, never to "the most recent dispatch". +- The sequence ends the delivery, not the loop: after relay and stamp + the session may fix the document and dispatch a fresh round, or put + its questions to the developer first. +- At most one live round per document per field within the session; + superseding a running round stops it when the platform offers a + stop, otherwise the stale result is relayed as stale and never + stamped. +- When the reviewed document changed after dispatch — known only + conversationally; an out-of-session edit is accepted as + undetectable — the relay says so and the stamp waits for the + developer's call. +- When compaction leaves an in-flight dispatch unclear, check the task + list rather than guess, and never fabricate a pending result. +- An agent that dies or returns nothing is an ordinary error: relay + the failure and offer a fresh dispatch on the same tier. +- A consultation (`*-consult`) produces no verdict and nothing to + record. + +This subsection and the lifecycle rule's relay-then-stamp sentence +state the same ordering and are edited together. +``` + +- [ ] **Step 3: Reference the subsection from steps 3 and 5** + +In step 3, replace: + +```markdown + working-process `architect` agent (when available); stamp its verdict + into the spec's `architect:` frontmatter field. + Dispatch it on the most capable available model, named explicitly. +``` + +with: + +```markdown + working-process `architect` agent (when available); dispatch and + stamping follow the verdict-agent dispatch subsection below. + Dispatch it on the most capable available model, named explicitly. +``` + +In step 5, replace: + +```markdown + offer a working-process plan-adversary agent dispatch (when + available); stamp its verdict into the plan's `adversary:` field. +``` + +with: + +```markdown + offer a working-process plan-adversary agent dispatch (when + available); dispatch and stamping follow the verdict-agent dispatch + subsection below. +``` + +- [ ] **Step 4: Verify structure and no third restatement** + +Run: `rg -n "^## " plugins/working-process/rules/workflow.md` +Expected: exactly one match — `## Dispatching a verdict agent` (the file has no other `##` heading). +Run: `tail -2 plugins/working-process/rules/workflow.md` +Expected: the edited-together closing sentence — proving the subsection ends the file. +Run: `rg -c "After every round of" plugins/working-process/rules/workflow.md` +Expected: no match (the phrase sits on one line in the deleted paragraph; "record the verdict" itself is line-wrapped in the source and would never match). +Run: `rg -c "stamp the" plugins/working-process/rules/workflow.md` +Expected: `1` (the subsection's ordering bullet). + +- [ ] **Step 5: Validate and commit** + +Run: `claude plugin validate . && claude plugin validate plugins/working-process` +Expected: both PASS. + +```bash +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): verdict-agent dispatch sequence in workflow rule" +``` + +--- + +### Task 3: Architect agent — full background pattern and self-describing report + +**Files:** +- Modify: `plugins/working-process/agents/architect.md` + +**Interfaces:** +- Consumes: nothing from other tasks. +- Produces: `background: true` — exactly the spec's enumeration, nothing beyond it (`disallowedTools` was considered and dropped: ADR 0001 scopes it to consult agents, and it cannot prevent a dispatcher-side resumption anyway); the description's pointer phrase (exact wording below, shared verbatim with Task 4); a report whose opening is claimed by exactly one labeled line — `**Subject**:` with the document path, then the model self-report. + +- [ ] **Step 1: Add the frontmatter keys and description phrase** + +Append to the end of the quoted `description` string (inside the closing quote, after "Dispatch on the most capable available model."): + +``` + Runs in the background; the verdict arrives as a task notification, and the dispatcher stamps after relay, not before. +``` + +Below the `description:` line add: + +```yaml +background: true +``` + +- [ ] **Step 2: Reword the Assumed-domains opener claim** + +In the "Domains — hybrid inference" section, replace: + +```markdown +- Questions mid-run are impossible, so declare instead: every report + opens with an **Assumed domains** section — each domain, where it came + from (hint / inferred), and your confidence, stated in plain words when + low. A wrong inference must be visible at the top of the report and + cheap to fix by a re-dispatch with a corrected hint. +``` + +with: + +```markdown +- Questions mid-run are impossible, so declare instead: the report + carries an **Assumed domains** section as its first numbered + section — each domain, where it came from (hint / inferred), and your + confidence, stated in plain words when low. A wrong inference must be + visible near the top of the report and cheap to fix by a re-dispatch + with a corrected hint. +``` + +- [ ] **Step 3: Reconcile the report opener** + +In the "Report" section, replace: + +```markdown +The report opens with a one-line **model self-report** — the model this +review actually ran on, as family plus version (e.g. "opus 4.8") — +before any section; the dispatcher compares it against the dispatched +and prescribed tiers before stamping. +``` + +with: + +```markdown +The report opens with a labeled **Subject** line — the path of the +reviewed document (a bare question has no path — say so instead) — +then a one-line **model self-report** — the model this review actually +ran on, as family plus version (e.g. "opus 4.8") — before any section. +The dispatcher routes the stamp by the Subject line and compares the +self-report against the dispatched and prescribed tiers before +stamping. +``` + +- [ ] **Step 4: Verify exactly one opener claim, validate, commit** + +Run: `rg -c "opens with" plugins/working-process/agents/architect.md` +Expected: `1`. +Check: the `description` value still opens and closes with one double quote and contains no unescaped `"`. +Run: `claude plugin validate plugins/working-process` +Expected: PASS. + +```bash +git add plugins/working-process/agents/architect.md +git commit -m "feat(working-process): architect runs in background with self-describing report" +``` + +--- + +### Task 4: Plan-adversary agent — full background pattern and subject key + +**Files:** +- Modify: `plugins/working-process/agents/plan-adversary.md` + +**Interfaces:** +- Consumes: the same description phrase as Task 3 (verbatim). +- Produces: `background: true` — exactly the spec's enumeration; JSON output with a `subject` key the dispatcher routes the stamp by. + +- [ ] **Step 1: Add the frontmatter keys and description phrase** + +Append to the end of the (unquoted) `description` value, after "never the cheapest family.": + +``` + Runs in the background; the verdict arrives as a task notification, and the dispatcher stamps after relay, not before. +``` + +The appended text contains no `: `, so the scalar stays safe unquoted. +Below the `description:` line add: + +```yaml +background: true +``` + +- [ ] **Step 2: Add the `subject` key to the Output block** + +Replace: + +``` + { + "model": "", +``` + +with: + +``` + { + "subject": "", + "model": "", +``` + +- [ ] **Step 3: Validate and commit** + +Run: `claude plugin validate plugins/working-process` +Expected: PASS. + +```bash +git add plugins/working-process/agents/plan-adversary.md +git commit -m "feat(working-process): plan-adversary runs in background with subject-keyed output" +``` + +--- + +### Task 5: Lifecycle rule — relay-then-stamp ordering + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` + +**Interfaces:** +- Consumes: Task 2's subsection (the edited-together counterpart). +- Produces: the ordering sentence in the lifecycle rule, marked edited-together. + +- [ ] **Step 1: Edit the closing sentence of the Lifecycle-offers paragraph** + +Replace: + +```markdown +After any +review round, stamp the verdict into the document's field. +``` + +with: + +```markdown +After any +review round, relay the report to the developer, then stamp the +verdict into the document's field — this sentence and the workflow +rule's verdict-agent dispatch subsection state the same ordering and +are edited together. +``` + +- [ ] **Step 2: Verify the pairing exists on both sides** + +Run: `rg -l "edited together" plugins/working-process/rules/` +Expected: both `workflow.md` and `spec-plan-lifecycle.md` listed. + +- [ ] **Step 3: Validate and commit** + +Run: `claude plugin validate . && claude plugin validate plugins/working-process` +Expected: both PASS. + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): relay-then-stamp ordering in lifecycle rule" +``` + +--- + +### Task 6: README — agent bullets, model-selection contrast, rollout pairing + +**Files:** +- Modify: `plugins/working-process/README.md` + +**Interfaces:** +- Consumes: Tasks 3–4 shipped frontmatter (the README must match it). +- Produces: user-facing text consistent with background verdict dispatch, plus the rollout-pairing note. + +- [ ] **Step 1: Update the architect bullet** + +Replace: + +```markdown + `architect:` frontmatter field by the dispatcher. Dispatched on the most capable available model. +``` + +with: + +```markdown + `architect:` frontmatter field by the dispatcher. Dispatched in the + background on the most capable available model; the verdict arrives + as a task notification and is stamped after the dispatcher relays + the report. +``` + +- [ ] **Step 2: Update the plan-adversary bullet** + +Replace: + +```markdown + come from `*-plan-review` checklist skills. Dispatched scaled to the + plan's size and risk. +``` + +with: + +```markdown + come from `*-plan-review` checklist skills. Dispatched in the + background, scaled to the plan's size and risk; the verdict arrives + as a task notification and is stamped after relay. +``` + +- [ ] **Step 3: Fix the model-selection contrast and add the rollout pairing** + +In the "Model selection" section, replace (full source lines, the last +one ending mid-sentence): + +```markdown +Consultations (the `*-consult` agents) dispatch on the most capable +available model as named background agents; they return no verdict, so +the fallback machinery below never applies to them. The model is always named explicitly at dispatch, and +``` + +with (re-wrapped to the file's width, the trailing sentence start +preserved): + +```markdown +Consultations (the `*-consult` agents) dispatch on the most capable +available model; like the verdict agents, they run as named background +agents — consultations return no verdict, so the fallback machinery +below never applies to them. The verdict agents' relay-then-stamp +sequence lives in the workflow rule's Rules payload: after a plugin +update, run a rules re-sync so the dispatcher side of the behavior +matches the agents (until then the previously installed rules still +carry the older record-the-verdict obligation, so no round is lost). +The model is always named explicitly at dispatch, and +``` + +- [ ] **Step 4: Validate and commit** + +Run: `claude plugin validate . && claude plugin validate plugins/working-process` +Expected: both PASS. + +```bash +git add plugins/working-process/README.md +git commit -m "docs(working-process): background verdict dispatch in README" +``` + +--- + +### Task 7: Dogfood version bump — after all content + +**Files:** +- Modify: `plugins/working-process/.claude-plugin/plugin.json` (the `version` field) + +**Interfaces:** +- Consumes: Tasks 2–6 committed (the content the string must key). +- Produces: version `0.14.0-dev.background-verdict-dispatch` minted AFTER every content edit, so the cache can never serve pre-edit content under this string. + +- [ ] **Step 1: Set the dogfood version** + +In `plugins/working-process/.claude-plugin/plugin.json` change: + +```json + "version": "0.13.0", +``` + +to: + +```json + "version": "0.14.0-dev.background-verdict-dispatch", +``` + +- [ ] **Step 2: Validate and commit the bump alone** + +Run: `claude plugin validate . && claude plugin validate plugins/working-process` +Expected: both PASS. + +```bash +git add plugins/working-process/.claude-plugin/plugin.json +git commit -m "chore(working-process): dogfood version for background-verdict-dispatch" +``` + +--- + +### Task 8: Dogfood verification — developer-driven, both agents, fresh session + +**Files:** +- No file changes; verification only. + +**Interfaces:** +- Consumes: everything above, live under the dogfood version. +- Produces: the spec's verification stage two (shipped artifacts), for BOTH verdict agents. + +- [ ] **Step 1: Make the shipped content live — STOP, developer-driven** + +STOP and hand this step to the developer on their explicit go-ahead — a marketplace change, a plugin update, and a sync-rules run mutate the developer's installed state and are never run unbid (the review-reports, memory-hybrid, and memory-entry-format plans' precedent). The installed `missing-bits` marketplace is a GitHub clone pinned to released `master`, so it can never serve the dogfood version. With the developer driving: add (or update) a marketplace sourced from this checkout — `/plugin marketplace add ` — install or update `working-process` from THAT marketplace, then run the `working-process:sync-rules` skill so the installed Rules payload picks up the new subsection and lifecycle sentence. The executor resumes at Step 2. + +- [ ] **Step 2: Confirm the served version AND the installed content** + +Run: `claude plugin list 2>/dev/null | grep -A1 working-process` +Expected: `0.14.0-dev.background-verdict-dispatch` (the string only — content follows). +Run: `rg -c "Dispatching a verdict agent" "$HOME/.claude/rules/working-process/workflow.md"` and `rg -c "edited together" "$HOME/.claude/rules/working-process/spec-plan-lifecycle.md"` — checking the project-level copy instead when that is the installed one. +Expected: `1` each. On a miss STOP — the dispatching session would run against the stale rules (the review-contract-sharpening plan's dogfood-gate precedent). + +- [ ] **Step 3: Exercise an architect dispatch — a real round** + +In a fresh session started after Step 1 (a running session keeps pre-sync rules), dispatch the `architect` agent on `docs/specs/2026-08-17-background-verdict-dispatch-design.md` (a real grilled document — no bare-question substitute, which would demonstrate neither the Subject opener nor stamp routing), on the most capable available model, named explicitly at dispatch. This is a live round: its verdict is stamped and its round record appended to the spec body like any other. Confirm the observables that prove the updated files loaded: the report opens with the labeled Subject line then the model self-report, the verdict arrives as a task notification, and the session relays before stamping. The immediate return is context, not evidence — background is the Agent tool's default, so a stale cache would also return immediately. +Expected: all three observed; any miss is a defect to fix before the release PR. + +- [ ] **Step 4: Exercise a plan-adversary dispatch — a real round** + +In the same fresh session, dispatch `plan-adversary` on `docs/plans/2026-08-17-background-verdict-dispatch.md` (this plan), one family below the most capable available model (a small mechanical plan), named explicitly at dispatch. This too is a live round: stamped and recorded in the plan body. Confirm: the dispatch returns immediately, the JSON output carries the `subject` key with the plan's path, and the session relays before stamping. +Expected: all three observed. + +- [ ] **Step 5: Re-mint on any post-mint content fix** + +Any content edit made after Task 7 minted the version string bumps the discriminator (`0.14.0-dev.background-verdict-dispatch-2`, `-3`, …) in its fix commit, then repeats Steps 1–2 before re-running Steps 3–4 — the cache keys content by version string, so a fix under an unchanged string re-dogfoods stale content (the design-personas topic needed three such re-mints). + +- [ ] **Step 6: Final validation sweep** + +Run: `claude plugin validate . && claude plugin validate plugins/working-process && rg -c "edited together" plugins/working-process/rules/workflow.md plugins/working-process/rules/spec-plan-lifecycle.md` +Expected: validations PASS; each rule file reports exactly `1`. + +--- + +### Task 9: Closing — lifecycle flips and docs commit + +**Files:** +- Modify: `docs/specs/2026-08-17-background-verdict-dispatch-design.md` (frontmatter `status`) +- Modify: `docs/plans/2026-08-17-background-verdict-dispatch.md` (frontmatter `status`, checked boxes) + +**Interfaces:** +- Consumes: Task 8 passed; every round record present in both documents. +- Produces: the closed lifecycle the two preceding plans end with. + +- [ ] **Step 1: Reconcile round records and review fields** + +Check both documents' "Review rounds" sections list every architect/adversary round with verdict, model, and date — including Task 8's dogfood rounds. Reconcile the frontmatter fields: a verdict resolved without a fresh round carries the `(resolved )` annotation with its body note; a live fallback record is resolved (fresh prescribed-tier round) or waived. STOP: a non-LGTM dogfood verdict that is neither resolved nor annotated blocks Step 2. + +- [ ] **Step 2: Flip lifecycle status — with the developer's confirmation** + +With the developer's explicit go-ahead (never silently), move `status: approved` → `status: implemented` in the spec and the plan (Task 1 Step 4 crossed the `draft` → `approved` gate). + +- [ ] **Step 3: Commit the docs** + +The glossary rides this commit because the grilling session edited it (two terms: Verdict agent, Relay) outside the plan's tasks and it is still uncommitted. + +```bash +git add docs/specs/2026-08-17-background-verdict-dispatch-design.md docs/plans/2026-08-17-background-verdict-dispatch.md docs/domain/glossary.md +git commit -m "docs: background-verdict-dispatch spec, plan, and glossary terms" +``` + +- [ ] **Step 4: Offer the memory review** + +The memory-review-session skill is available and a document just moved to `implemented`: offer the Project memory review (released work-state notes close, resolved entries sweep to the archive). The developer may decline. + +## Review rounds + +### 2026-08-17 — plan-adversary, opus, blocking (round 1) + +Six Important, six Minor; all twelve addressed the same day in this +revision: subsection moved to end-of-file in bullet form (I1, M7); +the third "opens with" claim reconciled (I2); an adversary dogfood +dispatch added (I3); the version bump moved after the content commits +with an explicit plugin update and a fresh-session requirement (I4); +the rollout window analyzed — old installed rules keep the +record-the-verdict obligation, so no round is lost — and paired in the +README (I5); a closing task added mirroring the two preceding plans +(I6); `branch`/`base` appended last per the documented field order +(M8); the version-bump commit unbundled from docs (M9); +`disallowedTools: SendMessage` added to both agents, resumption of a +verdict round ruled out (M10); the bare-question alternative dropped +from the dogfood step (M11); the README's consumer lines enumerated +(M12). + +### 2026-08-17 — plan-adversary, opus, blocking (round 2) + +Five Important, five Minor; nine fixed the same day in this revision, +one rejected with counter-evidence: + +1. Installed-copy content checks added to the dogfood task, with the + marketplace refresh and a stop-on-miss (I1). +2. A discriminator re-mint step added for post-mint content fixes; the + Architecture cache claim scoped to the first pass (I2). +3. Dogfood dispatches declared real rounds — stamped, recorded — with + field reconciliation and a non-LGTM stop before the flip (I3). +4. `disallowedTools: SendMessage` dropped from both agents: it exceeds + the spec's change enumeration, ADR 0001 scopes its rationale to + consult agents, and the key cannot prevent resumption anyway (I4). +5. The `approved` gate restored: Task 1 flips both documents to + `approved` with the developer's go-ahead; Task 9 moves + `approved` → `implemented` (I5). +6. Dogfood dispatch models named explicitly (M6). +7. The subsection now cites the lifecycle rule for the self-report + comparison and the round record instead of restating them (M7). +8. The architect's routing line gains the `**Subject**:` label, + mirroring the JSON key (M8). +9. Task 2's structural verification restated to what rg/tail can + actually prove (M9). +10. Rejected — glossary staging in the closing commit: `git status` + shows `docs/domain/glossary.md` modified and uncommitted (the + grilling session's two terms), so the staging is correct; a note + now says why the glossary rides that commit (M10). + +### 2026-08-17 — plan-adversary, opus, blocking (round 3) + +One Critical, three Important, four Minor; six fixed the same day, two +rejected (one partially) with counter-evidence: + +1. Critical — the dogfood string was a prerelease of the released and + installed 0.13.0, sorting below it and reducing the release to a + no-op: re-minted as `0.14.0-dev.background-verdict-dispatch`, the + re-mint ladder rebased (C1). +2. The Task 1 placement check read the wrong end of the file — now an + anchored rg on the frontmatter (I2). +3. Task 8 retitled developer-driven, with a STOP handing the + marketplace refresh, plugin update, and sync-rules run to the + developer on explicit go-ahead (I3). +4. Partially rejected — the claim that rounds 1–3 ran "at the top + family": they ran on opus, one family below the most capable + (fable), which IS the prescribed tier for a small mechanical plan, + so no fallback record applies. The valid core — the plan never + declared its prescribed tier — fixed with a Global Constraints line + (I4). +5. Rejected — moving the subsection after the consultation paragraph + re-raises round 1's finding I1 in reverse: mid-file placement puts + the glossary and elements-of-style paragraphs under the new `##` + heading, exactly what round 1 blocked. End-of-file placement + stands; recorded as a reviewer flip-flop (M5). +6. A dispatch-time announcement bullet added to the subsection (M6). +7. Task 1's approved flip gated on the adversary verdict being LGTM or + annotated resolved (M7). +8. A Global Constraints line reconciles the two readings of "the spec + is the contract": the enumeration binds behavior; user-facing docs + follow shipped behavior by repo convention (M8). + +### 2026-08-17 — plan-adversary, opus, concerns (round 4) + +One Important, four Minor, all fixed the same day; the reviewer also +re-checked and upheld the round-2/3 rejections: + +1. The make-live path could not deliver topic-branch content — the + installed missing-bits marketplace is a GitHub clone pinned to + released master. Task 8 Step 1 now adds a checkout-sourced + marketplace and updates from it, per the earlier plans' precedent + (I1). +2. The paragraph-gone check was vacuous (the phrase is line-wrapped in + the source) — re-anchored on the one-line fragment "After every + round of" (M2). +3. The dispatch-time announcement bullet exceeded the spec's + enumeration — routed into the spec as a one-line sequence addition, + recorded there (M3). +4. "Returns immediately" proves nothing (background is the Agent + tool's default) — the discriminating observables are now named: the + Subject line and the subject key; immediacy demoted to context + (M4). +5. The README quote started and ended mid-line — re-quoted as full + lines with the replacement re-wrapped (M5). + +Resolution note, 2026-08-17: all five round-4 findings fixed in this +revision (the list above says how); the developer accepted the +resolution in place of a fifth round after the 12→10→8→5 convergence +across four rounds. diff --git a/docs/specs/2026-08-17-background-verdict-dispatch-design.md b/docs/specs/2026-08-17-background-verdict-dispatch-design.md new file mode 100644 index 0000000..7177dbd --- /dev/null +++ b/docs/specs/2026-08-17-background-verdict-dispatch-design.md @@ -0,0 +1,247 @@ +--- +ticket: none +date: 2026-08-17 +status: approved +grilled: 2026-08-17 +architect: concerns (resolved 2026-08-17) +branch: feature/background-verdict-dispatch +base: develop +--- + +# Background dispatch for verdict agents + +## Problem + +The `architect` and `plan-adversary` agents block the session that +dispatches them. A review round runs 9–31 minutes (measured across the +#10 dogfooding runs), and for that whole time the developer's +interactive session sits idle. The plugin already solved this twice: +standards-plugin review dispatches "run in the background: a review +never blocks an interactive dispatching session" (review-reports rule), +and both consult agents carry `background: true` with matching +description text. The verdict agents are the same shape — a long, +self-contained run ending in one small deliverable — yet they still run +in the foreground, and no rule says what the session must do when a +verdict arrives as a task notification instead of a tool result. + +## Design + +### Dispatcher sequence — canonical in the workflow rule + +A dispatcher-sequence subsection in the workflow rule's dispatch +guidance defines the sequence; steps 3 and 5 reference it instead of +restating it. The workflow rule loads in every session (the plugin's +deliberate always-on exception), so the subsection is context every +session pays for — accepted deliberately: a single definition site +outweighs the context weight. + +- A verdict-agent dispatch from an interactive session always runs in + the background. The developer controls *whether* a review runs (every + step stays an offer); an accepted dispatch runs in one mode. No + foreground escape: a developer who wants to wait simply waits for the + notification. +- A run with no interactive dispatcher cannot relay, so it never + stamps — mirroring the review-reports precedent's deferral. The next + interactive touch closes the round through the re-offer loop the + Recovery section supplies. +- A verdict agent writes nothing, so no directory question guards the + agent itself; what the pre-dispatch check guards is the stamp turn. + A pre-existing but undecided `docs/specs/` or `docs/plans/` would + interrupt relay-and-stamp with the first-create question, so an + undecided directory is resolved before dispatch. +- At dispatch, the session tells the developer the round is running in + the background and its result will arrive as a task notification, + with progress visible in the session's task list. +- On the completion notification, in one turn and in this order: verify + the agent's model self-report against the dispatched and prescribed + tiers (the lifecycle rule already requires the comparison), relay the + report to the developer, then stamp the verdict. The stamp — the + frontmatter field, any fallback record, and the body's round record — + lands as a single edit, so no document ever holds a partial stamp. + Where edit granularity forces separate writes, the body round record + lands first: a mid-stamp death then leaves a round that visibly never + closed, never a verdict whose findings were lost. +- The relay carries the verdict, the model self-report, and every + finding in substance — narrative prose may be condensed, but no + finding or its severity is ever dropped: the relay is the + developer's veto point, and an omitted finding is a decision made + for them. The full report stays in the agent's transcript. +- The stamp goes to the document named in the report, never to "the + most recent dispatch". +- The sequence ends the delivery, not the loop: after relay and stamp + the session may fix the document and dispatch a fresh round, or put + its questions to the developer first — exactly as in a foreground + round. The iterative review loop is intended behavior. +- At most one live round per document per field — a constraint the + dispatching session enforces within itself; a parallel round from + another session is accepted as undetectable, like the out-of-session + edit below, and stays benign: both rounds record in the body, and + the field holds the later stamp. Superseding a running round stops + its dispatch when the platform offers a stop; otherwise the stale + result is discarded on arrival — relayed as stale, never stamped. +- When the reviewed document changed after dispatch, the relay says so + and the stamp — in this one case — waits for the developer's call at + relay: stamp regardless, or discard and dispatch a fresh round. The + only deliberate exception to same-turn stamping, and still no + persistent state. Detection rests on the session's own conversational + knowledge of edits; an out-of-session edit is accepted as + undetectable, consistent with the no-marker recovery stance. +- When compaction leaves an in-flight dispatch unclear, the session + checks its task list rather than guessing, and never fabricates a + pending result. +- A background agent that dies or returns nothing is an ordinary error: + relay the failure and offer a fresh dispatch on the same tier. The + existing cap-refusal question (drop one family or wait) is untouched — + a cap refusal surfaces synchronously at dispatch, before any + background run starts (a platform assumption recorded under + Recovery). + +### Agent side — mirroring the consult pattern + +Both verdict agents gain `background: true` in their frontmatter and +one description phrase: "runs in the background; the verdict arrives +as a task notification; the dispatcher stamps after relay, not +before". The description carries only that phrase — the full sequence +has exactly one definition site, the workflow rule. + +Reports become self-describing, because a notification arrives as a +detached message that must survive compaction and parallel rounds: + +- the architect's report opens with the reviewed document's path, + followed by the model self-report line that opens it today — one + reconciled order, not two claims on the first line; +- the plan-adversary's JSON output gains a `subject` key holding the + reviewed plan's path. + +The stamp routes by that subject, which makes parallel rounds on +different documents safe without any further rule. + +### Recovery — deliberately no in-flight marker + +The session's knowledge of a running dispatch (agent, subject, model, +date) stays conversational. The design rejects a persistent in-flight +marker (an `architect: pending` value): an abandoned session would +leave a durable lie in a committable document, and the field's clean +semantics — value equals latest verdict — would break. Recovery +without a marker is idempotent: a missing stamp means the round never +closed, so the lifecycle rule's existing offer loop re-offers the +review at the document's next touch. The worst case is a repeated run +— wasted compute, no corruption. + +Two platform assumptions, stated so the wording can be revisited if +either proves wrong: a task notification is delivered once, to the +live session, and dies with it — an unrelayed verdict survives only in +the agent's transcript; and a cap refusal surfaces synchronously at +dispatch, before any background run starts. + +## Changes by file + +- `plugins/working-process/rules/workflow.md` — the new + dispatcher-sequence subsection; steps 3 and 5 gain a reference to it, + and the rule's standalone "After every round … record the verdict" + paragraph folds into that reference — the subsection's + relay-then-stamp statement replaces it, leaving no third restatement. +- `plugins/working-process/agents/architect.md` — `background: true`; + the description phrase; the report opens with the reviewed document's + path. +- `plugins/working-process/agents/plan-adversary.md` — `background: + true`; the description phrase; `subject` key in the JSON output. +- `plugins/working-process/rules/spec-plan-lifecycle.md` — "After any + review round, stamp the verdict into the document's field" becomes + "After any review round, relay the report to the developer, then + stamp the verdict into the document's field"; nothing else moves. + That sentence and the workflow rule's dispatcher-sequence subsection + state the same ordering and are edited together — the plugin's + existing device for a deliberate two-site statement. +- `plugins/working-process/rules/review-reports.md` — untouched; the + new subsection cites it as precedent rather than restating it. + +A minor working-process version bump at release; the change is +backward-compatible. + +## Out of scope + +- **Background plan-writing.** Consultation surfaced a real contract + for it (an Assumed-decisions section, a fill-gaps-never-override + boundary against the spec, ticket inheritance, a no-overwrite rule) + and a persona disagreement over whether it needs a named agent. It + is a separate feature riding the same mechanics and gets its own + spec; the contract is parked in Private memory as its input. +- Consult agents and standards review commands — already background. +- Making the "plan without a verdict" state greppable — judged + acceptable to leave invisible; revisit if a lost round ever hurts. + +## Verification + +Dogfooding in this repo, in two stages matching what a round can +exercise. Pre-implementation rounds — starting with this spec's own +architect review — verify the dispatcher sequence hand-driven: the +session stays free, the verdict arrives as a notification, and the +stamp lands after the relay. The shipped agent and rule changes are +verified only after the topic branch's dogfood version bump and a +rules re-sync — the plugin cache keys content by version. + +## Review rounds + +### 2026-08-17 — architect, fable, concerns + +Four Minor findings, all wording-level, all fixed the same day before +the next round: + +1. Two "opens with" claims on the architect's report — reconciled: the + document path first, then the model self-report. +2. Single-edit atomicity across non-contiguous regions unnamed — the + write ordering is now stated: body round record before the + frontmatter field. +3. The first-create bullet borrowed a justification that does not + transfer — rewritten to name the real consumer, the stamp turn. +4. "One new paragraph" undersized a ten-bullet sequence entering the + always-on rule — sized honestly, the context trade-off recorded. + +### 2026-08-17 — architect, fable, concerns (round 2) + +Four Minor findings, all wording-level, fixed the same day before the +next round: + +1. The cap-refusal timing claim was a second platform assumption stated + as fact — now mirrored in the revisitable platform-assumption + paragraph. +2. The changed-after-dispatch exception named no detection basis — now + stated: conversational knowledge only; an out-of-session edit is + accepted as undetectable. +3. The relay-then-stamp ordering will live in two rules — the lifecycle + bullet now carries the edited-together note. +4. Dangling "new paragraph" referent — now "subsection". + +### 2026-08-17 — architect, fable, concerns (round 3) + +Two Minor findings, both wording-level, fixed the same day: + +1. The non-interactive dispatcher had an obligation it cannot meet — + the sequence now defines the deferral: no relay possible means no + stamp, and the next interactive touch closes the round via the + existing re-offer loop. +2. Verification conflated two dogfoods — now split: hand-driven + dispatcher rounds before implementation, shipped artifacts after + the dogfood version bump and rules re-sync. + +### 2026-08-17 — architect, fable, concerns (round 4; resolved 2026-08-17 without a fresh round) + +Two Minor findings, both enumeration-completeness, fixed the same day. +The session halted the loop after four consecutive all-Minor rounds +(4, 4, 2, 2 findings) and annotated the concerns resolved instead of +dispatching a fifth round; the developer accepted the resolution the +same day: + +1. The workflow rule's standalone verdict-recording paragraph escaped + the change enumeration — Changes by file now folds it into the + subsection reference. +2. The one-live-round constraint read as absolute — now scoped to the + dispatching session, the cross-session case accepted as + undetectable like the out-of-session edit. + +Post-resolution addition, 2026-08-17: a dispatch-time announcement +bullet joined the sequence (the session tells the developer the round +runs in the background and the result arrives as a notification) — +routed from the implementation plan's adversary round 4, which flagged +the plan shipping it beyond this spec's enumeration. From d4433c8521cf3c6d98dac7488e2704080e38448a Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:22:53 +0200 Subject: [PATCH 002/126] feat(working-process): verdict-agent dispatch sequence in workflow rule --- plugins/working-process/rules/workflow.md | 63 ++++++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index e2f5bd8..98f37eb 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -24,14 +24,15 @@ disables its suggestion — never the work itself. (when the working-process plugin is installed) to stress-test its language against the project's domain terms. 3. **Grilled spec → architect review.** Offer a dispatch of the - working-process `architect` agent (when available); stamp its verdict - into the spec's `architect:` frontmatter field. + working-process `architect` agent (when available); dispatch and + stamping follow the verdict-agent dispatch subsection below. Dispatch it on the most capable available model, named explicitly. 4. **Spec → plan.** Write the implementation plan with superpowers:writing-plans when available; plans live in `docs/plans/`. 5. **Plan → adversary review.** Before implementing a non-trivial plan, offer a working-process plan-adversary agent dispatch (when - available); stamp its verdict into the plan's `adversary:` field. + available); dispatch and stamping follow the verdict-agent dispatch + subsection below. Dispatch it on a model scaled to the plan's size, complexity, and risk — the most capable available for complex or risky plans, one family below for small mechanical ones — named explicitly. @@ -39,11 +40,6 @@ disables its suggestion — never the work itself. superpowers:test-driven-development is available; bugs go through superpowers:systematic-debugging when available. -After every round of the `architect` agent or plan-adversary, record the -verdict (`LGTM` | `concerns` | `blocking`) in the reviewed document's -`architect:` / `adversary:` frontmatter field. A consultation -(`*-consult`) produces no verdict and nothing to record. - Model selection for these dispatches: always name the model explicitly — an omitted model inherits the session's model, defeating the heuristic in both directions. Reviews are never dispatched on the cheapest @@ -79,3 +75,54 @@ glossary — get its pass: invoke it before drafting a new document, and run an explicit editing pass over the changed prose of an existing one. The pass binds wording, never decisions. Without the skill there is no substitute pass and no install nagging — the work proceeds normally. + +## Dispatching a verdict agent + +Dispatching a verdict agent (`architect`, `plan-adversary`), when +available: + +- From an interactive session the dispatch always runs in the + background — a review never blocks the session, mirroring the + review-reports rule's precedent. A run with no interactive + dispatcher cannot relay, so it never stamps; the next interactive + touch closes the round through the lifecycle rule's re-offer loop. +- Before dispatch, resolve any undecided Process directory + (`docs/specs/`, `docs/plans/`) so the first-create question cannot + interrupt the stamp turn. +- At dispatch, tell the developer the round is running in the + background and its result will arrive as a task notification, with + progress visible in the session's task list. (This bullet is part of + the spec's sequence — added there 2026-08-17, routed from this + plan's adversary round 4.) +- On the completion notification, in one turn and in this order: + verify the agent's model self-report (the comparison the lifecycle + rule defines), relay the report to the developer, then stamp the + verdict (`LGTM` | `concerns` | `blocking`) into the reviewed + document's `architect:` / `adversary:` frontmatter field. +- The relay carries the verdict, the model self-report, and every + finding in substance — condense narrative prose, never drop a + finding or its severity. +- The stamp — the field, any fallback record, and the round record + the lifecycle rule defines — lands as one edit, body record first + where edit granularity forces separate writes, and goes to the + document named in the report, never to "the most recent dispatch". +- The sequence ends the delivery, not the loop: after relay and stamp + the session may fix the document and dispatch a fresh round, or put + its questions to the developer first. +- At most one live round per document per field within the session; + superseding a running round stops it when the platform offers a + stop, otherwise the stale result is relayed as stale and never + stamped. +- When the reviewed document changed after dispatch — known only + conversationally; an out-of-session edit is accepted as + undetectable — the relay says so and the stamp waits for the + developer's call. +- When compaction leaves an in-flight dispatch unclear, check the task + list rather than guess, and never fabricate a pending result. +- An agent that dies or returns nothing is an ordinary error: relay + the failure and offer a fresh dispatch on the same tier. +- A consultation (`*-consult`) produces no verdict and nothing to + record. + +This subsection and the lifecycle rule's relay-then-stamp sentence +state the same ordering and are edited together. From 7923ee7f413bec3879512e9e37228f040e9d5ea2 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:26:05 +0200 Subject: [PATCH 003/126] feat(working-process): architect runs in background with self-describing report --- plugins/working-process/agents/architect.md | 25 ++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/plugins/working-process/agents/architect.md b/plugins/working-process/agents/architect.md index 81ff9d2..fb884b5 100644 --- a/plugins/working-process/agents/architect.md +++ b/plugins/working-process/agents/architect.md @@ -1,6 +1,7 @@ --- name: architect -description: "Architect reviewing design quality — a grilled spec (primary target) or any design document dispatched standalone; its report always ends in a verdict. For a verdict-free second opinion on a question, dispatch architect-consult instead. Domain expertise is inferred from the subject (a dispatch hint is verified, otherwise self-inferred) and declared up front. Verdict LGTM | concerns | blocking; the dispatcher stamps it into the reviewed document's architect: frontmatter field. Not for failure-mode hunting on plans — that is plan-adversary. Dispatch on the most capable available model." +description: "Architect reviewing design quality — a grilled spec (primary target) or any design document dispatched standalone; its report always ends in a verdict. For a verdict-free second opinion on a question, dispatch architect-consult instead. Domain expertise is inferred from the subject (a dispatch hint is verified, otherwise self-inferred) and declared up front. Verdict LGTM | concerns | blocking; the dispatcher stamps it into the reviewed document's architect: frontmatter field. Not for failure-mode hunting on plans — that is plan-adversary. Dispatch on the most capable available model. Runs in the background; the verdict arrives as a task notification, and the dispatcher stamps after relay, not before." +background: true --- Formal-review surface of the architect persona. FIRST ACTION: read @@ -17,18 +18,22 @@ finding (evidence = that file), not only a call-out. subject's content and the repo's markers (e.g. `sfdx-project.json` marks a Salesforce project); add any domain the dispatcher missed. - No hint → infer the domains yourself from the same signals. -- Questions mid-run are impossible, so declare instead: every report - opens with an **Assumed domains** section — each domain, where it came - from (hint / inferred), and your confidence, stated in plain words when - low. A wrong inference must be visible at the top of the report and - cheap to fix by a re-dispatch with a corrected hint. +- Questions mid-run are impossible, so declare instead: the report + carries an **Assumed domains** section as its first numbered + section — each domain, where it came from (hint / inferred), and your + confidence, stated in plain words when low. A wrong inference must be + visible near the top of the report and cheap to fix by a re-dispatch + with a corrected hint. ## Report -The report opens with a one-line **model self-report** — the model this -review actually ran on, as family plus version (e.g. "opus 4.8") — -before any section; the dispatcher compares it against the dispatched -and prescribed tiers before stamping. +The report opens with a labeled **Subject** line — the path of the +reviewed document (a bare question has no path — say so instead) — +then a one-line **model self-report** — the model this review actually +ran on, as family plus version (e.g. "opus 4.8") — before any section. +The dispatcher routes the stamp by the Subject line and compares the +self-report against the dispatched and prescribed tiers before +stamping. 1. **Assumed domains** — see above. 2. **Findings** — one per issue: severity, section, a one-sentence claim, From d02e83ee4705a1626f3cb48deec36f193ea77b4e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:29:03 +0200 Subject: [PATCH 004/126] feat(working-process): plan-adversary runs in background with subject-keyed output --- plugins/working-process/agents/plan-adversary.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/agents/plan-adversary.md b/plugins/working-process/agents/plan-adversary.md index d53639b..e910c41 100644 --- a/plugins/working-process/agents/plan-adversary.md +++ b/plugins/working-process/agents/plan-adversary.md @@ -1,6 +1,7 @@ --- name: plan-adversary -description: Adversarial reviewer for implementation plans. Hunts the most likely ways the plan is wrong, mis-scoped, or will break silently. Loads domain *-plan-review checklist skills for the domains the plan touches. Severity-graded findings with evidence. Use before implementing any non-trivial plan. Specs are out of scope — design review of a spec belongs to the architect agent. Dispatch on a model scaled to the plan's size and risk — most capable for complex or risky plans, one family below for small mechanical ones; never the cheapest family. +description: Adversarial reviewer for implementation plans. Hunts the most likely ways the plan is wrong, mis-scoped, or will break silently. Loads domain *-plan-review checklist skills for the domains the plan touches. Severity-graded findings with evidence. Use before implementing any non-trivial plan. Specs are out of scope — design review of a spec belongs to the architect agent. Dispatch on a model scaled to the plan's size and risk — most capable for complex or risky plans, one family below for small mechanical ones; never the cheapest family. Runs in the background; the verdict arrives as a task notification, and the dispatcher stamps after relay, not before. +background: true --- Adversarial reviewer of implementation plans — the last gate before code. @@ -85,6 +86,7 @@ to a design document and would misfire as findings. ## Output { + "subject": "", "model": "", "verdict": "LGTM" | "concerns" | "blocking", "findings": [ From 8b19d2e72f14b8623225f6b2f851a3ba5f51a584 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:31:23 +0200 Subject: [PATCH 005/126] feat(working-process): relay-then-stamp ordering in lifecycle rule --- plugins/working-process/rules/spec-plan-lifecycle.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index c982e9f..a250ae3 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -74,7 +74,10 @@ its consumption gate (fresh round at the prescribed tier); and when a spec or plan moves to `implemented` and the memory-review-session skill is available, offer a Project memory review — released work-state notes close, resolved entries sweep to the archive. After any -review round, stamp the verdict into the document's field. +review round, relay the report to the developer, then stamp the +verdict into the document's field — this sentence and the workflow +rule's verdict-agent dispatch subsection state the same ordering and +are edited together. The process suggests committing the work's documents under `docs/` at exactly one point — the implementation-ready gate: the developer has From 93ec7c55e6160ba0f47e8b61f90206faac43824b Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:33:44 +0200 Subject: [PATCH 006/126] docs(working-process): background verdict dispatch in README --- plugins/working-process/README.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index 5c137ae..137fbac 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -15,7 +15,10 @@ writing-plans (plan) → plan-adversary → implementation. - **`architect` agent** — formal design-quality review of a grilled spec or any design document dispatched standalone; verdict `LGTM | concerns | blocking`, stamped into the reviewed document's - `architect:` frontmatter field by the dispatcher. Dispatched on the most capable available model. + `architect:` frontmatter field by the dispatcher. Dispatched in the + background on the most capable available model; the verdict arrives + as a task notification and is stamped after the dispatcher relays + the report. - **`architect-session` skill** — the same persona as an interactive in-session consultation: no verdict, no stamping; hands off to a grilling-session or an `architect` dispatch. Triggers: "ask the @@ -39,8 +42,9 @@ writing-plans (plan) → plan-adversary → implementation. - **`plan-adversary` agent** — adversarial review of implementation plans (plans only; handed a spec it declines toward the `architect` agent). Generic failure-mode dimensions live here; domain specifics - come from `*-plan-review` checklist skills. Dispatched scaled to the - plan's size and risk. + come from `*-plan-review` checklist skills. Dispatched in the + background, scaled to the plan's size and risk; the verdict arrives + as a task notification and is stamped after relay. - **`sync-rules` skill** — installs, updates, and uninstalls the rule files shipped by plugins of this marketplace (Rules payloads); see the "Process rules" section. @@ -109,8 +113,14 @@ The architect is dispatched on the most capable available model; the plan-adversary on a model scaled to the plan's size and risk — most capable for complex or risky plans, one family below for small mechanical ones. Consultations (the `*-consult` agents) dispatch on the most capable -available model as named background agents; they return no verdict, so -the fallback machinery below never applies to them. The model is always named explicitly at dispatch, and +available model; like the verdict agents, they run as named background +agents — consultations return no verdict, so the fallback machinery +below never applies to them. The verdict agents' relay-then-stamp +sequence lives in the workflow rule's Rules payload: after a plugin +update, run a rules re-sync so the dispatcher side of the behavior +matches the agents (until then the previously installed rules still +carry the older record-the-verdict obligation, so no round is lost). +The model is always named explicitly at dispatch, and reviews never dispatch on the cheapest available family. A dispatch refused on the dispatched model's cap offers a one-family drop (once) or waiting for the reset; a verdict produced below the prescribed tier From a564247475a2f9e9db696e5a446c84e9bbd21a19 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 18:36:54 +0200 Subject: [PATCH 007/126] chore(working-process): dogfood version for background-verdict-dispatch --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index b439e40..0b4bd7e 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary review agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.13.0", + "version": "0.14.0-dev.background-verdict-dispatch", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From bacd398a96c9a9382b26f709a8b3d534b6e483ce Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 22:37:10 +0200 Subject: [PATCH 008/126] fix(working-process): narrow lost-round recovery claim, drop provenance leak, honor verdict-agent ban --- plugins/working-process/rules/spec-plan-lifecycle.md | 2 +- plugins/working-process/rules/workflow.md | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index a250ae3..129af8a 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -50,7 +50,7 @@ base: master # optional: branch the topic branch was cut from re-arms at the same gate). Declined: the field gains `, waived `. Moving `status` to `implemented` with a bare fallback field stamps the waiver as part of the move. -- Review agents self-report the model they ran on (family plus version); +- Verdict agents self-report the model they ran on (family plus version); the dispatcher compares it against the dispatched and prescribed tiers before stamping, and each round's verdict, model, and date are recorded in the document body. Committed examples of the bare fallback form use diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 98f37eb..2a3cf05 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -84,16 +84,17 @@ available: - From an interactive session the dispatch always runs in the background — a review never blocks the session, mirroring the review-reports rule's precedent. A run with no interactive - dispatcher cannot relay, so it never stamps; the next interactive - touch closes the round through the lifecycle rule's re-offer loop. + dispatcher cannot relay, so it never stamps; on a document whose + field is still unstamped, the next interactive touch re-offers the + round through the lifecycle rule's offer loop. A round lost on an + already-stamped document leaves no signal and is accepted as lost — + never corruption, only a missing re-run. - Before dispatch, resolve any undecided Process directory (`docs/specs/`, `docs/plans/`) so the first-create question cannot interrupt the stamp turn. - At dispatch, tell the developer the round is running in the background and its result will arrive as a task notification, with - progress visible in the session's task list. (This bullet is part of - the spec's sequence — added there 2026-08-17, routed from this - plan's adversary round 4.) + progress visible in the session's task list. - On the completion notification, in one turn and in this order: verify the agent's model self-report (the comparison the lifecycle rule defines), relay the report to the developer, then stamp the From 084bcd46e48d73e0f668de64a2af9a4d05eea77e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 22:39:06 +0200 Subject: [PATCH 009/126] docs: reconcile spec and plan with dogfood round-5 findings --- .../2026-08-17-background-verdict-dispatch.md | 69 ++++++++++++++++--- ...8-17-background-verdict-dispatch-design.md | 43 ++++++++++-- 2 files changed, 97 insertions(+), 15 deletions(-) diff --git a/docs/plans/2026-08-17-background-verdict-dispatch.md b/docs/plans/2026-08-17-background-verdict-dispatch.md index 13ac89e..8de4561 100644 --- a/docs/plans/2026-08-17-background-verdict-dispatch.md +++ b/docs/plans/2026-08-17-background-verdict-dispatch.md @@ -2,7 +2,7 @@ ticket: none date: 2026-08-17 status: approved -adversary: concerns (resolved 2026-08-17) +adversary: blocking branch: feature/background-verdict-dispatch base: develop --- @@ -26,7 +26,7 @@ base: develop - Never force-add ignored files; tracked `docs/` documents ride the closing commit (Task 9), not per-task commits. - `claude plugin validate .` and `claude plugin validate plugins/working-process` must pass before every commit. - The spec is the contract: wording below is copied from it; on a conflict the spec wins. The spec's change enumeration binds shipped BEHAVIOR; user-facing docs (the README, Task 6) follow the repo convention that they match shipped behavior, extending the enumeration without amending it. -- Prescribed tiers for this plan's own review rounds: the architect on the most capable available family; the plan-adversary one family below it (a small mechanical plan) — rounds 1–3 ran exactly there (opus, below fable), so no fallback record applies. A dispatch below these tiers lands the `*-fallback: (chosen )` record in the same stamp edit, resolved or waived before Task 9's flip. +- Prescribed tiers for this plan's own review rounds: the architect on the most capable available family; the plan-adversary one family below it (a small mechanical plan) — a standing rule for every round of this plan, not a per-round record; a round at these tiers needs no fallback record. A dispatch below these tiers lands the `*-fallback: (chosen )` record in the same stamp edit, resolved or waived before Task 9's flip. - Rollout pairing: the plugin version delivers agent frontmatter immediately; the dispatcher sequence reaches a project only through a rules re-sync. The reverse window degrades sanely — the previously installed rules still carry the old "record the verdict" obligation, so no round is lost — and Task 6 states the pairing where users see it. --- @@ -116,9 +116,7 @@ available: interrupt the stamp turn. - At dispatch, tell the developer the round is running in the background and its result will arrive as a task notification, with - progress visible in the session's task list. (This bullet is part of - the spec's sequence — added there 2026-08-17, routed from this - plan's adversary round 4.) + progress visible in the session's task list. - On the completion notification, in one turn and in this order: verify the agent's model self-report (the comparison the lifecycle rule defines), relay the report to the developer, then stamp the @@ -560,7 +558,9 @@ Expected: validations PASS; each rule file reports exactly `1`. - [ ] **Step 1: Reconcile round records and review fields** -Check both documents' "Review rounds" sections list every architect/adversary round with verdict, model, and date — including Task 8's dogfood rounds. Reconcile the frontmatter fields: a verdict resolved without a fresh round carries the `(resolved )` annotation with its body note; a live fallback record is resolved (fresh prescribed-tier round) or waived. STOP: a non-LGTM dogfood verdict that is neither resolved nor annotated blocks Step 2. +Check both documents' "Review rounds" sections list every architect/adversary round with verdict, model, and date — including Task 8's dogfood rounds. Reconcile the frontmatter fields: a verdict resolved without a fresh round carries the `(resolved )` annotation with its body note; a live fallback record is resolved (fresh prescribed-tier round) or waived. STOP: a non-LGTM dogfood verdict that is neither resolved nor annotated blocks Step 2. Also verify branch cleanliness: `git diff develop...HEAD --stat` +touches only `plugins/working-process/` and the three gate-time docs +paths — an unexpected path is a defect, not luck. - [ ] **Step 2: Flip lifecycle status — with the developer's confirmation** @@ -568,11 +568,13 @@ With the developer's explicit go-ahead (never silently), move `status: approved` - [ ] **Step 3: Commit the docs** -The glossary rides this commit because the grilling session edited it (two terms: Verdict agent, Relay) outside the plan's tasks and it is still uncommitted. +The gate-time commit (6d780e3) already carries the spec, the plan, +and the glossary; this closing commit stages what changed since — +the two documents' round records, dispositions, and status flips. ```bash -git add docs/specs/2026-08-17-background-verdict-dispatch-design.md docs/plans/2026-08-17-background-verdict-dispatch.md docs/domain/glossary.md -git commit -m "docs: background-verdict-dispatch spec, plan, and glossary terms" +git add docs/specs/2026-08-17-background-verdict-dispatch-design.md docs/plans/2026-08-17-background-verdict-dispatch.md +git commit -m "docs: close background-verdict-dispatch spec and plan" ``` - [ ] **Step 4: Offer the memory review** @@ -686,3 +688,52 @@ Resolution note, 2026-08-17: all five round-4 findings fixed in this revision (the list above says how); the developer accepted the resolution in place of a fifth round after the 12→10→8→5 convergence across four rounds. + +### 2026-08-17 — plan-adversary, opus 5, blocking (round 5) + +Four Important, three Minor; the plan judged as the record of work +largely done (Tasks 1–7 committed, Task 8 dogfood in flight, Task 9 +remaining): + +1. Task 9 Step 1's closing gate accepts an annotation for a dogfood + finding that names shipped `plugins/` rule text as wrong — the + architect dogfood round's recovery-guarantee overclaim in + `workflow.md` could close as `implemented`; the plan defines no + route (fix, re-mint, re-dogfood) for such findings (I1). +2. Task 8's make-live gate is unmet in the environment the dogfood is + running in: the installed plugin is still 0.13.0 from the GitHub + clone, and the dogfood project's rules copy was hand-placed without + a `.manifest.json` — stage-two verification proves nothing about + the shipped marketplace/cache/sync-rules delivery path (I2). +3. Task 2 Step 2's prescribed text ships plan-internal review + provenance ("routed from this plan's adversary round 4") into the + always-on workflow rule, unresolvable for installed readers (I3). +4. The branch's own glossary ban (`review agent`, unqualified) is + violated by `spec-plan-lifecycle.md:53` — the very sentence the new + subsection defers to — and no task sweeps shipped content for the + new bans, unlike the memory-hybrid precedent (I4). +5. The plan-as-record contradicts the branch: the docs commit is + already the branch's FIRST commit (6d780e3, carrying spec, plan, + and glossary), so Global Constraints line "docs ride the closing + commit" and Task 9 Step 3's "still uncommitted" rationale, staging, + and message are stale (M5). +6. The closing task has no whole-branch untouched-proof (no + `git diff --name-only develop... -- plugins/` check), unlike the + memory-hybrid precedent's Task 9 (M6). +7. The prescribed-tier statement enumerates rounds 1–3 only, leaving + rounds 4–5 outside the record Task 9's fallback reconciliation + reads; restate as a standing rule (M7). + +Dispositions, 2026-08-17: I1 fixed — the recovery claim is narrowed in +the spec and the shipped rule, and the fix→re-mint→re-check path ran +(discriminator -2). I2 partially rejected — the temp-config install +proved marketplace→cache→load for the dogfood version (version, +content, enabled state all verified); the un-exercised half is +sync-rules delivery, which this branch does not touch and which is +regression scope, not this plan's deliverable; the developer +authorized the temporary setup. I3 fixed — the provenance parenthesis +is deleted from the shipped rule and the plan block. I4 fixed — +"Verdict agents self-report" in the lifecycle rule. M5 fixed — Task 9 +Step 3 rewritten for the gate-time commit. M6 fixed — branch-diff +check added to Task 9 Step 1. M7 fixed — the tier line is a standing +rule. A fresh adversary round follows the re-mint. diff --git a/docs/specs/2026-08-17-background-verdict-dispatch-design.md b/docs/specs/2026-08-17-background-verdict-dispatch-design.md index 7177dbd..bafd309 100644 --- a/docs/specs/2026-08-17-background-verdict-dispatch-design.md +++ b/docs/specs/2026-08-17-background-verdict-dispatch-design.md @@ -28,7 +28,7 @@ verdict arrives as a task notification instead of a tool result. ### Dispatcher sequence — canonical in the workflow rule -A dispatcher-sequence subsection in the workflow rule's dispatch +A verdict-agent dispatch subsection in the workflow rule's dispatch guidance defines the sequence; steps 3 and 5 reference it instead of restating it. The workflow rule loads in every session (the plugin's deliberate always-on exception), so the subsection is context every @@ -41,9 +41,11 @@ outweighs the context weight. foreground escape: a developer who wants to wait simply waits for the notification. - A run with no interactive dispatcher cannot relay, so it never - stamps — mirroring the review-reports precedent's deferral. The next - interactive touch closes the round through the re-offer loop the - Recovery section supplies. + stamps — mirroring the review-reports precedent's deferral. On a + document whose field is still unstamped, the next interactive touch + re-offers the round through the Recovery section's offer loop; a + round lost on an already-stamped document leaves no signal and is + accepted as lost. - A verdict agent writes nothing, so no directory question guards the agent itself; what the pre-dispatch check guards is the stamp turn. A pre-existing but undecided `docs/specs/` or `docs/plans/` would @@ -126,7 +128,10 @@ semantics — value equals latest verdict — would break. Recovery without a marker is idempotent: a missing stamp means the round never closed, so the lifecycle rule's existing offer loop re-offers the review at the document's next touch. The worst case is a repeated run -— wasted compute, no corruption. +— wasted compute, no corruption. That idempotence covers an unstamped field. A later round lost on an +already-stamped document leaves no signal — the field shows the prior +verdict and looks closed — and is accepted as invisible, like the +cross-session cases. Two platform assumptions, stated so the wording can be revisited if either proves wrong: a task notification is delivered once, to the @@ -137,7 +142,7 @@ dispatch, before any background run starts. ## Changes by file - `plugins/working-process/rules/workflow.md` — the new - dispatcher-sequence subsection; steps 3 and 5 gain a reference to it, + verdict-agent dispatch subsection; steps 3 and 5 gain a reference to it, and the rule's standalone "After every round … record the verdict" paragraph folds into that reference — the subsection's relay-then-stamp statement replaces it, leaving no third restatement. @@ -245,3 +250,29 @@ bullet joined the sequence (the session tells the developer the round runs in the background and the result arrives as a notification) — routed from the implementation plan's adversary round 4, which flagged the plan shipping it beyond this spec's enumeration. + +### 2026-08-17 — architect, fable, concerns (round 5) + +One Important finding and one Minor: + +1. Important — the Recovery guarantee ("a missing stamp means the + round never closed, so the offer loop re-offers at the next touch") + holds only for an unstamped field. On any round after the first the + field already carries a verdict, and the lifecycle rule's greppable + anchors match only bare `blocking|concerns` values — a document + reading `LGTM` or `concerns (resolved …)` presents as fully closed, + so a lost later round leaves no signal and silently vanishes. Not + the out-of-scope unverdicted case: this is a verdicted-but-stale + state Recovery claims to close and cannot. Suggested: scope the + Recovery claim to rounds on an unstamped field and fold the + stamped-document lost round into the accepted-invisible bucket, or + give the offer loop a visible trigger. +2. Minor — the spec names the new subsection "dispatcher-sequence" + while both edited-together consumers ship "verdict-agent dispatch + subsection"; two names for one two-site statement invite the drift + the edited-together device exists to prevent. Suggested: rename the + spec's references to match the shipped heading. + +Resolution note, 2026-08-17: both findings fixed the same day — the +recovery claim narrowed in the spec and the shipped rule, and the +subsection references unified to the heading's name. From ffea3579745fe49ae6f7a7fdff14f17dcf8ffbb7 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 22:39:29 +0200 Subject: [PATCH 010/126] chore(working-process): re-mint dogfood discriminator after round-5 fixes --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index 0b4bd7e..8a216e2 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary review agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0-dev.background-verdict-dispatch", + "version": "0.14.0-dev.background-verdict-dispatch-2", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From 0ec1aa0d2274d1af8d947ef02c5b6656f41d16a6 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 23:11:51 +0200 Subject: [PATCH 011/126] fix(working-process): verdict agents across the plugin identity surfaces --- .claude-plugin/marketplace.json | 2 +- README.md | 2 +- plugins/working-process/.claude-plugin/plugin.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index eb73ccc..8416179 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ { "name": "working-process", "source": "./plugins/working-process", - "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary review agents, architect-consult and system-designer-consult consultation agents, plus distributed process rules" + "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, plus distributed process rules" }, { "name": "python-standards", diff --git a/README.md b/README.md index 85de10f..8bbb2be 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Marketplace of [Claude Code](https://code.claude.com) plugins by Missing Bits. | Plugin | Docs | Description | |--------|------|-------------| -| `working-process` | [README](plugins/working-process/README.md) | Spec-driven working process: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary review agents, two verdict-free consultation agents, distributed process rules | +| `working-process` | [README](plugins/working-process/README.md) | Spec-driven working process: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, two verdict-free consultation agents, distributed process rules | | `python-standards` | [README](plugins/python-standards/README.md) | Python coding standards for uv + ruff + pytest + pyright: area skills, code-review stack, plan-review checklist, distributed toolchain rule | | `salesforce-standards` | [README](plugins/salesforce-standards/README.md) | Salesforce coding standards for the sf CLI toolchain: area skills (Apex, LWC, Flow, data/security model, legacy UI), code-review stack, plan-review checklist, distributed toolchain rule | | `project-memory` | [README](plugins/project-memory/README.md) | In-repo project memory: committed Team memory (`docs/memory/`) and per-user Private memory (`.claude/memory/`), with `memory-review-session`, `migrate-memory`, and `redirect-memory` skills, distributed as a Rules payload | diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index 8a216e2..c2dca27 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "working-process", - "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary review agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", + "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", "version": "0.14.0-dev.background-verdict-dispatch-2", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", From 6efcdd98bc91488cf03fddb27a4aef71808c1212 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 23:12:01 +0200 Subject: [PATCH 012/126] chore(working-process): re-mint dogfood discriminator after round-7 fixes --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index c2dca27..7768478 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0-dev.background-verdict-dispatch-2", + "version": "0.14.0-dev.background-verdict-dispatch-3", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From 6d40269a7fc64a828c40e88decf189bbf16b35e2 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 17 Aug 2026 23:38:14 +0200 Subject: [PATCH 013/126] docs: close background-verdict-dispatch spec and plan --- .../2026-08-17-background-verdict-dispatch.md | 242 ++++++++++++++++-- ...8-17-background-verdict-dispatch-design.md | 14 +- 2 files changed, 236 insertions(+), 20 deletions(-) diff --git a/docs/plans/2026-08-17-background-verdict-dispatch.md b/docs/plans/2026-08-17-background-verdict-dispatch.md index 8de4561..eb45ecb 100644 --- a/docs/plans/2026-08-17-background-verdict-dispatch.md +++ b/docs/plans/2026-08-17-background-verdict-dispatch.md @@ -1,8 +1,8 @@ --- ticket: none date: 2026-08-17 -status: approved -adversary: blocking +status: implemented +adversary: blocking (adjudicated 2026-08-17) branch: feature/background-verdict-dispatch base: develop --- @@ -25,7 +25,7 @@ base: develop - Rule text mentions skills/agents conditionally ("when available") — rules load for people without the plugin. - Never force-add ignored files; tracked `docs/` documents ride the closing commit (Task 9), not per-task commits. - `claude plugin validate .` and `claude plugin validate plugins/working-process` must pass before every commit. -- The spec is the contract: wording below is copied from it; on a conflict the spec wins. The spec's change enumeration binds shipped BEHAVIOR; user-facing docs (the README, Task 6) follow the repo convention that they match shipped behavior, extending the enumeration without amending it. +- The spec is the contract: wording below is copied from it; on a conflict the spec wins. The spec's change enumeration binds shipped BEHAVIOR; user-facing docs (the plugin README, Task 6) and the identity surfaces the marketplace-sync rule binds (the catalog entry, the repo README row) follow the repo convention that they match shipped behavior, extending the enumeration without amending it. - Prescribed tiers for this plan's own review rounds: the architect on the most capable available family; the plan-adversary one family below it (a small mechanical plan) — a standing rule for every round of this plan, not a per-round record; a round at these tiers needs no fallback record. A dispatch below these tiers lands the `*-fallback: (chosen )` record in the same stamp edit, resolved or waived before Task 9's flip. - Rollout pairing: the plugin version delivers agent frontmatter immediately; the dispatcher sequence reaches a project only through a rules re-sync. The reverse window degrades sanely — the previously installed rules still carry the old "record the verdict" obligation, so no round is lost — and Task 6 states the pairing where users see it. @@ -60,7 +60,7 @@ base: develop - [ ] **Step 3: Verify placement** Run: `rg -n "^(branch|base):" docs/specs/2026-08-17-background-verdict-dispatch-design.md docs/plans/2026-08-17-background-verdict-dispatch.md` -Expected: two matches per file, with line numbers inside each YAML frontmatter block — the block's final fields, directly above the closing `---`. +Expected: the frontmatter pair in each file sits directly above the closing `---`; the plan file returns two extra matches from its own Task 1 Step 2 instructional snippet — expected, not a defect. - [ ] **Step 4: Cross the implementation-ready gate** @@ -109,8 +109,11 @@ available: - From an interactive session the dispatch always runs in the background — a review never blocks the session, mirroring the review-reports rule's precedent. A run with no interactive - dispatcher cannot relay, so it never stamps; the next interactive - touch closes the round through the lifecycle rule's re-offer loop. + dispatcher cannot relay, so it never stamps; on a document whose + field is still unstamped, the next interactive touch re-offers the + round through the lifecycle rule's offer loop. A round lost on an + already-stamped document leaves no signal and is accepted as lost — + never corruption, only a missing re-run. - Before dispatch, resolve any undecided Process directory (`docs/specs/`, `docs/plans/`) so the first-create question cannot interrupt the stamp turn. @@ -514,14 +517,25 @@ git commit -m "chore(working-process): dogfood version for background-verdict-di - Consumes: everything above, live under the dogfood version. - Produces: the spec's verification stage two (shipped artifacts), for BOTH verdict agents. -- [ ] **Step 1: Make the shipped content live — STOP, developer-driven** - -STOP and hand this step to the developer on their explicit go-ahead — a marketplace change, a plugin update, and a sync-rules run mutate the developer's installed state and are never run unbid (the review-reports, memory-hybrid, and memory-entry-format plans' precedent). The installed `missing-bits` marketplace is a GitHub clone pinned to released `master`, so it can never serve the dogfood version. With the developer driving: add (or update) a marketplace sourced from this checkout — `/plugin marketplace add ` — install or update `working-process` from THAT marketplace, then run the `working-process:sync-rules` skill so the installed Rules payload picks up the new subsection and lifecycle sentence. The executor resumes at Step 2. +- [ ] **Step 1: Make the shipped content live — as executed: a temporary, self-cleaning setup** + +Executed with the developer's explicit authorization as a temporary +setup instead of mutating the real install: a scratch +CLAUDE_CONFIG_DIR received a marketplace sourced from this checkout +plus the plugin install/update (proving marketplace→cache→load for +each dogfood discriminator), the payload rules were copied +project-scope into a scratch dogfood project, and the inner dispatcher +sessions ran with --plugin-dir from the checkout. The developer's real +install was touched only by a reversible plugin disable/enable pair, +restored the same day; their installed rules update at release through +the ordinary sync-rules path. (The original developer-driven variant — +real marketplace add, plugin update, sync-rules run — remains valid +when a developer prefers dogfooding on their live install.) - [ ] **Step 2: Confirm the served version AND the installed content** Run: `claude plugin list 2>/dev/null | grep -A1 working-process` -Expected: `0.14.0-dev.background-verdict-dispatch` (the string only — content follows). +Expected: the discriminator currently minted in `plugins/working-process/.claude-plugin/plugin.json` — after re-mint N that is the `-N`-suffixed string; a stale un-suffixed expectation cannot fail on pre-re-mint content. Run: `rg -c "Dispatching a verdict agent" "$HOME/.claude/rules/working-process/workflow.md"` and `rg -c "edited together" "$HOME/.claude/rules/working-process/spec-plan-lifecycle.md"` — checking the project-level copy instead when that is the installed one. Expected: `1` each. On a miss STOP — the dispatching session would run against the stale rules (the review-contract-sharpening plan's dogfood-gate precedent). @@ -532,8 +546,8 @@ Expected: all three observed; any miss is a defect to fix before the release PR. - [ ] **Step 4: Exercise a plan-adversary dispatch — a real round** -In the same fresh session, dispatch `plan-adversary` on `docs/plans/2026-08-17-background-verdict-dispatch.md` (this plan), one family below the most capable available model (a small mechanical plan), named explicitly at dispatch. This too is a live round: stamped and recorded in the plan body. Confirm: the dispatch returns immediately, the JSON output carries the `subject` key with the plan's path, and the session relays before stamping. -Expected: all three observed. +In the same fresh session, dispatch `plan-adversary` on `docs/plans/2026-08-17-background-verdict-dispatch.md` (this plan), one family below the most capable available model (a small mechanical plan), named explicitly at dispatch. This too is a live round: stamped and recorded in the plan body. Confirm the discriminating observables: the JSON output carries the `subject` key with the plan's path, and the session relays before stamping; the immediate return is context, not evidence. +Expected: both observed. - [ ] **Step 5: Re-mint on any post-mint content fix** @@ -550,17 +564,27 @@ Expected: validations PASS; each rule file reports exactly `1`. **Files:** - Modify: `docs/specs/2026-08-17-background-verdict-dispatch-design.md` (frontmatter `status`) -- Modify: `docs/plans/2026-08-17-background-verdict-dispatch.md` (frontmatter `status`, checked boxes) +- Modify: `docs/plans/2026-08-17-background-verdict-dispatch.md` (frontmatter `status`) **Interfaces:** - Consumes: Task 8 passed; every round record present in both documents. - Produces: the closed lifecycle the two preceding plans end with. +Version note: no task on this branch restores the release string — the +release PR strips the discriminator while minting the final version +(plugin-versioning rule). + - [ ] **Step 1: Reconcile round records and review fields** Check both documents' "Review rounds" sections list every architect/adversary round with verdict, model, and date — including Task 8's dogfood rounds. Reconcile the frontmatter fields: a verdict resolved without a fresh round carries the `(resolved )` annotation with its body note; a live fallback record is resolved (fresh prescribed-tier round) or waived. STOP: a non-LGTM dogfood verdict that is neither resolved nor annotated blocks Step 2. Also verify branch cleanliness: `git diff develop...HEAD --stat` -touches only `plugins/working-process/` and the three gate-time docs -paths — an unexpected path is a defect, not luck. +touches only `plugins/working-process/`, the three gate-time docs +paths, and the plugin's identity surfaces the marketplace-sync rule +binds together (`.claude-plugin/marketplace.json`, the repo +`README.md` row — swept by round 7's I1 fix) — an unexpected path is a +defect, not luck. Finally, diff every rewritten block the plan quotes (Tasks 2–6 +"with:" blocks) against the shipped files — the plan is recipe and +record at once, and a drifted block re-run would revert a shipped fix; +STOP on any mismatch. - [ ] **Step 2: Flip lifecycle status — with the developer's confirmation** @@ -737,3 +761,191 @@ is deleted from the shipped rule and the plan block. I4 fixed — Step 3 rewritten for the gate-time commit. M6 fixed — branch-diff check added to Task 9 Step 1. M7 fixed — the tier line is a standing rule. A fresh adversary round follows the re-mint. + +### 2026-08-17 — plan-adversary, opus 5, blocking (round 6) + +Two Important, four Minor; the reviewer diffed every prescribed +"after" block against the shipped files, re-checked round 5's +partially rejected I2, and did not re-raise it (no new evidence +beyond the recorded counter-evidence). Underlying weakness named: +nothing in Task 9 reconciles plan text against shipped text, so the +branch could close as `implemented` with the plan asserting rule +wording the repo does not contain. + +1. Important — Task 2 Step 2's prescribed subsection text still + carries the un-narrowed recovery claim round 5's I1 blocked on + ("the next interactive touch closes the round through the + lifecycle rule's re-offer loop"), while the shipped rule + (bacd398) carries the narrowed version — re-executing Task 2 from + this plan regresses the fix; the only divergence the + block-by-block diff found (I1). +2. Important — the re-mint ladder mandates re-running dogfood + Steps 3–4 after a post-mint content fix, but Task 9 Step 1's + closing gate never checks that the recorded dogfood rounds ran + under the current discriminator: rounds produced against pre-fix + content under `-1` satisfy it verbatim, and the architect re-run + Step 5 owes under `-2` is unrecorded and unblocked (I2). +3. Minor — Task 8 Step 2's expected version is the un-suffixed + literal, so the gate cannot fail on a stale pre-re-mint version; + expect the discriminator currently in plugin.json, exact match + (M3). +4. Minor — no task returns the plugin version to a release string, + and the plan omits its precedent's note (memory-hybrid) that the + release PR strips the discriminator while minting the final + version (M4). +5. Minor — the branch's new glossary ban on `reviewer agent` still + has live violations in `review-reports.md` (lines 22 and 39) and + no sweep step or recorded scope decision covers them (M5). +6. Minor — Task 9's Files list names "checked boxes" as a + deliverable, but no step checks any box and all 35 remain + unchecked; repo precedent is split (M6). + +Dispositions, 2026-08-17: I1 fixed — the Task 2 block is byte-identical +to the shipped subsection again (the drift would have reverted commit +bacd398 on a re-run). I2 waived with ruling — `git diff +a564247..ffea357 -- plugins/working-process/agents/` is empty, so the +agent-side observables verified under -1 hold verbatim under -2, and +round 6 itself exercised the dispatcher side under -2 (announce, +verify, relay, body-first stamp); an architect repeat under -2 would +re-verify nothing. M3 fixed — the version expectation tracks the +current discriminator. M4 fixed — the release-string note is in +Task 9. M5 rejected with ruling — the glossary ban lists "reviewer +agent" as an avoided name for the Verdict-agent concept; +review-reports.md's "reviewer agent" names the dispatched code-review +run owner, a different concept outside the entry's referent (glossary +Avoid semantics are per-concept); flagged as a possible future wording +cleanup, no sweep owed. M6 fixed — the checked-boxes deliverable is +dropped; the ledger and round records are the execution record. + +### 2026-08-17 — plan-adversary, opus 5, blocking (round 7) + +Three Important, one Minor. The reviewer first verified round 6's +dispositions against the working tree — Task 2's prescribed block +byte-identical to the shipped subsection, the I2 waiver's empty +`agents/` diff confirmed, M3/M4/M6 confirmed fixed, every prescribed +"after" block in Tasks 3–6 matching the shipped diff — and re-raised +nothing waived or rejected: + +1. Important — the branch's own glossary ban on `review agent` + (unqualified) has two live, in-scope violations naming the verdict + agents literally: `plugins/working-process/.claude-plugin/plugin.json:3` + and `.claude-plugin/marketplace.json` (working-process description), + both reading "architect and plan-adversary review agents" — squarely + inside the Verdict-agent referent, so round 6's per-concept M5 + ruling is no defense; round 5's I4 established the sweep obligation + by fixing the identical form in `spec-plan-lifecycle.md`. Suggested: + replace with "verdict agents" in both manifests, or record an + explicit scope ruling; the plugin.json edit is content, so it + re-mints the discriminator per Task 8 Step 5 (I1). +2. Important — Task 9's close gate still has no step reconciling the + plan's prescribed blocks against shipped text, the systemic weakness + round 6 named in its preamble and left undispositioned: Task 9 + Step 1 checks only round records, frontmatter fields, and the + branch-diff paths, so the branch can close as `implemented` with the + plan asserting rule wording the repo does not contain — rounds 6 and + 7 both had to establish agreement by hand-diffing every block. + Suggested: a Step 1 sub-check diffing each prescribed replacement + block against its shipped file, STOP on divergence (I2). +3. Important — Task 8 Step 1 prescribes a durable mutation of the + developer's installed state (checkout-sourced marketplace, plugin + update, sync-rules) with no restoring step anywhere, while the + round-5 disposition records the executed path deliberately avoided + it (developer-authorized temp-config install). Confirmed live + consequence: the home rules copy of `workflow.md` is still + pre-change while the dogfood project's copy carries `-2` content — + a split install state nothing in the plan reconciles. Suggested: + rewrite Step 1 to the temp-config path actually used (self-cleaning), + or add a Task 9 restore step (I3). +4. Minor — round 4's M4 demotion of "returns immediately" was applied + to Step 3 only; Task 8 Step 4 still lists immediacy as a confirmable + observable. Suggested: drop it from Step 4's confirm list or mark it + context as Step 3 does (M4). + +The reviewer notes the I1 fix re-mints the discriminator to `-3` and +re-triggers Task 8 Steps 1–2; whether Steps 3–4 are owed again is the +question round 6's I2 waiver answered for `-2`, and the same reasoning +(`agents/` untouched) would apply. + +Dispositions, 2026-08-17: I1 fixed — "verdict agents" now in all three +identity surfaces (plugin.json, marketplace.json, the README table row) +per the marketplace-sync rule, with the discriminator re-minted to -3. +I2 fixed — Task 9 Step 1 gains the rewritten-block diff with a STOP. +I3 fixed — Task 8 Step 1 now records the temporary-setup path actually +executed, with the live-install variant kept as an option. M4 fixed — +Step 4's immediate return demoted to context. Steps 3–4 repetition +under -3 waived by the round-6 ruling's reasoning: the -2→-3 commits +touch no file under plugins/working-process/agents/ and no rule file. + +### 2026-08-17 — plan-adversary, opus 5, blocking (round 8) + +Three Important, one Minor. The reviewer first verified round 7's +dispositions against the working tree — the manifests sweep present +(0ec1aa0), the discriminator at -3 (6efcdd9), the rewritten-block diff +in Task 9 Step 1, the temp-config path in Task 8 Step 1, Step 4's +immediacy demoted — diffed every prescribed "with:" block in Tasks 2–6 +against the shipped files (all byte-identical), confirmed the +Steps 3–4 waiver's premise via the empty `agents/` and rule-file diff, +and re-raised nothing waived or rejected. `claude plugin validate` +passes on both manifests. This is the loop's pre-decided final round: +the verdict goes to developer adjudication, not another round. + +1. Important — round 7's own I1 fix put two paths on the branch the + plan neither prescribes nor permits: `git diff develop...HEAD + --name-only` lists `.claude-plugin/marketplace.json` and the root + `README.md` (commit 0ec1aa0), yet Task 9 Step 1's cleanliness gate + expects only `plugins/working-process/` and the three gate-time + docs paths — it now STOPs on legitimate shipped content — and the + Global Constraints carve-out ("the README, Task 6") covers only the + plugin README, not the two manifests, which the marketplace-sync + rule forces to move together. Suggested: add the identity-surface + edit as a numbered step, extend the gate's expected paths and the + enumeration carve-out to manifest identity text — or record an + explicit scope ruling the gate reads (I1). +2. Important — Task 8 Steps 1–2 are owed under discriminator -3 and + never ran: the re-mint ladder (Task 8 Step 5) and round 7's own + note re-trigger Steps 1–2 on a re-mint, the round-7 disposition + waives only Steps 3–4, and that waiver's reasoning (agents and + rules untouched) does not reach `plugin.json`, whose description + string changed in 0ec1aa0 and which no dogfood pass has loaded; + Task 9's close gate never checks that the recorded dogfood pass + names the discriminator currently in `plugin.json`. Suggested: + re-run Steps 1–2 under -3 and record the result, or waive them + explicitly with reasoning in the round-8 dispositions, and give + Task 9 Step 1 a discriminator sub-check (I2). +3. Important — the spec's Verification section still names a rules + re-sync as part of stage-two verification, while the executed path + (round-7 I3's rewrite of Task 8 Step 1) copied the payload rules + project-scope; the spec is the contract on a conflict, and Task 9 + flips it to `implemented` with no step reconciling the spec's own + claim against what ran. Suggested: amend the spec's Verification + sentence to the path actually executed (the sync-rules half + recorded as regression scope per the round-5 ruling) and add that + amendment to Task 9 Step 1's reconciliation (I3). +4. Minor — the close path depends on annotating a `blocking` verdict + as resolved, but the shipped lifecycle rule scopes the + `(resolved )` annotation to `concerns` only + (spec-plan-lifecycle.md:32–34), and this document sits at + `adversary: blocking` beside `status: approved` going into + adjudication. Suggested: record a ruling in Task 9 Step 1 that + `blocking` takes the same annotation form (the greppable anchor at + spec-plan-lifecycle.md:64 covers both values), or note the + rule-text change as out of this spec's enumeration, a follow-up + (M4). + +Dispositions, 2026-08-17 — developer adjudication, the pre-decided +close of the loop's final round: I1 fixed — Task 9 Step 1's expected +paths and the Global Constraints carve-out now include the identity +surfaces the marketplace-sync rule binds. I2 fixed by recording — +Steps 1–2 DID run under -3 before this round: the temp-config +marketplace and plugin updates to -3 succeeded and the cached +plugin.json carries "verdict agents" (grep count 1); the gap was the +missing record, closed by this line. I3 fixed — the spec's +Verification sentence now records the executed temporary-setup path, +the sync-rules half noted as regression scope per the round-5 ruling. +M4 adjudicated — blocking takes the same annotation form as concerns +by developer decision: the field closes as `blocking (adjudicated +2026-08-17)` with this record as its body note; extending the +lifecycle rule's text to name the form is a follow-up outside this +spec's enumeration. Every finding of rounds 5–8 is fixed, waived, +rejected, or adjudicated on the record; the developer closes the loop +— no round 9. diff --git a/docs/specs/2026-08-17-background-verdict-dispatch-design.md b/docs/specs/2026-08-17-background-verdict-dispatch-design.md index bafd309..00866f4 100644 --- a/docs/specs/2026-08-17-background-verdict-dispatch-design.md +++ b/docs/specs/2026-08-17-background-verdict-dispatch-design.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-08-17 -status: approved +status: implemented grilled: 2026-08-17 architect: concerns (resolved 2026-08-17) branch: feature/background-verdict-dispatch @@ -102,7 +102,7 @@ outweighs the context weight. Both verdict agents gain `background: true` in their frontmatter and one description phrase: "runs in the background; the verdict arrives -as a task notification; the dispatcher stamps after relay, not +as a task notification, and the dispatcher stamps after relay, not before". The description carries only that phrase — the full sequence has exactly one definition site, the workflow rule. @@ -155,7 +155,7 @@ dispatch, before any background run starts. review round, stamp the verdict into the document's field" becomes "After any review round, relay the report to the developer, then stamp the verdict into the document's field"; nothing else moves. - That sentence and the workflow rule's dispatcher-sequence subsection + That sentence and the workflow rule's verdict-agent dispatch subsection state the same ordering and are edited together — the plugin's existing device for a deliberate two-site statement. - `plugins/working-process/rules/review-reports.md` — untouched; the @@ -183,8 +183,12 @@ exercise. Pre-implementation rounds — starting with this spec's own architect review — verify the dispatcher sequence hand-driven: the session stays free, the verdict arrives as a notification, and the stamp lands after the relay. The shipped agent and rule changes are -verified only after the topic branch's dogfood version bump and a -rules re-sync — the plugin cache keys content by version. +verified after the topic branch's dogfood version bump, against the +installed cache and the rules made live for the dogfood sessions — as +executed 2026-08-17 through a developer-authorized temporary setup (a +checkout-sourced marketplace in a scratch config, the payload rules +project-scope); the sync-rules delivery half is regression scope, +untouched by this change. The plugin cache keys content by version. ## Review rounds From 977075aa4fa8e38ed788e49c70af28ed49998d49 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 11:46:57 +0200 Subject: [PATCH 014/126] feat(working-process): publish the unfinished-work list as a named section --- .../rules/spec-plan-lifecycle.md | 60 ++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 129af8a..1e0128c 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -54,18 +54,60 @@ base: master # optional: branch the topic branch was cut from the dispatcher compares it against the dispatched and prescribed tiers before stamping, and each round's verdict, model, and date are recorded in the document body. Committed examples of the bare fallback form use - placeholders (as above) so they never match the grep below. + placeholders (as above) so they never match the list below. - `branch` and `base` appear once the topic branch exists — never guessed up front, omitted entirely when there is no topic branch. -- Unfinished process work is greppable: - `rg -l '^grilled: grilling' docs/` and - `rg -l '^(architect|adversary): (blocking|concerns)$' docs/` — the - anchored match deliberately skips resolved-concern annotations. - `rg -l '^(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/` - — pending re-reviews; the waived annotation deliberately defeats the - anchor. -Lifecycle offers — each an offer the developer may decline, and each made +## Unfinished-work list + +One entry per class of unfinished process work: the class name, its +command, and the owner of the next move. This section is the list — a +command published elsewhere, such as the ticket sweep in the +ticket-frontmatter rule, is a lookup and not part of it. The +`process-status` skill, when available, runs exactly what stands here, +and this heading is the name it keys on: the heading and the skill move +together or not at all. + +A command returns hits, not Findings. A hit counts only when the +matching line sits inside the document's frontmatter block — between the +`---` on the file's first line and the `---` that closes it, never a +later pair — because a document quoting this convention in its body +describes it rather than instantiating it. + +- **Grilling pending** — a session's outcomes are recorded and not yet + applied. + `rg -l --no-ignore --crlf '^\s*grilled: grilling' docs/` + Owner: the grilling-session, when available. +- **Unresolved verdict** — a round ended in `concerns` or `blocking` + and nothing closed it. + `rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/` + Owner: a fresh round at the prescribed tier, or the resolution + annotation above. +- **Pending re-review** — a verdict produced below the prescribed tier, + neither refreshed nor waived. + `rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/` + Owner: the re-review offer at the document's consumption gate. +- **Misplaced stamp** — a process field outside the top level of the + frontmatter, at any value. + `rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback):' docs/` + Owner: the developer; no process surface owns moving a stamp back. + The class suppresses per field: it hides the one other class whose + published command would match the relocated line, and no other — + itself excluded, since its own command matches every process field. + Match semantics are the mapping, so a class published later needs no + extra rule. + +The tail anchors are exact on purpose: a `(resolved )`, +`(adjudicated )` or `, waived ` annotation defeats the +match, and that defeat is the recorded closed state. The leading +anchors are tolerant on purpose, so a relocated field is still found. +The Misplaced stamp command anchors `^\s+` instead, because there the +indentation is the defect it looks for rather than an accident to +tolerate. + +## Lifecycle offers + +Each an offer the developer may decline, and each made only when the tool is available: grill a fresh spec (grilling-session); architect-review a grilled spec (architect agent dispatch); adversary-review a plan before implementation (plan-adversary agent From e2a8e0194adf806928dde2ad8365be8d56c6af8c Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 11:52:13 +0200 Subject: [PATCH 015/126] fix(working-process): tolerate a relocated field in the ticket sweep --- plugins/working-process/rules/ticket-frontmatter.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/working-process/rules/ticket-frontmatter.md b/plugins/working-process/rules/ticket-frontmatter.md index 506ebc4..30f7582 100644 --- a/plugins/working-process/rules/ticket-frontmatter.md +++ b/plugins/working-process/rules/ticket-frontmatter.md @@ -54,5 +54,6 @@ documents). `date` is the file's git creation date: ## Finding documents by ticket The `ticket:` line matches both single-reference and inline-list forms; -`--no-ignore` reaches ignored-mode artifacts: -`rg -l --no-ignore '^ticket:.*ABC-123' docs/ .superpowers/` +`--no-ignore` reaches ignored-mode artifacts, and the tolerant leading +anchor finds the field where a second writer relocated it: +`rg -l --no-ignore --crlf '^\s*ticket:.*ABC-123' docs/ .superpowers/` From d8d3d5ee5884092447db37e771ea57e24a38d24f Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 11:56:47 +0200 Subject: [PATCH 016/126] feat(working-process): offer a code review after implementation --- plugins/working-process/README.md | 2 +- plugins/working-process/rules/workflow.md | 10 ++++++++++ .../working-process/skills/grilling-session/SKILL.md | 8 +++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index 137fbac..92ebc0c 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -4,7 +4,7 @@ Tech-agnostic tooling for a spec-driven working process on top of the `superpowers` plugin: idea → brainstorming (spec) → grilling-session → architect review → -writing-plans (plan) → plan-adversary → implementation. +writing-plans (plan) → plan-adversary → implementation → code review. ## Components diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 2a3cf05..f9b0b99 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -39,6 +39,16 @@ disables its suggestion — never the work itself. 6. **Implementation.** Test-driven when superpowers:test-driven-development is available; bugs go through superpowers:systematic-debugging when available. +7. **Implementation → code review.** When a `*-code-review` skill is + installed for a domain the change touches, offer a review of the + work's diff — once implementation is complete and before the plan's + `status` moves to `implemented`, so a finding can still become work. + Domains are judged as the plan-adversary judges them: from the change + itself and the repo's own markers. Several domains touched mean one + run per domain; orchestrating them into a single run is not this + step. The step re-specifies no mechanics — the offer routes to + whatever review surface the matched plugin ships, and that surface + owns scope resolution, dispatch, and the report. Model selection for these dispatches: always name the model explicitly — an omitted model inherits the session's model, defeating the heuristic diff --git a/plugins/working-process/skills/grilling-session/SKILL.md b/plugins/working-process/skills/grilling-session/SKILL.md index 0847ae8..37a76fc 100644 --- a/plugins/working-process/skills/grilling-session/SKILL.md +++ b/plugins/working-process/skills/grilling-session/SKILL.md @@ -7,7 +7,8 @@ description: Grilling session that stress-tests a spec (the primary target), pla idea → brainstorming (spec) → **grilling-session on the spec** → architect review (an `architect` agent dispatch) → writing-plans (plan) → -plan-adversary on the plan → implementation. Offer a grilling once a spec +plan-adversary on the plan → implementation → code review. Offer a +grilling once a spec exists and before its implementation plan is written. Specs are the primary target; plans and raw ideas are in scope too. @@ -51,8 +52,9 @@ applies (edit with the Edit tool): - Session end: replace it with the ISO date (e.g. `grilled: 2026-07-13`) — but ONLY once every decision, glossary update, and document amendment from the session has been applied. -- A session cut short leaves `grilling` in place on purpose: greppable - debt (`rg -l '^grilled: grilling' docs/`). +- A session cut short leaves `grilling` in place on purpose: the + Grilling-pending class of the lifecycle rule's Unfinished-work list, + which publishes the command and which `process-status` runs. ## Grilling mechanics From d178a84d1bcf6162d58a248cb40ee2168c5e4b37 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 12:01:50 +0200 Subject: [PATCH 017/126] feat(working-process): add the process-status skill --- .../skills/process-status/SKILL.md | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 plugins/working-process/skills/process-status/SKILL.md diff --git a/plugins/working-process/skills/process-status/SKILL.md b/plugins/working-process/skills/process-status/SKILL.md new file mode 100644 index 0000000..328c515 --- /dev/null +++ b/plugins/working-process/skills/process-status/SKILL.md @@ -0,0 +1,83 @@ +--- +name: process-status +description: "Report what the working process left unfinished in this repo — a pending grilling, an unresolved verdict, a re-review nobody ran, a stamp in the wrong place. Use when the developer asks what is unfinished, what the process still owes, or for a status pass over docs/specs and docs/plans." +--- + +# process-status — what the process left unfinished + +Runs the Unfinished-work list the lifecycle rule publishes and reports +what it finds. The rule owns which classes exist; this skill owns +nothing but running them, confirming their hits, and reporting. A class +this skill has never heard of works the moment the rule publishes it. + +## Step 1 — read the list + +Read the `## Unfinished-work list` section of +`${CLAUDE_PLUGIN_ROOT}/rules/spec-plan-lifecycle.md` — the payload copy +shipped beside this skill, never an installed copy under +`.claude/rules/`. The plugin releases skill and payload in one version, +so that copy is always in step with this skill. + +Each entry carries three legs: the class name, one command, and the +owner of the next move. Take all three. + +The read fails, and the report says so instead of reporting a clean +repo, when the section is missing or an entry lacks a leg. A run that +could not read the list must never look like a run that found no +unfinished work. + +## Step 2 — run each command + +Run each entry's command exactly as published, from the repository root. +Never rewrite a command, add a path, or drop a flag: a command that +differs from the published one answers a different question. + +## Step 3 — confirm every hit + +A command returns hits. A hit becomes a report line only when its +matching line sits inside the document's frontmatter block: the file's +opening `---` on line 1 and its closing `---`. Read the head of the +file to decide. + +- The line sits inside that block → the hit is real. +- The line sits anywhere else → the document quotes the convention + instead of instantiating it. Reject the hit. +- The file has no opening `---`, or none closing it → treat it as having + no frontmatter block and reject every hit in it. A file whose + frontmatter never closes is broken for every consumer of frontmatter, + so it surfaces on its next touch rather than here. Say so if asked; + never invent a class for it. + +## Step 4 — report + +Group by document, because the developer acts on a document. Under each +document, one line per confirmed hit: the class name, the field where +the class distinguishes fields, and the owner the entry carries. Read +the owner from the entry — never supply one from your own knowledge of +the process. + +Misplaced stamp suppresses per field: it hides the one other class whose +published command would match the relocated line — itself excluded, +since its own command matches every process field. Match semantics are +the mapping, so you never need process knowledge to find it and a class +published later works the same way. Name the field on the line, so the +developer can see which class went quiet. + +Close the report with: + +- the rejected hits — how many, and in which documents — because + over-rejection is the only way confirmation can quietly eat real + unfinished work; +- what was checked: every class name from the list, so a clean run is a + statement and never silence; +- one question, whether to take anything from the list. + +Fire no offer yourself. Each class names its owner, and those owners +have their own gates; a second trigger for one of them belongs to +nobody. + +## Out of scope + +The Project memory store, documents merely in flight (`draft` or +`approved` with no further move), and any criterion this skill invents. +A new class of unfinished work arrives by being published on the list. From 9e9842416422d59007f67bb29df5ae8b7742e58e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 12:06:58 +0200 Subject: [PATCH 018/126] fix(project-memory): state the field's write place and a tolerant read --- plugins/project-memory/README.md | 5 ++-- .../rules/project-memory-conventions.md | 25 ++++++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/plugins/project-memory/README.md b/plugins/project-memory/README.md index 3fdf912..a3e79b4 100644 --- a/plugins/project-memory/README.md +++ b/plugins/project-memory/README.md @@ -23,8 +23,9 @@ The plugin ships two rule files as a Rules payload: Always-on deliberately: index loading has no file path to scope on. - `project-memory-conventions.md` — paths-scoped to the two store directories: note/idea entry shapes, the required H1 and `description` and - the index line projected from them, top-level placement of the plugin's own - frontmatter fields, the tolerance clause for keys other tools wrote, + the index line projected from them, the top-level write place and tolerant + read of the plugin's own frontmatter fields, the tolerance clause for keys + other tools wrote, team-memory scope, the gotcha↔ADR promotion offer, the live-only `MEMORY.md` / on-demand `ARCHIVE.md` layout, and the closure lifecycle. diff --git a/plugins/project-memory/rules/project-memory-conventions.md b/plugins/project-memory/rules/project-memory-conventions.md index 7ec0f55..65f1042 100644 --- a/plugins/project-memory/rules/project-memory-conventions.md +++ b/plugins/project-memory/rules/project-memory-conventions.md @@ -76,10 +76,27 @@ the `description` first, then re-derive the line from them. `MEMORY.md` and lives on the `ARCHIVE.md` Done redirect line, not a live file. Every field this rule defines — `description`, `status`, `spec`, `ticket`, -`adr-candidate` — sits at the top level of the frontmatter, never nested -under a `metadata:` block. Nesting would break the anchored `^ticket:` sweep -the project's ticket convention publishes (when it keeps one), across the -whole project rather than only in the store. +`adr-candidate` — is written at the top level of the frontmatter, which is +where the index projection and a human reader look first. That is a write +place, not an invariant: in a Hybrid store the harness relocates fields +into its own block, and it rewrites the frontmatter of any entry it +touches, so a repair is undone at its next write. + +- A write creates a field the entry lacks at the top level, and updates + a field the entry already carries where it sits. Where two copies + exist, the write takes the top-level one. +- A read accepts the field anywhere inside the frontmatter block, and + where two copies exist the top-level one wins. The read names no block + of the harness — the format is that tool's own moving detail. +- Nothing rewrites an entry solely to move a field, and no surface nags + about a relocated one. A grooming walk the developer asked for is not + nagging, so its standing report of foreign keys stands. +- Never write a duplicate deliberately. `status` changes, and two copies + of a changing value with nobody to reconcile them is a dual-write. + +Any anchored grep over these fields is written `^\s*:` with +`--crlf` from the start, so tolerance is built in rather than retrofitted +after a sweep goes blind. Entries may carry frontmatter that other tools wrote. Leave unknown keys alone: never remove them, never rewrite them, and never let one change an From 9d986a3b7510faf9a2f3172e96d7272d3e12b89b Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 12:11:59 +0200 Subject: [PATCH 019/126] fix(project-memory): read a relocated status in the grooming audit --- plugins/project-memory/skills/memory-review-session/SKILL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/project-memory/skills/memory-review-session/SKILL.md b/plugins/project-memory/skills/memory-review-session/SKILL.md index 23f7172..14e949a 100644 --- a/plugins/project-memory/skills/memory-review-session/SKILL.md +++ b/plugins/project-memory/skills/memory-review-session/SKILL.md @@ -41,7 +41,9 @@ surface the worklist: - frontmatter keys this plugin does not define: report them and move on, never remove them; - `idea-*` files whose `status` is `spec'd` or `dropped` but that still sit as - live bodies; + live bodies — read `status` wherever it sits inside the frontmatter, since + a co-writer may have relocated it, and take the top-level copy where two + exist; - index lines sitting in the wrong section (a section-blind writer — Auto-memory in a Hybrid store — appended them): move the line to its part's proper section; the entry body is untouched; From e05a3bdfdd649125c35bcd33a5171461c4cd3f30 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 12:16:38 +0200 Subject: [PATCH 020/126] docs(working-process): sync identity surfaces and README for process-status --- .claude-plugin/marketplace.json | 2 +- README.md | 2 +- .../working-process/.claude-plugin/plugin.json | 2 +- plugins/working-process/README.md | 17 +++++++++++------ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 8416179..2ce51c5 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ { "name": "working-process", "source": "./plugins/working-process", - "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, plus distributed process rules" + "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, plus distributed process rules" }, { "name": "python-standards", diff --git a/README.md b/README.md index 8bbb2be..76866f5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Marketplace of [Claude Code](https://code.claude.com) plugins by Missing Bits. | Plugin | Docs | Description | |--------|------|-------------| -| `working-process` | [README](plugins/working-process/README.md) | Spec-driven working process: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, two verdict-free consultation agents, distributed process rules | +| `working-process` | [README](plugins/working-process/README.md) | Spec-driven working process: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, two verdict-free consultation agents, distributed process rules | | `python-standards` | [README](plugins/python-standards/README.md) | Python coding standards for uv + ruff + pytest + pyright: area skills, code-review stack, plan-review checklist, distributed toolchain rule | | `salesforce-standards` | [README](plugins/salesforce-standards/README.md) | Salesforce coding standards for the sf CLI toolchain: area skills (Apex, LWC, Flow, data/security model, legacy UI), code-review stack, plan-review checklist, distributed toolchain rule | | `project-memory` | [README](plugins/project-memory/README.md) | In-repo project memory: committed Team memory (`docs/memory/`) and per-user Private memory (`.claude/memory/`), with `memory-review-session`, `migrate-memory`, and `redirect-memory` skills, distributed as a Rules payload | diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index 7768478..c820747 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "working-process", - "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", + "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", "version": "0.14.0-dev.background-verdict-dispatch-3", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index 92ebc0c..a9c30cf 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -45,6 +45,12 @@ writing-plans (plan) → plan-adversary → implementation → code review. come from `*-plan-review` checklist skills. Dispatched in the background, scaled to the plan's size and risk; the verdict arrives as a task notification and is stamped after relay. +- **`process-status` skill** — reports what the process left unfinished + in the current repo: a pending grilling, an unresolved verdict, a + re-review nobody ran, a stamp outside the top level of a frontmatter + block. Runs the Unfinished-work list the lifecycle rule publishes and + fires none of the offers those classes name. Triggers: "what is + unfinished" / "process status". - **`sync-rules` skill** — installs, updates, and uninstalls the rule files shipped by plugins of this marketplace (Rules payloads); see the "Process rules" section. @@ -100,12 +106,11 @@ document body. Concerns later resolved without a fresh round keep the verdict and gain a resolution date — `concerns (resolved 2026-07-16)` — plus a body note saying what resolved them. -Find unfinished work (the anchored match skips resolved concerns): - - rg -l '^grilled: grilling' docs/ - rg -l '^architect: (blocking|concerns)$' docs/ - rg -l '^adversary: (blocking|concerns)$' docs/ - rg -l '^(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/ +Finding unfinished work is one command per class, published as the +`## Unfinished-work list` section of the lifecycle rule — the exact +anchors live there, and the `process-status` skill runs them. The tail +anchors are exact, so a resolved-concern annotation drops out of the +match by design. ## Model selection From 08a118dd05c67e59c0b13ef2df51d701c70b2c5d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 12:20:48 +0200 Subject: [PATCH 021/126] chore(working-process): dogfood version for process-status-riders --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index c820747..ad7e8da 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0-dev.background-verdict-dispatch-3", + "version": "0.14.0-dev.process-status-riders", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From d95a57a1466a95a800a482f154fb56b9e3de6cbc Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 13:10:46 +0200 Subject: [PATCH 022/126] docs: close the process-status riders spec and plan --- docs/domain/glossary.md | 17 + .../plans/2026-08-25-process-status-riders.md | 990 ++++++++++++++++++ ...cess-status-and-anchor-hardening-design.md | 490 +++++++++ 3 files changed, 1497 insertions(+) create mode 100644 docs/plans/2026-08-25-process-status-riders.md create mode 100644 docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 21905dc..4b7d2c1 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -234,6 +234,23 @@ implementation for a plan. Where re-review offers on fallback-recorded verdicts fire. _Avoid_: usage point +**Unfinished-work list**: +The named section of the spec-plan-lifecycle rule holding one entry per +class of unfinished process work — class name, grep command, and the +owner of the next move — and the single definition site for which +classes exist, so a new class costs one edit in the rule and none in +the consumers that run it. A command's output is hits to confirm +against the frontmatter block, never Findings. +_Avoid_: anchor list, debt list + +**Misplaced stamp**: +A process field — `grilled`, `architect`, `adversary`, `*-fallback` — +sitting outside the top level of a document's frontmatter, where the +stamping steps put it. One entry of the Unfinished-work list detects it, +and the value is irrelevant: a misplaced `LGTM` is as malformed as a +misplaced `concerns`. +_Avoid_: malformed stamp, nested field + **Persona**: A role plus its duties, single-sourced in one `*_PERSONA.md` file at the working-process plugin root and adopted by one or more persona surfaces; diff --git a/docs/plans/2026-08-25-process-status-riders.md b/docs/plans/2026-08-25-process-status-riders.md new file mode 100644 index 0000000..b274afe --- /dev/null +++ b/docs/plans/2026-08-25-process-status-riders.md @@ -0,0 +1,990 @@ +--- +ticket: none +date: 2026-08-25 +status: implemented +adversary: concerns (resolved 2026-08-25) +branch: feature/process-status-riders +base: develop +spec: ../specs/2026-08-24-process-status-and-anchor-hardening-design.md +--- + +# Process Status Riders Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Ship the three increments of `docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md` — a `process-status` skill, workflow step 7, and the anchored-sweep hardening — in working-process 0.14.0 plus one project-memory minor. + +**Architecture:** The lifecycle rule gains a named `## Unfinished-work list` section whose entries are triples (class, command, owner); the new skill runs exactly what that section publishes and confirms every hit inside a frontmatter block. The workflow rule gains step 7. The store half rewrites one paragraph of the project-memory conventions rule and adds one audit clause to memory-review-session. Content lands first and the dogfood version bump last, so the plugin cache never serves pre-edit content under the dogfood string. No code — every deliverable is rule text, skill content, manifest fields, or README prose. + +**Tech Stack:** Claude Code plugin content (Markdown rules and skills, YAML frontmatter), `rg`, `claude plugin validate`, git. + +## Global Constraints + +- Public repo: English only, no machine paths, no company names (repo-hygiene rule). +- Commits: one line, conventional prefix `type(scope):`, no body, no trailers (no `Co-Authored-By`). +- Frontmatter safety: any YAML scalar containing `: ` stays double-quoted. `claude plugin validate` does NOT check `rules/` files — review their frontmatter by hand. +- Rule text mentions skills and agents conditionally ("when available") — payload rules load for people without the plugin. +- No version bumps except Task 8. Never force-add ignored files; tracked `docs/` documents ride Task 10's closing commit, not per-task commits. +- `claude plugin validate .`, `claude plugin validate plugins/working-process` and `claude plugin validate plugins/project-memory` must pass before every commit. +- The spec is the contract: wording below is copied from it, and on a conflict the spec wins. +- **Recipe-and-record**: every replacement block below is verbatim shipped text and carries no author annotation, parenthetical, or commentary. A fix applied to shipped text during execution is back-ported into this plan's block in the same fix wave — drift means a re-run reverts the fix. Task 10 diffs every block against the shipped file and STOPs on a mismatch. +- No committed eval files: skills in this repo ship without `evals/trigger-evals.json`. +- The elements-of-style pass on every block below was applied at plan-authoring time. Executors ship the blocks byte-for-byte and never re-style them; a wording improvement is a plan amendment, not an execution-time edit. +- Prescribed tiers for this plan's own review rounds: plan-adversary on the most capable available family (the plan touches two plugins and a published contract other surfaces key on). A round at that tier needs no fallback record. + +--- + +### Task 1: Lifecycle rule — the Unfinished-work list as a named section + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md:56-66` (the placeholder sentence's pointer, and the greppable bullet it replaces) + +**Interfaces:** +- Consumes: nothing. +- Produces: the `## Unfinished-work list` heading and its four entries — the name Task 4's skill keys on, and the commands Task 9 runs. + +- [ ] **Step 1: Write the expected post-edit state to a scratchpad file and run every command against it** + +Write the four commands to a file and run them over `docs/` before touching the rule, so the expected outputs in Step 4 are measured rather than assumed: + +```bash +mkdir -p /tmp/psr && cat > /tmp/psr/commands.txt <<'EOF' +rg -l --no-ignore --crlf '^\s*grilled: grilling' docs/ +rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/ +rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/ +rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback):' docs/ +EOF +while read -r c; do echo "--- $c"; eval "$c" || echo "(no hits)"; done < /tmp/psr/commands.txt +``` + +Expected: command 1 returns `docs/plans/2026-07-13-rules-distribution.md`, the fenced example the confirmation step rejects. Commands 3 and 4 return no hits. + +Command 2 has one conditional extra hit: **this plan itself**, whenever its own `adversary:` field carries a bare `concerns` or `blocking`. That is not a failure of the command — the plan is genuinely an unresolved verdict until the round closes. Expect it while the field is bare, expect it absent once the field reads `LGTM` or carries a resolution annotation, and never edit the field to make a verification step pass. + +- [ ] **Step 2: Re-point the placeholder sentence** + +In `plugins/working-process/rules/spec-plan-lifecycle.md`, replace: + +``` + placeholders (as above) so they never match the grep below. +``` + +with: + +``` + placeholders (as above) so they never match the list below. +``` + +- [ ] **Step 3: Replace the greppable bullet with the named section** + +Delete this bullet: + +``` +- Unfinished process work is greppable: + `rg -l '^grilled: grilling' docs/` and + `rg -l '^(architect|adversary): (blocking|concerns)$' docs/` — the + anchored match deliberately skips resolved-concern annotations. + `rg -l '^(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/` + — pending re-reviews; the waived annotation deliberately defeats the + anchor. +``` + +Insert this section immediately after the bullet list that contained it, before the `Lifecycle offers` paragraph: + +``` +## Unfinished-work list + +One entry per class of unfinished process work: the class name, its +command, and the owner of the next move. This section is the list — a +command published elsewhere, such as the ticket sweep in the +ticket-frontmatter rule, is a lookup and not part of it. The +`process-status` skill, when available, runs exactly what stands here, +and this heading is the name it keys on: the heading and the skill move +together or not at all. + +A command returns hits, not Findings. A hit counts only when the +matching line sits inside the document's frontmatter block — between the +`---` on the file's first line and the `---` that closes it, never a +later pair — because a document quoting this convention in its body +describes it rather than instantiating it. + +- **Grilling pending** — a session's outcomes are recorded and not yet + applied. + `rg -l --no-ignore --crlf '^\s*grilled: grilling' docs/` + Owner: the grilling-session, when available. +- **Unresolved verdict** — a round ended in `concerns` or `blocking` + and nothing closed it. + `rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/` + Owner: a fresh round at the prescribed tier, or the resolution + annotation above. +- **Pending re-review** — a verdict produced below the prescribed tier, + neither refreshed nor waived. + `rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/` + Owner: the re-review offer at the document's consumption gate. +- **Misplaced stamp** — a process field outside the top level of the + frontmatter, at any value. + `rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback):' docs/` + Owner: the developer; no process surface owns moving a stamp back. + The class suppresses per field: it hides the one other class whose + published command would match the relocated line, and no other — + itself excluded, since its own command matches every process field. + Match semantics are the mapping, so a class published later needs no + extra rule. + +The tail anchors are exact on purpose: a `(resolved )`, +`(adjudicated )` or `, waived ` annotation defeats the +match, and that defeat is the recorded closed state. The leading +anchors are tolerant on purpose, so a relocated field is still found. +The Misplaced stamp command anchors `^\s+` instead, because there the +indentation is the defect it looks for rather than an accident to +tolerate. + +## Lifecycle offers +``` + +The trailing `## Lifecycle offers` heading is part of this edit, not decoration: the rule carries no other `##` heading today, so without it the new section would swallow every paragraph that follows it — the offers paragraph, the commit-gate paragraph, and the ticket pointer — and the structural boundary the skill keys on would exist only at the top edge. + +The heading makes the sentence that followed it redundant in its opening, so the same edit re-opens that sentence. Replace: + +``` +Lifecycle offers — each an offer the developer may decline, and each made +``` + +with: + +``` +Each an offer the developer may decline, and each made +``` + +- [ ] **Step 4: Run the four published commands from the shipped rule** + +Extract them from the file rather than retyping, so a typo in the rule is caught rather than reproduced: + +```bash +rg -o --no-filename '`rg -l [^`]+`' plugins/working-process/rules/spec-plan-lifecycle.md | tr -d '`' > /tmp/psr/shipped.txt +diff /tmp/psr/commands.txt /tmp/psr/shipped.txt && echo IDENTICAL +while read -r c; do echo "--- $c"; eval "$c" || echo "(no hits)"; done < /tmp/psr/shipped.txt +``` + +Expected: `IDENTICAL`, then the same outputs as Step 1. The diff is the point — a typo inside a ninety-character regex is exactly what an eyeball comparison of four such lines waves through. + +- [ ] **Step 5: Verify the rule's own YAML frontmatter still parses and no stale pointer remains** + +```bash +head -5 plugins/working-process/rules/spec-plan-lifecycle.md +rg -n 'the grep below|Unfinished process work is greppable' plugins/working-process/rules/spec-plan-lifecycle.md || echo "no stale pointer" +``` + +Expected: the `paths:` block intact; "no stale pointer". + +- [ ] **Step 6: Commit** + +```bash +claude plugin validate plugins/working-process +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): publish the unfinished-work list as a named section" +``` + +--- + +### Task 2: Ticket sweep — tolerant leading anchor + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/working-process/rules/ticket-frontmatter.md:54-58` (the "Finding documents by ticket" section) + +**Interfaces:** +- Consumes: nothing. +- Produces: the tolerant ticket sweep the project-memory conventions rule's prospective clause (Task 5) refers to. + +- [ ] **Step 1: Prove the current sweep goes blind on a relocated field** + +```bash +mkdir -p /tmp/psr/tk && printf -- '---\nname: ""\nmetadata:\n ticket: ABC-123\n---\n\n# Entry\n' > /tmp/psr/tk/nested.md +rg -l --no-ignore '^ticket:.*ABC-123' /tmp/psr/tk/ || echo "old form: no hits" +rg -l --no-ignore --crlf '^\s*ticket:.*ABC-123' /tmp/psr/tk/ || echo "new form: no hits" +``` + +Expected: "old form: no hits"; the new form returns `/tmp/psr/tk/nested.md`. + +- [ ] **Step 2: Replace the sweep** + +Replace: + +``` +The `ticket:` line matches both single-reference and inline-list forms; +`--no-ignore` reaches ignored-mode artifacts: +`rg -l --no-ignore '^ticket:.*ABC-123' docs/ .superpowers/` +``` + +with: + +``` +The `ticket:` line matches both single-reference and inline-list forms; +`--no-ignore` reaches ignored-mode artifacts, and the tolerant leading +anchor finds the field where a second writer relocated it: +`rg -l --no-ignore --crlf '^\s*ticket:.*ABC-123' docs/ .superpowers/` +``` + +- [ ] **Step 3: Run the shipped sweep against a real ticket value** + +```bash +rg -o --no-filename '`rg -l --no-ignore --crlf [^`]+`' plugins/working-process/rules/ticket-frontmatter.md | tr -d '`' +rg -l --no-ignore --crlf '^\s*ticket:.*none' docs/ | head -3 +``` + +Expected: one command printed, matching the block above; the second command returns documents (this repo's specs and plans carry `ticket: none`). + +- [ ] **Step 4: Commit** + +```bash +claude plugin validate plugins/working-process +git add plugins/working-process/rules/ticket-frontmatter.md +git commit -m "fix(working-process): tolerate a relocated field in the ticket sweep" +``` + +--- + +### Task 3: Workflow rule — step 7, and every surface that enumerates the flow + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md:39-41` (after step 6) +- Modify: `plugins/working-process/skills/grilling-session/SKILL.md:8-11` (the "Place in the flow" line) and `:54-55` (a drifted copy of the Grilling-pending command) +- Modify: `plugins/working-process/README.md:6-7` (the flow line under the title) + +**Interfaces:** +- Consumes: nothing. +- Produces: step 7's text; no other task depends on it. + +The three files are the complete set of shipped surfaces enumerating the flow, established by +`rg -n '→ implementation' plugins/` (the other hits are historical documents under `docs/`, which are records and not consumers). + +- [ ] **Step 1: Append step 7 to the workflow rule** + +After step 6 ("**Implementation.** …"), insert: + +``` +7. **Implementation → code review.** When a `*-code-review` skill is + installed for a domain the change touches, offer a review of the + work's diff — once implementation is complete and before the plan's + `status` moves to `implemented`, so a finding can still become work. + Domains are judged as the plan-adversary judges them: from the change + itself and the repo's own markers. Several domains touched mean one + run per domain; orchestrating them into a single run is not this + step. The step re-specifies no mechanics — the offer routes to + whatever review surface the matched plugin ships, and that surface + owns scope resolution, dispatch, and the report. +``` + +- [ ] **Step 2: Extend the grilling-session flow line** + +Replace: + +``` +plan-adversary on the plan → implementation. Offer a grilling once a spec +``` + +with: + +``` +plan-adversary on the plan → implementation → code review. Offer a +grilling once a spec +``` + +- [ ] **Step 3: Extend the plugin README flow line** + +Replace: + +``` +writing-plans (plan) → plan-adversary → implementation. +``` + +with: + +``` +writing-plans (plan) → plan-adversary → implementation → code review. +``` + +- [ ] **Step 4: Replace the drifted command in the grilling-session skill** + +The same file carries a fork of the Grilling-pending command — old form, no tolerant anchor, no flags — which is the fork Task 7 Step 3 removes from the plugin README. Replace: + +``` +- A session cut short leaves `grilling` in place on purpose: greppable + debt (`rg -l '^grilled: grilling' docs/`). +``` + +with: + +``` +- A session cut short leaves `grilling` in place on purpose: the + Grilling-pending class of the lifecycle rule's Unfinished-work list, + which publishes the command and which `process-status` runs. +``` + +- [ ] **Step 5: Verify every flow enumeration moved, and the step numbering is unbroken** + +```bash +rg -n '→ implementation\.' plugins/ || echo "no unextended flow line left" +rg -n '→ code review' plugins/ +rg -n '^[0-9]\. \*\*' plugins/working-process/rules/workflow.md +rg -n "rg -l '\^grilled" plugins/working-process/rules/spec-plan-lifecycle.md plugins/working-process/skills/grilling-session/SKILL.md || echo "no old-form command in this task's files" +``` + +Expected, in order: + +1. "no unextended flow line left". The period is the discriminator: the old lines end `→ implementation.` and the new ones continue `→ implementation → code review.`, so a bare `→ implementation` grep matches the corrected text too and would pass on either state. +2. **Three** hits, not two: the two arrow-notation surfaces, plus `plugins/working-process/rules/workflow.md`, where step 7's own title reads `**Implementation → code review.**`. +3. Steps 1 through 7, in order — this is what verifies the workflow rule's flow, whose enumeration is a numbered list that no arrow grep has ever matched. +4. "no old-form command in this task's files". The sweep is deliberately scoped: `plugins/working-process/README.md:105` still carries the old form at this point, and Task 7 Step 3 owns removing it. A plugins-wide sweep here would fail on a correct run. + +If a check fails, the fix is in the plan, never in the shipped text: an executor must not edit a flow line, a command or a title to satisfy a failing expectation. Report the mismatch and stop. + +- [ ] **Step 6: Validate and commit** + +```bash +claude plugin validate plugins/working-process +git add plugins/working-process/rules/workflow.md plugins/working-process/skills/grilling-session/SKILL.md plugins/working-process/README.md +git commit -m "feat(working-process): offer a code review after implementation" +``` + +--- + +### Task 4: The process-status skill + +Executor: implementer agent. Step 1's block is the final authored output: the `skill-creator` pass and the elements-of-style pass ran at plan-authoring time, so an executor ships the block byte-for-byte rather than re-scaffolding or re-tuning it — a description change is a plan amendment, since Task 10 diffs the block against the shipped file. Ship no `evals/` directory. + +**Files:** +- Create: `plugins/working-process/skills/process-status/SKILL.md` + +**Interfaces:** +- Consumes: the `## Unfinished-work list` heading and entry shape from Task 1. +- Produces: the skill directory name `process-status`, which Task 7's identity surfaces name. + +This task settles the two questions the spec deferred to the plan: an unclosed frontmatter block, and whether a Misplaced stamp line names the field. + +- [ ] **Step 1: Write the skill** + +```markdown +--- +name: process-status +description: "Report what the working process left unfinished in this repo — a pending grilling, an unresolved verdict, a re-review nobody ran, a stamp in the wrong place. Use when the developer asks what is unfinished, what the process still owes, or for a status pass over docs/specs and docs/plans." +--- + +# process-status — what the process left unfinished + +Runs the Unfinished-work list the lifecycle rule publishes and reports +what it finds. The rule owns which classes exist; this skill owns +nothing but running them, confirming their hits, and reporting. A class +this skill has never heard of works the moment the rule publishes it. + +## Step 1 — read the list + +Read the `## Unfinished-work list` section of +`${CLAUDE_PLUGIN_ROOT}/rules/spec-plan-lifecycle.md` — the payload copy +shipped beside this skill, never an installed copy under +`.claude/rules/`. The plugin releases skill and payload in one version, +so that copy is always in step with this skill. + +Each entry carries three legs: the class name, one command, and the +owner of the next move. Take all three. + +The read fails, and the report says so instead of reporting a clean +repo, when the section is missing or an entry lacks a leg. A run that +could not read the list must never look like a run that found no +unfinished work. + +## Step 2 — run each command + +Run each entry's command exactly as published, from the repository root. +Never rewrite a command, add a path, or drop a flag: a command that +differs from the published one answers a different question. + +## Step 3 — confirm every hit + +A command returns hits. A hit becomes a report line only when its +matching line sits inside the document's frontmatter block: the file's +opening `---` on line 1 and its closing `---`. Read the head of the +file to decide. + +- The line sits inside that block → the hit is real. +- The line sits anywhere else → the document quotes the convention + instead of instantiating it. Reject the hit. +- The file has no opening `---`, or none closing it → treat it as having + no frontmatter block and reject every hit in it. A file whose + frontmatter never closes is broken for every consumer of frontmatter, + so it surfaces on its next touch rather than here. Say so if asked; + never invent a class for it. + +## Step 4 — report + +Group by document, because the developer acts on a document. Under each +document, one line per confirmed hit: the class name, the field where +the class distinguishes fields, and the owner the entry carries. Read +the owner from the entry — never supply one from your own knowledge of +the process. + +Misplaced stamp suppresses per field: it hides the one other class whose +published command would match the relocated line — itself excluded, +since its own command matches every process field. Match semantics are +the mapping, so you never need process knowledge to find it and a class +published later works the same way. Name the field on the line, so the +developer can see which class went quiet. + +Close the report with: + +- the rejected hits — how many, and in which documents — because + over-rejection is the only way confirmation can quietly eat real + unfinished work; +- what was checked: every class name from the list, so a clean run is a + statement and never silence; +- one question, whether to take anything from the list. + +Fire no offer yourself. Each class names its owner, and those owners +have their own gates; a second trigger for one of them belongs to +nobody. + +## Out of scope + +The Project memory store, documents merely in flight (`draft` or +`approved` with no further move), and any criterion this skill invents. +A new class of unfinished work arrives by being published on the list. +``` + +- [ ] **Step 2: Validate the plugin and confirm the skill is discoverable** + +```bash +claude plugin validate plugins/working-process +rg -n 'name: process-status' plugins/working-process/skills/process-status/SKILL.md +test ! -d plugins/working-process/skills/process-status/evals && echo "no evals dir" +``` + +Expected: validation passes; the name line prints; "no evals dir". + +- [ ] **Step 3: Verify the description's YAML is safe** + +The double quotes are deliberate and stay whatever the text contains — a later description edit that introduces `: ` would otherwise break the parse silently, and `claude plugin validate` does check skill frontmatter but the failure mode is empty metadata, not an error. Confirm the block parses and both keys survive: + +```bash +python3 -c "import re,sys; t=open('plugins/working-process/skills/process-status/SKILL.md').read().split('---')[1]; import yaml; d=yaml.safe_load(t); print(sorted(d)); print(len(d['description']))" +``` + +Expected: `['description', 'name']` and a non-zero length — a silent parse failure would raise or drop the key. + +- [ ] **Step 4: Commit** + +```bash +git add plugins/working-process/skills/process-status/SKILL.md +git commit -m "feat(working-process): add the process-status skill" +``` + +--- + +### Task 5: Project-memory conventions — write place, tolerant read, no repair + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/project-memory/rules/project-memory-conventions.md:78-82` +- Modify: `plugins/project-memory/README.md:26` (the line summarizing what that rule covers) + +**Interfaces:** +- Consumes: Task 2's tolerant sweep, which the prospective clause generalizes. +- Produces: the read rule Task 6's audit clause relies on. + +- [ ] **Step 1: Replace the paragraph** + +Replace: + +``` +Every field this rule defines — `description`, `status`, `spec`, `ticket`, +`adr-candidate` — sits at the top level of the frontmatter, never nested +under a `metadata:` block. Nesting would break the anchored `^ticket:` sweep +the project's ticket convention publishes (when it keeps one), across the +whole project rather than only in the store. +``` + +with: + +``` +Every field this rule defines — `description`, `status`, `spec`, `ticket`, +`adr-candidate` — is written at the top level of the frontmatter, which is +where the index projection and a human reader look first. That is a write +place, not an invariant: in a Hybrid store the harness relocates fields +into its own block, and it rewrites the frontmatter of any entry it +touches, so a repair is undone at its next write. + +- A write creates a field the entry lacks at the top level, and updates + a field the entry already carries where it sits. Where two copies + exist, the write takes the top-level one. +- A read accepts the field anywhere inside the frontmatter block, and + where two copies exist the top-level one wins. The read names no block + of the harness — the format is that tool's own moving detail. +- Nothing rewrites an entry solely to move a field, and no surface nags + about a relocated one. A grooming walk the developer asked for is not + nagging, so its standing report of foreign keys stands. +- Never write a duplicate deliberately. `status` changes, and two copies + of a changing value with nobody to reconcile them is a dual-write. + +Any anchored grep over these fields is written `^\s*:` with +`--crlf` from the start, so tolerance is built in rather than retrofitted +after a sweep goes blind. +``` + +- [ ] **Step 2: Update the plugin README's summary of that rule** + +The README describes the rule's coverage in one clause, and it still names the invariant. Replace: + +``` + the index line projected from them, top-level placement of the plugin's own + frontmatter fields, the tolerance clause for keys other tools wrote, +``` + +with: + +``` + the index line projected from them, the top-level write place and tolerant + read of the plugin's own frontmatter fields, the tolerance clause for keys + other tools wrote, +``` + +Both blocks keep the two-space continuation indent the README's list item uses; an exact-match edit fails without it. + +- [ ] **Step 3: Verify the rule's frontmatter and the absence of the old justification** + +```bash +head -6 plugins/project-memory/rules/project-memory-conventions.md +rg -n 'never nested|would break the anchored' plugins/project-memory/rules/project-memory-conventions.md || echo "old justification gone" +rg -n 'sits at the top level' plugins/project-memory/rules/project-memory-conventions.md || echo "invariant phrasing gone" +``` + +Expected: the `paths:` block intact; both "gone" messages. + +- [ ] **Step 4: Verify the README and the rule agree** + +```bash +rg -n 'place, not an invariant' plugins/project-memory/rules/project-memory-conventions.md +rg -n 'write place and tolerant' plugins/project-memory/README.md +rg -n 'top-level placement' plugins/project-memory/README.md || echo "stale summary gone" +``` + +Expected: one hit in the rule, one in the README, then "stale summary gone". The rule is matched on `place, not an invariant` rather than on `write place`, because the prescribed block wraps that phrase across a line break — a line-based grep for `write place` cannot match it there however faithfully the block is transcribed, and rewrapping the shipped text to suit a check is exactly the inversion this plan forbids. + +- [ ] **Step 5: Commit** + +```bash +claude plugin validate plugins/project-memory +git add plugins/project-memory/rules/project-memory-conventions.md plugins/project-memory/README.md +git commit -m "fix(project-memory): state the field's write place and a tolerant read" +``` + +--- + +### Task 6: Grooming audit — read `status` wherever it sits + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/project-memory/skills/memory-review-session/SKILL.md:43-44` + +**Interfaces:** +- Consumes: Task 5's read rule. +- Produces: nothing later tasks depend on; Task 9 exercises it. + +- [ ] **Step 1: Measure the false negative this closes** + +```bash +cd .claude/memory && for f in idea-*.md; do head -20 "$f" | grep -qE '^[[:space:]]+status:' && echo "relocated: $f"; done; cd - >/dev/null +``` + +Expected: a non-empty list — every one of those entries is invisible to the audit's lifecycle check today. + +- [ ] **Step 2: Replace the audit bullet** + +Replace: + +``` +- `idea-*` files whose `status` is `spec'd` or `dropped` but that still sit as + live bodies; +``` + +with: + +``` +- `idea-*` files whose `status` is `spec'd` or `dropped` but that still sit as + live bodies — read `status` wherever it sits inside the frontmatter, since + a co-writer may have relocated it, and take the top-level copy where two + exist; +``` + +- [ ] **Step 3: Verify** + +```bash +rg -n 'read `status` wherever it sits' plugins/project-memory/skills/memory-review-session/SKILL.md +claude plugin validate plugins/project-memory +``` + +Expected: the clause prints; validation passes. + +- [ ] **Step 4: Commit** + +```bash +git add plugins/project-memory/skills/memory-review-session/SKILL.md +git commit -m "fix(project-memory): read a relocated status in the grooming audit" +``` + +--- + +### Task 7: Identity surfaces and the plugin README + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/working-process/.claude-plugin/plugin.json:3` (`description`) +- Modify: `.claude-plugin/marketplace.json:10` (the working-process entry's `description`) +- Modify: `README.md:19` (the working-process table row) +- Modify: `plugins/working-process/README.md:48-50` (component list) and `:103-108` (the duplicated commands) + +**Interfaces:** +- Consumes: the skill name `process-status` from Task 4. +- Produces: nothing later tasks depend on. + +All three identity surfaces enumerate this plugin's skills by name, established by +`rg -n 'sync-rules' plugins/working-process/.claude-plugin/plugin.json .claude-plugin/marketplace.json README.md`, +so a new skill touches all three in one commit (marketplace-sync rule). + +- [ ] **Step 1: Add the skill to the three identity surfaces** + +In `plugins/working-process/.claude-plugin/plugin.json`, replace `grilling-session, architect-session, system-designer-session and sync-rules skills` with `grilling-session, architect-session, system-designer-session, process-status and sync-rules skills`. + +Make the identical substring replacement in `.claude-plugin/marketplace.json` and in the `README.md` table row. + +- [ ] **Step 2: Add the component bullet to the plugin README** + +Before the `sync-rules` bullet, insert: + +``` +- **`process-status` skill** — reports what the process left unfinished + in the current repo: a pending grilling, an unresolved verdict, a + re-review nobody ran, a stamp outside the top level of a frontmatter + block. Runs the Unfinished-work list the lifecycle rule publishes and + fires none of the offers those classes name. Triggers: "what is + unfinished" / "process status". +``` + +- [ ] **Step 3: Replace the README's duplicated commands with a pointer** + +The four commands at `plugins/working-process/README.md:103-108` are a fork of the rule's list and have already drifted — the README splits the verdict sweep into two lines where the rule publishes one. Replace: + +``` +Find unfinished work (the anchored match skips resolved concerns): + + rg -l '^grilled: grilling' docs/ + rg -l '^architect: (blocking|concerns)$' docs/ + rg -l '^adversary: (blocking|concerns)$' docs/ + rg -l '^(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/ +``` + +with: + +``` +Finding unfinished work is one command per class, published as the +`## Unfinished-work list` section of the lifecycle rule — the exact +anchors live there, and the `process-status` skill runs them. The tail +anchors are exact, so a resolved-concern annotation drops out of the +match by design. +``` + +- [ ] **Step 4: Verify all four surfaces agree and the fork is gone** + +```bash +rg -n 'process-status' plugins/working-process/.claude-plugin/plugin.json .claude-plugin/marketplace.json README.md plugins/working-process/README.md +rg -n "rg -l '\^grilled" plugins/ || echo "no old-form command left anywhere" +python3 -c "import json; json.load(open('.claude-plugin/marketplace.json')); json.load(open('plugins/working-process/.claude-plugin/plugin.json')); print('json ok')" +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: `process-status` in all four files; "no old-form command left anywhere" — this is where the plugins-wide sweep becomes true, since Task 1 fixed the rule, Task 3 the skill, and Step 3 above the README; "json ok"; both validations pass. + +- [ ] **Step 5: Commit** + +```bash +git add plugins/working-process/.claude-plugin/plugin.json .claude-plugin/marketplace.json README.md plugins/working-process/README.md +git commit -m "docs(working-process): sync identity surfaces and README for process-status" +``` + +--- + +### Task 8: Dogfood version bump — after all content + +Executor: implementer agent. + +**Files:** +- Modify: `plugins/working-process/.claude-plugin/plugin.json` (`version`) + +**Interfaces:** +- Consumes: every content task above, complete. +- Produces: the version string Task 9's session must observe. + +- [ ] **Step 1: Check the arithmetic against the ecosystem, not just the syntax** + +```bash +git show master:plugins/working-process/.claude-plugin/plugin.json | rg version +rg version plugins/working-process/.claude-plugin/plugin.json +git show master:plugins/project-memory/.claude-plugin/plugin.json | rg version +rg version plugins/project-memory/.claude-plugin/plugin.json +``` + +Expected, as measured on 2026-08-25: master carries working-process `0.12.0` and project-memory `0.3.0`; develop carries `0.14.0-dev.background-verdict-dispatch-3` and `0.4.0`. So `0.14.0` is still the unreleased minor, and a new discriminator on it sorts above the current one (`process-status-riders` > `background-verdict-dispatch-3` by prerelease comparison), which is what makes an update fetch it. + +- [ ] **Step 2: Re-mint the discriminator** + +Replace `"version": "0.14.0-dev.background-verdict-dispatch-3"` with `"version": "0.14.0-dev.process-status-riders"`. + +Leave project-memory's version alone: its content change is dogfooded through `--plugin-dir` in Task 9, and the release PR mints its minor. + +- [ ] **Step 3: Verify and commit** + +```bash +rg version plugins/working-process/.claude-plugin/plugin.json +claude plugin validate plugins/working-process +git add plugins/working-process/.claude-plugin/plugin.json +git commit -m "chore(working-process): dogfood version for process-status-riders" +``` + +--- + +### Task 9: Dogfood verification — developer-driven + +Executor: **the developer**. Every step here mutates installed state or needs a fresh session, so an implementer agent cannot run them. **STOP: do not start this task without the developer's explicit go-ahead.** + +**Files:** none — this task observes. + +**Interfaces:** +- Consumes: Tasks 1-8 committed. +- Produces: the record below, rewritten to state what actually ran if the executed path differs from the prescribed one. + +- [ ] **Step 1: Load the working tree as a plugin in a fresh session** + +Per the recorded dogfood recipe, run a fresh session with `--plugin-dir` pointing at this checkout, so both plugins' working-tree content is live without touching the real install. + +- [ ] **Step 2: Verify the artifact the session actually loaded** + +Check content, not a version string: confirm the loaded lifecycle rule carries the `## Unfinished-work list` heading and that the loaded `process-status` skill exists. A stale cache passes any check that only asks whether the dispatch worked. + +- [ ] **Step 3: Run the skill and check the discriminating observable** + +Ask for the process status. Expected: a report naming all four classes as checked, plus a rejected-hit line naming `docs/plans/2026-07-13-rules-distribution.md` — the fenced example the confirmation step rejects. A report that omits the rejection has skipped confirmation; a report that lists that file as unfinished work has skipped it the other way. + +One entry is expected under Unresolved verdict rather than clean, for as long as this plan's own `adversary:` field carries a bare verdict: this plan. The right response is to close that verdict, never to edit the field so the report looks clean. + +- [ ] **Step 4: Exercise the classes that this repo cannot produce naturally** + +In a scratch copy outside the repo, or in a throwaway file under `docs/` reverted afterwards, create: a document with a bare `adversary: concerns`; a document with `grilled: grilling` relocated under a `metadata:` block beside a top-level `architect: concerns`; and a document quoting a bare verdict in its body. Expected: the first reports as an unresolved verdict; the second reports Misplaced stamp naming `grilled` while still reporting the top-level `architect: concerns`; the third is rejected. + +- [ ] **Step 5: Confirm step 7 offers nothing here, and the audit clause reads a relocated status** + +This work touches plugin content only, so no `*-code-review` skill matches a touched domain and step 7 correctly offers nothing. + +Then the store half, which needs a constructed case for the same reason the `docs/` classes did: every live `idea-*` entry reads `status: parked`, and the audit's worklist fires only on `spec'd` or `dropped`, so a walk that honours Task 6's clause and one that ignores it produce identical output on today's store. In one of the relocated entries from Task 6 Step 1, set the **nested** `status` to `spec'd` without moving the field, run a memory-review-session over Private memory, confirm the audit flags that entry as a closed idea still sitting live, then revert the value. Without this the clause ships with a test that cannot fail. + +- [ ] **Step 6: Exercise step 7's firing path on a real domain project** + +The negative branch above proves only that the step stays silent. The spec's Verification section requires the positive one: in a Python or Salesforce checkout of the developer's own, with this plugin dogfooded, take a change to completion and confirm the offer fires before the plan's `status` would flip, names the matched domain, and hands off to that plugin's own review surface. **This step needs a checkout this repo does not contain.** If the developer prefers to defer it, record the deferral here with its date rather than deleting the step — an unverified firing path is a known gap, not a silent one. + +- [ ] **Step 7: Record what ran** + +Rewrite the steps above to match the executed path where it differed, and note the outcome. + +**Executed 2026-08-25, six of seven steps, by the controller session rather than the developer.** The delivery path was `claude -p --plugin-dir` against this checkout, so no installed state changed and no version re-mint was needed. Outcomes: + +- Steps 1-2: the run loaded the working tree's plugin and named all four classes, Misplaced stamp among them — a class that exists only in this checkout, which is what distinguishes a fresh load from a stale cache. The report stated it had read the payload copy rather than `.claude/rules/`. +- Steps 3-4: on a scratch fixture repo the report was exactly the designed one. The fixture that matters carried a nested `grilled:` beside a top-level `architect: concerns`: the report named Misplaced stamp with its field, said Grilling pending was suppressed **for that field**, and still reported the verdict — per-field precedence, live. Two body-quoted lines were rejected with the reason. On this repo the report came back clean with the one known rejection at `docs/plans/2026-07-13-rules-distribution.md:267`. +- Step 5: step 7 correctly offered nothing — the branch changes twelve files, none a Python or Salesforce artifact, so no `*-code-review` skill matches a touched domain. The store's constructed case fired: one relocated `status` set to `spec'd` without moving the field, and the grooming audit flagged the entry as a closed idea still living, reading the value from its nested position. Reverted afterwards; the co-writer's own `modified:` key was left as it rewrote it. +- Step 6 **executed 2026-08-25**, against a constructed fixture rather than the developer's own project, once a mechanic became clear: step 7 lives in a rule, and rules do not arrive through `--plugin-dir` — they bind a session only when installed. The fixture therefore carried the new `workflow.md` and `spec-plan-lifecycle.md` installed at project level, exactly as sync-rules would place them, plus a real `src/calc.py` and a plan at `status: approved`; python-standards was loaded so a `*-code-review` skill existed. The session named step 7, placed it before the flip to `implemented` and quoted the window, judged the domain from the change and the repo's markers, found `python-code-review` installed, said one domain means one run, added no mechanics of its own, framed it as a declinable offer, and chained to the memory-review offer at the flip. Nothing about step 7 is now unverified. + + Two observations from setting that up, neither a defect in this plan. The rules installed on this host are a prior release and carry no step 7, so a session in this repo would not fire the offer until the release lands — which is the rules-payload delivery lag the plugin already documents. And this repo does hold `.py` and `.cls` files, but they are reference content shipped *inside* the standards plugins; whether a change to one of those counts as touching the Python domain is a question step 7's wording leaves open, and it is worth answering the first time it comes up rather than now. + +The audit run also surfaced a defect nobody planted: `.claude/memory/idea-standards-skills-rework.md` carries `ticket: [#6, #12, #14]`, where `#` after a space opens a comment, so the flow sequence never closes and the whole frontmatter fails to parse. Out of this plan's scope, recorded for the store's next grooming walk. + +If a content fix falls out of this task, apply it and back-port it into the block it came from. Then, before re-verifying, decide which delivery path the re-verification uses. Through `--plugin-dir` (Step 1's path) the working tree is read directly and no version change is needed. Through the plugin cache, the version string is the cache key, so the discriminator must **widen to a fresh value** — `0.14.0-dev.process-status-riders-2`, then `-3` — exactly as the previous topic did; re-running Task 8 Step 2 verbatim writes the same string and delivers nothing. + +--- + +### Task 10: Closing — block-to-shipped diff, lifecycle flips, docs commit + +Executor: implementer agent, except the flips, which need the developer's confirmation that Task 9 passed. + +**Files:** +- Modify: `docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md` (frontmatter `status`) +- Modify: `docs/plans/2026-08-25-process-status-riders.md` (frontmatter `status`) + +**Interfaces:** +- Consumes: Tasks 1-9. +- Produces: the closing commit. + +- [ ] **Step 1: Byte-compare every prescribed block against the shipped tree** + +The Global Constraints promise a diff, so this step runs one. Each fenced block in this plan is prescribed shipped text in one of two directions: a block whose marker line ends `with:`, mentions inserting, or is written as ```markdown must appear **verbatim** in the tree afterwards; a block whose marker ends `replace:` or `delete this bullet:` must be **gone** from it. Marker matching is case-insensitive, and a block the grammar cannot place is reported and fails the step — a classifier that silently drops what it does not recognize reads exactly like a classifier that checked everything. A keyword grep passes on a paraphrase; this does not. + +```bash +python3 - <<'PY' +import pathlib, re, sys +PLAN = pathlib.Path('docs/plans/2026-08-25-process-status-riders.md') +FILES = [ + 'plugins/working-process/rules/spec-plan-lifecycle.md', + 'plugins/working-process/rules/workflow.md', + 'plugins/working-process/rules/ticket-frontmatter.md', + 'plugins/working-process/README.md', + 'plugins/working-process/skills/grilling-session/SKILL.md', + 'plugins/working-process/skills/process-status/SKILL.md', + 'plugins/working-process/.claude-plugin/plugin.json', + '.claude-plugin/marketplace.json', + 'README.md', + 'plugins/project-memory/rules/project-memory-conventions.md', + 'plugins/project-memory/README.md', + 'plugins/project-memory/skills/memory-review-session/SKILL.md', +] +missing_files = [f for f in FILES if not pathlib.Path(f).exists()] +if missing_files: + print("NOT YET CREATED:", missing_files) +blob = "\n".join(pathlib.Path(f).read_text() for f in FILES if pathlib.Path(f).exists()) +lines, marker, i = PLAN.read_text().splitlines(), '', 0 +present, absent, unclassified = [], [], [] +while i < len(lines): + if lines[i].startswith('```'): + lang, body, i = lines[i][3:].strip(), [], i + 1 + while i < len(lines) and not lines[i].startswith('```'): + body.append(lines[i]); i += 1 + block = "\n".join(body) + m = marker.lower() + if lang == 'bash' or not block.strip(): + pass + elif lang == 'markdown' or m.endswith('with:') or 'insert' in m: + present.append(block) + elif m.endswith('replace:') or m.endswith('delete this bullet:'): + absent.append(block) + else: + unclassified.append((marker[:70], block.splitlines()[0][:50])) + elif lines[i].strip(): + marker = lines[i].strip() + i += 1 +EXPECTED = (14, 11) # (present, absent); a plan amendment that adds or drops a + # fenced block updates these in the same wave, like any back-port +missing = [b.splitlines()[0][:70] for b in present if b not in blob] +ghosts = [b.splitlines()[0][:70] for b in absent if b in blob] +counts = (len(present), len(absent)) +print("blocks checked:", counts[0], "present /", counts[1], "absent; expected", EXPECTED) +print("UNCLASSIFIED (a block the grammar could not place):", unclassified or "none") +print("MISSING (prescribed, not shipped):", missing or "none") +print("SURVIVING (should be replaced):", ghosts or "none") +if counts != EXPECTED: + print("COUNT DRIFT: a fenced block was added, dropped, or escaped the grammar") +sys.exit(1 if missing or ghosts or unclassified or counts != EXPECTED else 0) +PY +``` + +Expected: no "NOT YET CREATED" line, 14 present and 11 absent blocks checked against `EXPECTED`, all three lists "none", exit 0. Run before Task 4 the script reports the skill file as not yet created and every unapplied block as missing — that is the mechanism working, not a defect. **STOP on any entry at Task 10**: either the shipped text is wrong and gets fixed, or this plan drifted and the block gets back-ported in the same wave. A re-run of a drifted plan reverts shipped fixes. + +The counts are enforced by the script, not left to a reader comparing printed numbers against prose — a shortfall means a fenced block escaped the grammar, and that is invisible in three "none" lists. One edit remains specified as prose rather than a fenced block and is therefore the only thing outside this check: Task 7 Step 1's identity-surface substring, covered by Task 7 Step 4's `process-status` grep across all four files. + +- [ ] **Step 2: Run the full validation set and the two prose-edit checks** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process && claude plugin validate plugins/project-memory && echo "VALIDATE-OK" +rg -n '^## Lifecycle offers$' plugins/working-process/rules/spec-plan-lifecycle.md +rg -n 'Lifecycle offers — each an offer' plugins/working-process/rules/spec-plan-lifecycle.md || echo "sentence prefix removed" +``` + +Expected: "VALIDATE-OK"; the heading present; "sentence prefix removed". + +- [ ] **Step 3: Confirm the repo's own anchors are clean** + +Extract and run the commands from the shipped rule, without reaching for Task 1's scratch files — the developer-paced Task 9 sits between the two tasks and `/tmp` may have been cleared, which would read as command drift rather than a missing file: + +```bash +rg -o --no-filename '`rg -l [^`]+`' plugins/working-process/rules/spec-plan-lifecycle.md | tr -d '`' > /tmp/psr-close.txt +while read -r c; do echo "--- $c"; eval "$c" || echo "(no hits)"; done < /tmp/psr-close.txt +``` + +Expected: four commands, and the only hit is the known rejected example. The `status` flip in Step 4 has nothing to do with this — no command on the list reads `status`. What must be clean is this plan's `adversary:` field: a bare `concerns` or `blocking` on it is an Unresolved verdict, so before the close it takes either a fresh round or this rule's resolution annotation with its body note. **STOP** if the field is bare. + +- [ ] **Step 4: Flip both documents to `implemented`** + +Set `status: implemented` in the spec and in this plan. The spec already carries `grilled: 2026-08-24` and `architect: LGTM`; this plan carries its own `adversary:` verdict by then. + +- [ ] **Step 5: Commit the documents** + +```bash +git add docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md docs/plans/2026-08-25-process-status-riders.md docs/domain/glossary.md +git commit -m "docs: close the process-status riders spec and plan" +``` + +- [ ] **Step 6: Offer the Project memory review** + +The lifecycle rule's offer at the `implemented` flip: released work-state notes close and resolved entries sweep to the archive. Three entries already closed during the spec's authoring; the remaining candidate is the `initiate` half of the review-driven remediation loop, whose body already points at the shipped step 7. + +## Review rounds + +### 2026-08-25 — plan-adversary, fable 5, blocking (round 1) + +Three Important, six Minor; every finding fixed in this document. The round re-ran the plan's own verification claims and confirmed all seven, adding one the dispatcher had missed: the checkout stands on the topic branch with the spec, this plan and the glossary still uncommitted, which Task 10 Step 5 already covers. + +- **fixed** — [Important] Task 3's verification expected `rg -n '→ implementation' plugins/` to list three files, but the workflow rule enumerates the flow as a numbered list and no arrow grep has ever matched it — so the "complete set of surfaces" claim rested on a grep blind to the file the task edits. The step now verifies the two arrow surfaces by `→ code review`, the workflow rule by its step numbering, and says which is which. +- **fixed** — [Important] `grilling-session/SKILL.md:55` shipped a drifted fork of the Grilling-pending command (old form, no flags), surviving a task that edits the same file while Task 7 removed the identical fork from the plugin README. Task 3 now replaces it with a pointer to the list. +- **fixed** — [Important] the spec's requirement that a run over a Python or Salesforce project demonstrate step 7 firing had no owning task; Task 9 gains that step, with an explicit deferral-with-date option because the checkout is not in this repo. +- **fixed** — [Minor] `project-memory/README.md:26` still summarized the conventions rule as "top-level placement"; Task 5 now updates it, and its prescribed block keeps the list item's two-space continuation indent, without which the exact-match edit would fail. +- **fixed** — [Minor] the new `## Unfinished-work list` was the rule's only H2, so it would swallow every following paragraph; Task 1 now adds a closing `## Lifecycle offers` heading in the same edit. +- **fixed** — [Minor] Task 10 Step 3 claimed the `status` flip clears the anchors, which no command on the list reads; the step now conditions the close on this plan's `adversary:` field and STOPs on a bare verdict. +- **fixed** — [Minor] Task 1 Step 4 compared four ninety-character regexes by eye; it now runs `diff`. +- **fixed** — [Minor] the `skill-creator` instruction in Task 4 collided with the recipe-and-record rule; Step 1's block is now declared the final authored output. +- **fixed** — [Minor] the repo's elements-of-style rule would have an executor re-style the verbatim blocks into Task 10's STOP; Global Constraints now states the pass ran at authoring time. + +### 2026-08-25 — plan-adversary, fable 5, blocking (round 2) + +Four Important, three Minor; every finding fixed. The round confirmed what round 1's fixes had left standing — every old-text block matching byte-for-byte, the identity-surface substring in all three files, Task 8's version arithmetic, Task 10 Step 6's memory claim, PyYAML — and found no unenumerated consumer. Two of the four Important were debris from round 1's own fixes, which is the failure mode this round was dispatched to hunt. + +- **fixed** — [Important] round 1's rewritten flow verification had two false expectations: `→ implementation` is a substring of the corrected `→ implementation → code review`, so it matches either state, and `→ code review` also matches step 7's own title in the workflow rule. The step now greps `→ implementation\.` for the old state, expects three hits for the new one and says which file is the third, and forbids editing shipped text to satisfy a failing check. +- **fixed** — [Important] the same step swept all of `plugins/` for the old-form command while `plugins/working-process/README.md:105` legitimately still carries it until Task 7. The sweep is now scoped to the files this task edits, and the plugins-wide version moved to Task 7 Step 4, where it becomes true. +- **fixed** — [Important] Task 1 Step 1's recorded measurement said commands 2, 3 and 4 return no hits, but stamping this plan's own `adversary: blocking` made command 2 return this plan — a gate colliding with its own record. Task 1 Step 1 and Task 9 Step 3 now name the plan's own frontmatter as the one conditional hit, with the instruction never to edit the field to make a check pass. +- **fixed** — [Important] Global Constraints promised Task 10 diffs every block, while the step ran three keyword greps that pass on a paraphrase. Step 1 now extracts every fenced block from this plan and byte-compares it against the shipped tree in both directions — prescribed text must be present, replaced text must be gone. Verified by running it: all nine old-text blocks are detected verbatim in the tree today. +- **fixed** — [Minor] Task 4 Step 3 asserted the description contains `: `, which it does not; the step now states the quotes are deliberate regardless of content and keeps the parse check. +- **fixed** — [Minor] the rule and the skill defined the frontmatter boundary differently, the rule's wording admitting a later `---` pair mid-body; both now say the block opens on line 1. +- **fixed** — [Minor] suppression required a field-to-class mapping no entry published while the skill was barred from supplying process knowledge; both surfaces now say the mapping is the command's own pattern, which also keeps the future-class promise intact. + +### 2026-08-25 — plan-adversary, fable 5, concerns (round 3) + +One Important, two Minor; every finding fixed. First round below the blocking threshold. The round re-verified the whole round-2 wave against the tree — the flow discriminator, the scoped sweep, the conditional-hit clause, the identity substring, the version arithmetic, every old-text block — and found it sound; the one break was in the new mechanism, in the way this loop keeps breaking things. + +- **fixed** — [Important] the block classifier implemented a narrower marker grammar than the contract it claimed, so three fenced blocks escaped both directions with no branch to report them: the absent side of Task 1 Step 2 (`replace:` lowercase against a case-sensitive test) and — worse — the step 7 text and the README component bullet, whose markers said "insert" in prose the grammar did not match. The plan's headline deliverable was never byte-checked. The grammar is now case-insensitive and accepts any marker mentioning an insert, an unclassified block fails the step loudly, and the expected block counts (13 present, 10 absent) are part of the expectation so a shortfall cannot hide inside three "none" lists. Re-verified after the fix: zero unclassified, all ten absent-kind blocks detected verbatim. +- **fixed** — [Minor] the suppression mapping asserted a uniqueness that fails on a literal reading — `(architect|adversary)-fallback` contains `architect`, and the Misplaced stamp command's own pattern names every process field, admitting a self-suppression reading. Both surfaces now phrase it as match semantics against the relocated line, with this class excluded. +- **fixed** — [Minor] three commit steps (Tasks 1, 2 and 5) omitted the validation the Global Constraints require before every commit; they now run it. + +The dispatcher's own verification of the mechanism read "11 present / 9 absent" as success when it was a three-block shortfall — a count with no baseline proves nothing, which is why the counts are now written into the expectation. + +### 2026-08-25 — plan-adversary, fable 5, concerns (round 4) + +Three Minor, **no Important** — the first round with nothing above that grade. The round re-verified the whole round-3 wave: all 23 classifications direction-checked by hand and by run, no absent block a substring of its replacement, no present block pre-existing, the four commands' live outputs including the conditional hit, the consumer sweeps, the version arithmetic. It also answered the inversion attack: a marker phrased "insert X, then replace:" would misdirect a block, but a misdirected block fails loudly in both directions, so the silent class is only one that lands wrong-direction *and* coincidentally satisfies the inverted check. + +- **fixed** — [Minor] Task 1 Step 3's prose instruction for the sentence prefix was self-contradictory: deleting `Lifecycle offers — ` mechanically yields a lowercase `each an offer`, while the stated result was capitalized, and no check distinguished them. The edit is now a fenced replace/with pair, so the byte-diff owns it — one prose-specified edit remains, and it has its own grep. +- **fixed** — [Minor] the block counts were declared part of the expectation while `sys.exit` ignored them, leaving drift to a reader comparing printed numbers against prose — the same mistake one level up from round 3's. The script now carries `EXPECTED = (14, 11)` and exits non-zero on drift. +- **fixed** — [Minor] the rule block read "hits, not findings" where the spec and the glossary both carry the canonical `Findings`; capitalized, since the Global Constraints make the spec's wording binding. + +Re-verified after this wave: 14 present, 11 absent, zero unclassified, all eleven absent blocks detected verbatim in the tree, no present block already applied. + +### 2026-08-25 — plan-adversary, fable 5, concerns (resolved 2026-08-25) (round 5) + +One Important, two Minor; all fixed. The round was aimed at the dimensions the earlier four spent least on — task ordering, the executor split, and what the dogfood run proves versus claims — since the verification machinery had already had three rounds of attention. It re-verified the classifier, the four commands' live outputs, the records against the plan they describe, every spec deliverable's owning task, and the version arithmetic, and found the ordering windows benign. + +- **fixed** — [Important] Task 9 Step 5's store check was vacuous: every live `idea-*` entry reads `status: parked`, and the audit's worklist fires only on `spec'd` or `dropped`, so a walk honouring Task 6's clause and one ignoring it produce identical output. The clause would have shipped with a test that cannot fail, while the `docs/` classes each had a discriminating observable. The step now constructs the case — set a relocated entry's nested `status` to `spec'd` without moving the field, confirm the audit flags it, revert. +- **fixed** — [Minor] Step 7 pointed at Task 8 Step 2 to "re-mint the discriminator", but that step writes a fixed string, so re-running it delivers nothing through the cache. The step now says the discriminator widens to a fresh value and names which delivery path needs it, `--plugin-dir` needing none. +- **fixed** — [Minor] Task 10 Step 3 reached back to Task 1's scratch file for its diff, across the developer-paced Task 9; it now re-extracts the commands from the shipped rule itself. + +The round also flagged, ungraded and outside its subject, that the spec's round-4 record declared three findings and carried seven: inserting rounds 3 and 4 had split round 2's bullet list and the four orphans landed under round 4. Fixed in the spec, where every record now matches its own tally. + +Asked whether a sixth round would earn its cost, the round answered no: after this wave the remaining risk lives in Task 9's execution rather than in the plan text, and the honest close is a resolution annotation. That answer is why this record carries one. diff --git a/docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md b/docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md new file mode 100644 index 0000000..f7caf27 --- /dev/null +++ b/docs/specs/2026-08-24-process-status-and-anchor-hardening-design.md @@ -0,0 +1,490 @@ +--- +ticket: none +date: 2026-08-24 +status: implemented +grilled: 2026-08-24 +architect: LGTM +branch: feature/process-status-riders +base: develop +--- + +# Process status, the review offer, and anchored-sweep hardening + +Throughout this document *anchor* means a regex anchor — `^` or `$` — +and nothing else. The lifecycle rule's named section of grep commands is +the Unfinished-work list — not every published command belongs to it; a +command's output is a hit until the reader confirms it. + +## Problem + +Three increments ride the working-process 0.14.0 release. Two of them +edit the same list, so one spec decides all three; specing them apart +would fork it. + +**Nobody runs the list.** The lifecycle rule publishes grep commands for +unfinished process work — a pending grilling, a bare `concerns` or +`blocking` verdict, a live fallback record. They answer exactly one +question ("what did the process leave unfinished?"), and today the +developer answers it only by remembering the commands. + +**The flow ends at Implementation.** Both standards plugins ship a +`*-code-review` skill and a review command, yet no step offers the +review. The process reviews plans and specs on its own initiative and +reviews code only when asked. + +**The store's readers assume a top-level field.** In a Hybrid store +Auto-memory relocates this plugin's lifecycle fields into its own +`metadata:` block — observed live on 2026-08-17, and by now routine: +measured on 2026-08-25, 10 of the 20 `idea-*` entries in this repo's +Private memory carry `status` there rather than at the top level, an +even split. The count is the one measurement this document quotes; the +co-writer keeps writing, so later readings will differ and every +argument below rests on the split being substantial, never on the +figure. One consequence is live rather than prospective. The grooming walk's audit +looks for `idea-*` entries whose `status` reads `spec'd` or `dropped` +while their body still lives; a relocated `status` reads to that check +as no `status` at all, so a closed idea slips through it. The published +ticket sweep, by contrast, meets no damage today — it covers `docs/` +and `.superpowers/`, the writer touches `.claude/memory/`, and Team +memory is never a Hybrid store — so there the tolerant form buys +resistance for the next anchored grep rather than a repair. + +## Design + +### The Unfinished-work list is the definition site + +The lifecycle rule owns which classes of unfinished work exist; the +skill runs what the rule publishes. One definition site, so a new class +costs one edit in the rule and none in the consumers that run it. The +pending autonomous-review-loop spec already plans to publish two more +classes (`open` and `held` lines); under this contract it publishes them +and `process-status` reports them with no edit of its own. + +The contract names its own scope: the lifecycle rule's Unfinished-work +list, not every `rg` command the payload contains. The +ticket-frontmatter rule publishes a sweep of its own, and that sweep +answers "which documents belong to this ticket" — a lookup, never +unfinished work. + +The list changes shape to carry the contract: + +- the list becomes a named section of the rule, so its boundary is + structural rather than the reader's judgment. The name binds both + sides and moves only when both move — the pattern the Contract + probe's paths already set; +- each entry becomes a triple — the class name, its one-line command, + and the owner of the next move — instead of a command buried in a + paragraph; +- every command gains `--no-ignore`, so an ignored-mode Process + directory stays visible; the ticket sweep already carries the flag; +- every command gains `--crlf`. An exact tail `$` misses a line ending + `\r\n`, so a bare verdict saved on Windows reads as closed — a silent + clean state the confirmation cannot rescue, because a hit that never + fires never reaches it. The flag changes nothing on LF files, and + this repo has none of the other kind; +- a fourth entry joins them, **Misplaced stamp**: a process field + (`grilled`, `architect`, `adversary`, `*-fallback`) outside the top + level of the frontmatter, at any value. Its owner leg names the + developer, because no process surface owns moving a stamp back — the + same fact the Out-of-scope section states from the other side. An + owner is a mandatory leg, so the honest value goes on the entry + rather than being left for the skill to infer; +- one sentence states what a command returns: hits, not Findings. + +The owner rides the entry because the two promises otherwise collide: +the report names the owner of the next move, and a new class costs one +edit in the rule and none in the skill. Deriving the owner from the +rule's offers paragraph would be exactly the executor judgment this +design removes, and it already fails for Misplaced stamp, which no +offer covers. The entry *names* the owner and nothing more — the skill +still fires no offer, so the owner on the entry never becomes a second +trigger. + +The skill reads the list from the payload copy shipped beside it, +`${CLAUDE_PLUGIN_ROOT}/rules/spec-plan-lifecycle.md`, never from an +installed copy. The plugin releases skill and payload in one version, so +that copy is always in step with the skill, while an installed copy can +only lag. This inverts the Contract probe deliberately: there the +installed copy governs the shape of a report written in the reviewed +project, whereas here the list governs what the skill itself runs. + +### A command finds hits; the skill confirms them + +A command's semantic target is the frontmatter block, which a regex +cannot express — and the gap is not theoretical. Run the list's three +current commands over this repo — Misplaced stamp arrives with this +spec — and exactly one document matches: +`docs/plans/2026-07-13-rules-distribution.md:267`, where the plan quotes +the lifecycle rule's own example frontmatter inside a fenced block. The +plan's real frontmatter carries `status: implemented` and no `grilled:` +field. One hit, and it documents the convention rather than instantiating +it. + +So the skill confirms every hit before reporting it: the matching line +must sit inside the document's frontmatter block, between the opening +`---` and its closing pair. A document with no frontmatter block +therefore yields nothing, however its body reads. The confirmation +carries the precision a command cannot, which is what lets every command +take the tolerant `^\s*` form without paying for it. + +### The uniform shape of an anchored sweep + +Every anchored grep over a frontmatter field is written +`^\s*:`. Where a sweep anchors its tail, the `$` stays exact: +the lifecycle commands rely on it, because an annotation such as +`(resolved 2026-07-16)`, `(adjudicated 2026-08-17)` or `, waived +2026-08-01` defeats the match, and that defeat **is** the recorded +closed state. Softening a tail would reopen every closed document onto +the list. + +One rule replaces a per-surface judgment. The store has a second writer +that nests fields; specs and plans have none, so uniformity buys +resistance there rather than repair — and it costs nothing, because the +frontmatter confirmation already rejects the quoted examples that a +tolerant leading anchor would otherwise catch. + +### Placement in the store: one writer's preference, every reader's tolerance + +Auto-memory rewrites the frontmatter of any entry it touches, so +relocation is not an accident to repair but the standing behaviour of a +co-writer that writes more often than the rules do. Repair is a loop +nobody wins, and ADR 0003 already set the posture for harness-caused +deviation: tolerate it, and count it as format debt rather than a +defect. + +The conventions rule therefore stops asserting an invariant the +environment violates across half the measured entries, and states the +rules that stay true: + +- the rules write a field the entry lacks at the top level, where the + index projection and a human reader look first; +- every reader accepts the field anywhere inside the frontmatter block, + and where two copies exist the top-level one wins. The read names no + block of the harness: ADR 0002 declines to bind that shape, and the + tolerant form already covers any nesting depth; +- no rewrite exists solely to move a field, and an unsolicited report + of one is a nag. A grooming walk the developer asked for is not + unsolicited, so its standing report of the co-writer's keys stands. + +Writing a duplicate deliberately stays out. `status` is the one field of +the set that changes, and two copies of a changing value with nobody to +reconcile them is a dual-write: an idea's graduation would update one +copy and leave the other reading `parked`. Today each entry holds +exactly one copy, because the co-writer relocates rather than copies, +and the read rule is what makes that harmless. + +A write to a field the entry already carries updates it where it sits. +Only a field the entry lacks is created, and it is created at the top +level. Where two copies exist, a write takes the top-level one, which +mirrors the read's precedence rather than inventing a second rule. So no +write produces a second copy and no write moves one, which is what makes +the three rules above readable together: the tolerant read carries the +difference, and the co-writer's block is never restructured and never +the target of a field's creation. Updating a value where it already sits +is not a violation of that — it is the case the rule exists for. +Top-level placement is therefore where fields are created, not a +property of existing entries — the honest statement, since half of them +say otherwise. + +One consequence lands in the grooming walk: its audit reads `status` +wherever it sits inside the frontmatter, so a closed idea with a +relocated field stops slipping through the lifecycle check. + +### process-status — the report + +The skill reads the list, runs each command over the project, confirms +each hit, and reports. + +The report groups by document, because the developer acts on a document +and not on a class of hit. Each line names the class and the owner the +entry carries — the re-review offer rides the consumption gate before +plan-writing, a pending grilling belongs to the grilling-session, and so +on. The skill reads that owner rather than knowing it. + +Misplaced stamp takes precedence per field, not per document: a +misplaced `grilled:` suppresses only the class that reads `grilled`, +while a correctly placed `architect: concerns` in the same document +still reports as unfinished work. Suppression follows the untrustworthy +field and stops there. A document carrying both appears once, with a +line for each — grouping by document already guarantees that. + +A clean repo produces a statement, never silence: the report names what +it checked and found nothing. A silent clean run and a broken run read +alike, and the run that reports nothing is exactly the one the developer +cannot verify. Two consequences follow from the same argument. An empty +or unparseable list is an error the report states outright — a run that +found no list must never read like a run that found no unfinished work. +With the list a named section, "unparseable" is bounded: the section is +missing, or an entry lacks a leg of its triple. And the report shows its rejected hits, counted and +named, because over-rejection is the one way the confirmation — this +design's central mechanism — can quietly eat real unfinished work. + +The report closes with one question — whether to take anything from the +list. The skill fires no offer the lifecycle rule defines; those offers +have an owner and a gate, and a second trigger for one of them would +duplicate the owner. + +Three things stay out of the report: the Project memory store, documents +merely in flight (`draft` or `approved` with no further move), and any +criterion the skill invents. A future class reaches the report by being +published on the list, never by being taught to the skill. + +### Step 7 — implementation to code review + +The flow gains a step: when a `*-code-review` skill is installed for a +domain the change touches, offer a review of the work's diff. The offer +fires once implementation is complete and before the plan's `status` +moves to `implemented`. Findings can mean more work, so the review +precedes the flip that declares the work finished; the memory-review +offer stays at the flip, where it belongs. + +Skill discovery mirrors the `*-plan-review` convention the +plan-adversary already uses: match installed skills by name, for the +domains the change touches. No match, no offer — the rule's standing +ethos already says that a tool which is absent disables its own +suggestion. + +The step re-specifies no mechanics, and it makes no assumption about +which surface carries them: the offer routes to whatever review surface +the matched plugin ships. Today both standards plugins pair the skill +with a command, and the step keys on the skill because that is the name +the discovery convention matches; a future plugin shipping the skill +alone still gets the offer, and its own surface decides how the run +happens. + +The domain plugin owns those mechanics: its +review command resolves the scope, runs the pre-dispatch first-create +check, dispatches in the background, and writes one Review report under +the review-reports contract. Where a change touches several domains, +each domain gets its own run; the step says so, so nobody invents a +mixed run here. Orchestrating domains into one run is the parked review +orchestrator, not this step. + +The offer does not join the lifecycle rule's offer list. That list is +keyed to a document's state and fields; a code review is keyed to code. +The workflow rule loads in every session, so step 7 fires on its own, +and a second statement would buy the list's completeness at the price of +a second source of truth. + +## Changes by file + +- `plugins/working-process/skills/process-status/SKILL.md` — new skill: + the contract, the confirmation step, the report shape. +- `plugins/working-process/rules/spec-plan-lifecycle.md` — the + Unfinished-work list as a named section whose entries are triples, + `^\s*`, `--no-ignore` and `--crlf` on each command, the Misplaced + stamp entry and its per-field precedence, the hits-not-Findings + sentence. +- `plugins/working-process/rules/workflow.md` — step 7. +- `plugins/working-process/rules/ticket-frontmatter.md` — `^\s*ticket:` + in "Finding documents by ticket". +- `plugins/project-memory/rules/project-memory-conventions.md` — the + top-level requirement becomes a write place plus a tolerant read with + top-level precedence, and the sweep-fragility justification goes with + it; a prospective clause requires `^\s*:` and `--crlf` of any + future anchored grep over store fields. +- `plugins/project-memory/skills/memory-review-session/SKILL.md` — the + opening audit reads `status` wherever it sits inside the frontmatter. +- `plugins/working-process/.claude-plugin/plugin.json`, + `.claude-plugin/marketplace.json`, `README.md`, + `plugins/working-process/README.md` — the new skill in all three + identity surfaces and in the plugin's component list. +- `docs/domain/glossary.md` — **Unfinished-work list** and **Misplaced + stamp**, minted during this spec's grilling session and already + applied. + +Versions: working-process keeps `0.14.0`, the unreleased minor it +already carries, and dogfoods this branch as +`0.14.0-dev.process-status-riders`; the release PR strips the suffix. +project-memory takes a minor in the same release PR: the audit clause +adds behaviour, so a patch would misreport the change. It needs no +dogfood version of its own — the clause is exercised against this +repo's own store, which carries relocated entries in quantity. + +## Out of scope + +- **Orchestrating reviews across domains** — the parked review + orchestrator; step 7 offers one run per domain and no more. +- **The `open` and `held` classes** — they belong to the + autonomous-review-loop spec and reach the report through the same + published list, with no edit to this skill. +- **Repairing a Misplaced stamp in `docs/`** — detection is what this + spec buys, and the repair has no owner yet: the parked second-writer + detector was scoped to the store, where this spec declines repair + outright, so that entry closes or narrows with this work rather than + standing as the docs-side owner. +- **Softening any tail anchor** — stated as a decision, not an + omission. +- **Frontmatter hygiene beyond process fields** — a nested `ticket`, + `date`, `status`, `branch` or `base` suppresses no class, so the list + stays silent about it. `status` is named deliberately: its + misplacement would mislead the lifecycle more than the others, and it + is still not unfinished work, because no command on the list reads it. + +## Verification + +Dogfooding in this repo. + +- All four commands run clean after the confirmation step, and the + report says so by naming what it checked. The single hit — + `docs/plans/2026-07-13-rules-distribution.md:267` — is rejected as + documentation, which exercises the confirmation on the first run + rather than on a constructed case. +- A temporary document with a bare `concerns` verdict, one with a + misplaced `grilled:` beside a correctly placed `architect: concerns`, + and one quoting either form in its body together prove the three + outcomes: reported as unfinished work, reported as a Misplaced stamp + with the neighbouring verdict still reported, and rejected. +- Step 7 is exercised by this work itself: the change touches plugin + content only, so no `*-code-review` skill matches a touched domain and + the step correctly offers nothing. A run over a Python or Salesforce + project demonstrates the offer firing. +- The audit clause runs against this repo's Private memory, where the + relocated entries are counted in the Problem section: every entry's + lifecycle state is read, and no entry is rewritten to move the field + back. +- The recorded scope of the parked hardening idea said "exactly one + regex". This spec widens it to four commands plus a new class, and the + memory entry closes with a pointer here rather than drifting. + +## Consultations + +Consultations return no verdict and stamp nothing; they are recorded +here for the trail, separately from the rounds below. + +### 2026-08-25 — system designer, fable 5 + +Read the design as parts and contracts and raised ten gaps: the +class-to-owner mapping sitting in the skill rather than on the entry, +the list's boundary having no structural marker, undefined behaviour on +an empty list, four confirmation edge cases (a hit that no longer +reproduces, an unclosed frontmatter block, a duplicate stamp in `docs/`, +CRLF line endings), two holes in the store's write semantics, and a +report that shows no rejections. + +### 2026-08-25 — architect, fable 5 + +Judged the same ten for fit, briefed unattributed so neither +consultation carried the other's authority. Seven landed in this +document: the entry triple, the named section, the empty-list error, +`--crlf`, the "never touched" rewording, the top-level copy on a write, +and the rejected-hit line. Two went to the plan as implementation +detail: the unclosed-block parse rule (this document's existing +decisions already forbid a fifth class, so no new sentence is needed) +and naming the field on a Misplaced stamp line. Three were declined — +a drift warning in the report (the drift hook owns that signal, and the +skill re-reading the installed copy's state would undercut the settled +inversion), a clause for a hit that no longer reproduces (the +confirmation reads the file at confirmation time, and the only +co-writer writes to a store this report excludes), and suspending +Misplaced stamp's suppression when a top-level copy exists (suppression +follows the untrustworthy field; the document still appears under its +Misplaced stamp line, and the proposal would import the store's +top-level-wins read into `docs/`, where no tolerant read is +established). + +## Review rounds + +### 2026-08-24 — architect, fable 5, LGTM (round 1) + +Three Minor findings, all wording-level, all fixed in this document: + +- the measured claim counted four commands where the rule publishes + three today — the fourth arrives with this spec; +- the Problem section's "goes blind" overstated the live breakage: the + published ticket sweep covers `docs/` and `.superpowers/`, the second + writer touches `.claude/memory/`, and Team memory is never a Hybrid + store, so no published command and the observed nesting intersect + today; +- "surface" carried a third, unqualified sense against the glossary's + reservation of the short form — now "consumer" and "owner". + +#### Amendment after the round — 2026-08-25 + +The developer reopened the store half of the hardening, and the +amendment postdates the verdict above, which therefore does not cover +it. A fresh round is dispatched. + +The design previously kept top-level placement as an invariant and +implied that the grooming walk restores a relocated field. Two facts +killed that: the walk does no such thing today — its audit reports +foreign keys and moves on — and Auto-memory rewrites the frontmatter of +any entry it touches, so a repair is undone at the co-writer's next +write. Measurement settled the direction: half the `idea-*` entries +already carry a relocated `status`, and the audit's lifecycle check goes +blind on every one of them. The rule now states a write place plus a +tolerant read, declines repair outright per ADR 0003's posture, and +bars a deliberate duplicate because `status` changes. The audit gains +one clause so the live false negative closes. + +### 2026-08-25 — architect, fable 5, concerns (round 2) + +One Important, four Minor. The round verified the amendment's factual +basis independently, including the minor-bump claim against the +versioning rule. + +- **resolved 2026-08-25** — [Important] the write place, the duplicate + bar and "nothing repairs" gave no consistent reading for the one + operation the amendment exists for: writing `status` on an entry that + already carries it in the co-writer's block. The developer decided + update-in-place — a field the entry carries is updated where it sits, + only a missing field is created, and creation goes to the top level. + The substance lives in the placement section; this line does not + repeat it. +- **fixed** — [Minor] the measured count read "11 of 20" and the store + holds 10 of 20, an even split rather than a majority; recounted, and + the number now appears once, dated, with the other places referring + to it. +- **fixed** — [Minor] the Out-of-scope bullet named the parked + second-writer detector as the owner of a repair this spec declines; + re-scoped to the `docs/` case, with the store's refusal pointing at + the placement section. +- **fixed** — [Minor] "either placement" now reads as any placement + inside the frontmatter block, naming no block of the harness — ADR + 0002 declines to bind that shape. +- **fixed** — [Minor] "nothing nags" is scoped to unsolicited reports; + a grooming walk the developer asked for is not a nag, and its + standing report of foreign keys is intended. + +### 2026-08-25 — architect, fable 5, concerns (round 3) + +Dispatched on the spec as the seven consultation-driven amendments left +it. One Important, one Minor, both fixed the same day; the round found +no fault in the store half and confirmed `--crlf`'s behaviour by test. +The frontmatter verdict carries this round's resolution date — round 2's +annotation read identically, and only these records tell them apart. + +- **fixed** — [Important] the owner leg of the Misplaced stamp entry + was never named, though the design makes the owner mandatory and has + the skill read rather than infer it. The entry now names the + developer, licensed by the Out-of-scope section's own statement that + no surface owns the repair. +- **fixed** — [Minor] "unparseable" covered only a missing section, + while the triple makes a malformed entry possible; the error branch + now names both. + +### 2026-08-25 — architect, fable 5, LGTM (round 4) + +Three Minor findings, no Important, none touching a settled decision. +The round re-ran the published commands, the tolerant forms and an +indented-field probe against this repo, and re-checked the versioning +and glossary claims, before judging. All three findings are fixed; the +verdict predates those fixes, each of which narrows a statement the +round itself flagged. + +- **fixed** — [Minor] the preamble defined the Unfinished-work list as + "the published set of grep commands", which the scope paragraph and + the glossary both contradict — the ticket sweep is published and not + on the list. The preamble now says what the glossary says. +- **fixed** — [Minor] the frontmatter-hygiene bullet enumerated four + non-process fields and omitted `status`, the one whose misplacement + would mislead the lifecycle most; it is now named, with the reason it + still falls outside the list. +- **fixed** — [Minor] step 7 keyed its offer on a skill match while + attributing every mechanic to a command, so the seam held by today's + inventory rather than by contract. The step now states the + assumption: the offer routes to whatever review surface the matched + plugin ships. This was the round's one genuine design point, and the + choice between stating the assumption and accepting the degradation + was made here rather than put to the developer — a small call, open + to reversal. From 0b466695a11049752348c881bc82fa34aadb8424 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 13:18:33 +0200 Subject: [PATCH 023/126] docs(working-process): match Grilling pending citation to its published heading --- docs/plans/2026-08-25-process-status-riders.md | 2 +- plugins/working-process/skills/grilling-session/SKILL.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plans/2026-08-25-process-status-riders.md b/docs/plans/2026-08-25-process-status-riders.md index b274afe..efedc47 100644 --- a/docs/plans/2026-08-25-process-status-riders.md +++ b/docs/plans/2026-08-25-process-status-riders.md @@ -323,7 +323,7 @@ with: ``` - A session cut short leaves `grilling` in place on purpose: the - Grilling-pending class of the lifecycle rule's Unfinished-work list, + Grilling pending class of the lifecycle rule's Unfinished-work list, which publishes the command and which `process-status` runs. ``` diff --git a/plugins/working-process/skills/grilling-session/SKILL.md b/plugins/working-process/skills/grilling-session/SKILL.md index 37a76fc..26a85aa 100644 --- a/plugins/working-process/skills/grilling-session/SKILL.md +++ b/plugins/working-process/skills/grilling-session/SKILL.md @@ -53,7 +53,7 @@ applies (edit with the Edit tool): — but ONLY once every decision, glossary update, and document amendment from the session has been applied. - A session cut short leaves `grilling` in place on purpose: the - Grilling-pending class of the lifecycle rule's Unfinished-work list, + Grilling pending class of the lifecycle rule's Unfinished-work list, which publishes the command and which `process-status` runs. ## Grilling mechanics From 4b79b0ba58a51ee4eacddc98cd1d909c7e223e2f Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 13:19:06 +0200 Subject: [PATCH 024/126] docs: record the developer's go-ahead for the Task 9 executor change --- docs/plans/2026-08-25-process-status-riders.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plans/2026-08-25-process-status-riders.md b/docs/plans/2026-08-25-process-status-riders.md index efedc47..b8a1f2f 100644 --- a/docs/plans/2026-08-25-process-status-riders.md +++ b/docs/plans/2026-08-25-process-status-riders.md @@ -801,7 +801,7 @@ The negative branch above proves only that the step stays silent. The spec's Ver Rewrite the steps above to match the executed path where it differed, and note the outcome. -**Executed 2026-08-25, six of seven steps, by the controller session rather than the developer.** The delivery path was `claude -p --plugin-dir` against this checkout, so no installed state changed and no version re-mint was needed. Outcomes: +**Executed 2026-08-25 by the controller session rather than the developer, on the developer's explicit go-ahead.** The loop stopped at this task and handed it over as the plan requires; the developer then asked the controller to run it, which is what authorizes the departure from the reserved executor. The delivery path was `claude -p --plugin-dir` against this checkout, so no installed state changed and no version re-mint was needed. Outcomes: - Steps 1-2: the run loaded the working tree's plugin and named all four classes, Misplaced stamp among them — a class that exists only in this checkout, which is what distinguishes a fresh load from a stale cache. The report stated it had read the payload copy rather than `.claude/rules/`. - Steps 3-4: on a scratch fixture repo the report was exactly the designed one. The fixture that matters carried a nested `grilled:` beside a top-level `architect: concerns`: the report named Misplaced stamp with its field, said Grilling pending was suppressed **for that field**, and still reported the verdict — per-field precedence, live. Two body-quoted lines were rejected with the reason. On this repo the report came back clean with the one known rejection at `docs/plans/2026-07-13-rules-distribution.md:267`. From c53940866af04cba643757ef094af7960d7f6e40 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 14:11:06 +0200 Subject: [PATCH 025/126] fix(working-process): quote hash-leading ticket values and bound the sweep to one line --- .../working-process/rules/ticket-frontmatter.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/working-process/rules/ticket-frontmatter.md b/plugins/working-process/rules/ticket-frontmatter.md index 30f7582..eebdad4 100644 --- a/plugins/working-process/rules/ticket-frontmatter.md +++ b/plugins/working-process/rules/ticket-frontmatter.md @@ -36,6 +36,15 @@ GitLab, or anything else; the field is always `ticket`. use the inline list form `[ABC-123, ABC-456]` — one greppable line, never a multi-line dash list. No ticket means an explicit `ticket: none`; the field is always present. +- A value that starts with `#` is quoted: `ticket: "#123"`, and + `ticket: ["#6", "#12"]` for several. YAML reads an unquoted `#` after + a space as a comment, and the two forms fail differently — the single + value becomes null with no error, while the list breaks the parse and + takes the whole frontmatter block with it. A Jira key and the + `org/repo#123` form need no quotes, since neither puts `#` after a + space. Earlier documents here quote the whole list instead + (`ticket: "[#6, #7, #8]"`); that parses as a string rather than a + sequence and stays as it is — the sweep below finds it either way. - `date`: the ISO creation date (`2026-07-13`). ## Sourcing and backfill @@ -57,3 +66,9 @@ The `ticket:` line matches both single-reference and inline-list forms; `--no-ignore` reaches ignored-mode artifacts, and the tolerant leading anchor finds the field where a second writer relocated it: `rg -l --no-ignore --crlf '^\s*ticket:.*ABC-123' docs/ .superpowers/` + +The sweep reads the value on the `ticket:` line itself, which bounds it: +a co-writer that reshapes an inline list into a multi-line dash list +moves the values off that line, and no leading anchor recovers them +(observed in a Project-memory store, 2026-08-25). Such an entry is found +by a multi-line `rg -U` or by the store's grooming walk, not here. From 5ac034700599a334f6ca64ee47e9a7548e6acb28 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 25 Aug 2026 14:11:06 +0200 Subject: [PATCH 026/126] fix(project-memory): anchor the adr-candidate grep per the rule's own clause --- plugins/project-memory/rules/project-memory-conventions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/project-memory/rules/project-memory-conventions.md b/plugins/project-memory/rules/project-memory-conventions.md index 65f1042..4abf693 100644 --- a/plugins/project-memory/rules/project-memory-conventions.md +++ b/plugins/project-memory/rules/project-memory-conventions.md @@ -67,7 +67,7 @@ the `description` first, then re-derive the line from them. `MEMORY.md` and registry, exempt from any per-work `ticket` convention the project keeps. It may carry an optional `adr-candidate: yes` frontmatter flag — presence marks a decision-shaped note for later ADR review - (`rg 'adr-candidate:'`); absent means not a candidate. + (`rg --crlf '^\s*adr-candidate:'`); absent means not a candidate. - **idea** (`idea-.md`) — a `parked` idea (a live entry). Frontmatter: `status` (parked → spec'd | dropped), a `spec:` pointer once it graduates, and — when the project links documents to its issue tracker (e.g. the From 8123f77c7d2f5749869c8a0c3db00f740bd2704c Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:20:14 +0200 Subject: [PATCH 027/126] chore(working-process): start review-loop-audits topic, re-mint dev version --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index ad7e8da..3467ff5 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0-dev.process-status-riders", + "version": "0.14.0-dev.review-loop-audits", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From c6ec1a5ee350418a5746939247965d27e5d588e1 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:20:18 +0200 Subject: [PATCH 028/126] docs: review-loop and audit-agents specs, plan and glossary entries --- docs/domain/glossary.md | 24 +- ...2026-08-27-review-loop-and-audit-agents.md | 956 ++++++++++++++++++ ...026-08-17-autonomous-review-loop-design.md | 429 ++++++++ docs/specs/2026-08-27-audit-agents-design.md | 295 ++++++ 4 files changed, 1701 insertions(+), 3 deletions(-) create mode 100644 docs/plans/2026-08-27-review-loop-and-audit-agents.md create mode 100644 docs/specs/2026-08-17-autonomous-review-loop-design.md create mode 100644 docs/specs/2026-08-27-audit-agents-design.md diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 4b7d2c1..080eca6 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -244,9 +244,9 @@ against the frontmatter block, never Findings. _Avoid_: anchor list, debt list **Misplaced stamp**: -A process field — `grilled`, `architect`, `adversary`, `*-fallback` — -sitting outside the top level of a document's frontmatter, where the -stamping steps put it. One entry of the Unfinished-work list detects it, +A process field — `grilled`, `architect`, `adversary`, `*-fallback`, +`integrity` — sitting outside the top level of a document's +frontmatter, where the stamping steps put it. One entry of the Unfinished-work list detects it, and the value is irrelevant: a misplaced `LGTM` is as malformed as a misplaced `concerns`. _Avoid_: malformed stamp, nested field @@ -270,6 +270,24 @@ the repo's own rules means something else, a document location where a statement lives. _Avoid_: mode, channel, entrypoint +**Audit agent**: +An agent whose report ends in no verdict and stamps nothing: it checks a +document and returns material for the dispatcher's disposition — hits +(`propagation-auditor`, the mechanical pass) or defects-with-quotes and +ranked questions (`integrity-auditor`, the judgment pass). Dispatched as +a gate before expensive work — a clean audit is a precondition, never a +judgment on the design. The third dispatch category beside Verdict agent +and Consultation: an audit agent adopts no persona and its output is +never a Contribution. +_Avoid_: sweep agent, verifier + +**Hit**: +The unit a mechanical check returns — an Unfinished-work list command's +match or a propagation-auditor detection: located, binary, confirmed or +dismissed by the dispatcher, never graded. Graded problems are Findings +and belong to review rounds. +_Avoid_: mechanical finding + **Verdict agent**: An agent whose report ends in a verdict the dispatcher stamps into the reviewed document's frontmatter — `architect` and `plan-adversary`. diff --git a/docs/plans/2026-08-27-review-loop-and-audit-agents.md b/docs/plans/2026-08-27-review-loop-and-audit-agents.md new file mode 100644 index 0000000..2e6ddc0 --- /dev/null +++ b/docs/plans/2026-08-27-review-loop-and-audit-agents.md @@ -0,0 +1,956 @@ +--- +ticket: none +date: 2026-08-27 +status: approved +adversary: blocking (adjudicated 2026-08-29) +branch: feature/review-loop-audits +base: develop +spec: [../specs/2026-08-17-autonomous-review-loop-design.md, ../specs/2026-08-27-audit-agents-design.md] +--- + +# Review Loop and Audit Agents Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Ship both grilled-and-reviewed specs — the autonomous review +loop (`architect: concerns (resolved 2026-08-27)`) and the two audit +agents (`architect: LGTM`) — as one working-process release. + +**Architecture:** Two new agents (`propagation-auditor`, +`integrity-auditor`) join the plugin's agent set; the workflow rule's +dispatcher section gains the autonomous loop and the audit offers; the +lifecycle rule gains the disposition-ledger grammar, its Unfinished-work +entry, the `integrity:` field, and the mirrored relay-then-stamp +exception; `ARCHITECT_PERSONA.md` narrows. Both specs' Changes-by-file +sections are the authority — every task below names its spec section, +and the implementer writes rule prose from the spec, never from this +plan's summaries. No code: every deliverable is Markdown rule text, +agent content, or manifest prose. + +**Tech Stack:** Claude Code plugin content (Markdown rules and agents, +YAML frontmatter), `rg`, `claude plugin validate`, git. + +## Global Constraints + +- Public repo: English only, no machine paths, no client names + (repo-hygiene rule). +- Commits: one-line conventional-commit subject, no body, no trailers + (commit-messages rule + the developer's global instruction). +- Frontmatter safety: quote any `description:` containing `: ` — + `claude plugin validate` does NOT check `rules/` frontmatter, so + review rule frontmatter by hand (plugin-authoring rule). +- Both validations pass before every commit: + `claude plugin validate .` and + `claude plugin validate plugins/working-process`. +- Glossary bans bind all shipped text: never `reviewer agent` / + unqualified `review agent`, never `sweep agent`, never `verifier`, + never `retire` as a closure verb; the two agents are **Audit + agents**, their mechanical unit is a **hit** (`docs/domain/glossary.md`). +- Cross-plugin and cross-component mentions in rule text stay + conditional ("when available") — rules load for people without the + plugin (plugin-authoring rule, Rules payload section). +- Version: this topic dogfoods working-process, so it sets + `0.14.0-dev.review-loop-audits` on the plugin (plugin-versioning + rule); the release PR strips the suffix later. Never bump the release + number on the topic branch. +- Executor audit: every task below is runnable by an implementer agent + (file edits, `rg`, `claude plugin validate`, headless `claude -p` + dispatches). The developer steps are the plan-approval status flip + before execution (Task 1 Step 0), the final-gate review (Task 9 + Step 4), and Task 9's three conditional contacts — the mismatch STOP + in Step 1, a contested propagation hit and decision-shaped integrity + defects in Step 3; each carries an explicit STOP. + +--- + +### Task 1: Topic branch and dogfood version + +**Files:** +- Modify: `plugins/working-process/.claude-plugin/plugin.json` (the + `version` field; currently `0.14.0-dev.process-status-riders`) +- Commit (already written, uncommitted at the gate): both specs, this + plan, and `docs/domain/glossary.md` — the grilling's Audit agent and + Hit entries plus the Misplaced-stamp field list gaining `integrity`. + +**Interfaces:** +- Produces: branch `feature/review-loop-audits` off `develop`; version + string `0.14.0-dev.review-loop-audits`; the process documents in the + branch's history, so the rules and agents Tasks 2–8 write never cite + glossary terms absent from the branch. + +- [ ] **Step 0: STOP — approval gate** + +Confirm the plan's frontmatter reads `status: approved` (the +developer's flip) AND that its `adversary:` field reads LGTM or +carries a closing annotation — the pair the Task 9 verdict sweep's +precondition relies on. Either check failing → stop; nothing below +runs. + +- [ ] **Step 1: Create the branch** + +```bash +git checkout develop && git checkout -b feature/review-loop-audits +``` + +- [ ] **Step 2: Set the dogfood discriminator** + +In `plugins/working-process/.claude-plugin/plugin.json` set +`"version": "0.14.0-dev.review-loop-audits"` — same 0.14.0 line (it has +not released), new discriminator per the plugin-versioning rule's +one-channel-one-purpose clause. + +- [ ] **Step 3: Validate** + +Run: `claude plugin validate . && claude plugin validate plugins/working-process` +Expected: both pass. + +- [ ] **Step 4: Commit the version re-mint** + +```bash +git add plugins/working-process/.claude-plugin/plugin.json +git commit -m "chore(working-process): start review-loop-audits topic, re-mint dev version" +``` + +- [ ] **Step 5: Commit the process documents** + +The implementation-ready gate the lifecycle rule names — the plan is +approved and implementation starts now, so the work's `docs/` +artifacts enter the branch. The glossary is not optional here: Tasks +2–8 write rule and agent text citing Audit agent, Hit and the +`integrity` field, and those definitions live only in the working tree +until this commit. + +```bash +git add docs/specs/2026-08-17-autonomous-review-loop-design.md \ + docs/specs/2026-08-27-audit-agents-design.md \ + docs/plans/2026-08-27-review-loop-and-audit-agents.md \ + docs/domain/glossary.md +git commit -m "docs: review-loop and audit-agents specs, plan and glossary entries" +``` + +--- + +### Task 2: `propagation-auditor` agent + +**Files:** +- Create: `plugins/working-process/agents/propagation-auditor.md` +- Read first: `docs/specs/2026-08-27-audit-agents-design.md` + (§The category, §propagation-auditor), `docs/domain/glossary.md` + (Audit agent, Hit, Tier), an existing agent file for frontmatter + shape (`plugins/working-process/agents/plan-adversary.md`). + +**Interfaces:** +- Produces: the agent name `propagation-auditor` (Task 6's offers and + Task 5's grammar cite it); the report contract — opens with a model + self-report (family plus version), then hits each with location and + derivation, or the single line `CLEAN`. + +- [ ] **Step 1: Write the agent file** + +Content requirements, all from spec §propagation-auditor (the spec text +is the authority — write from it, not from this list): + +- Frontmatter: `name: propagation-auditor`; `description:` states the + triggering contract — a mechanical, verdict-free audit gating + expensive dispatches, returning hits, dispatched on the cheapest + available family — quoted (it contains `: `); and + `background: true`, per the spec and like every agent this plugin + ships. +- Role inline (the plan-adversary pattern), no persona file, and a + standing line that the agent adopts no persona and returns no + verdict. +- The seven duties, each phrased domain-neutrally with the marketplace + instantiation beside it, exactly as the spec lists them (interface → + consumer enumeration by parsing; prescribed block vs shipped file; + carrier and consumer chains; counters re-derived; cross-document + identifier diff reported as a spec gap; boundary sentences; + verification simulation). +- Output contract: the opening model self-report, then hits + (location + one-line claim + derivation) or `CLEAN`; hits are never + graded; severity words never appear. +- The glossary duty, so the plugin README's "Every component reads + `docs/domain/glossary.md` and `docs/domain/adr/` first" stays true of + the component set: duties 1 and 5 are where `_Avoid_` bans bite, and + the release's own constraint is that glossary bans bind all shipped + text. An audit agent adopts no persona, so the duty is stated in the + agent body rather than inherited from `PERSONA_COMMON.md`. + +- [ ] **Step 2: Validate and hand-check frontmatter quoting** + +Run: `claude plugin validate plugins/working-process` +Expected: pass. Then visually confirm the `description:` scalar is +quoted. + +- [ ] **Step 3: Commit** + +```bash +git add plugins/working-process/agents/propagation-auditor.md +git commit -m "feat(working-process): add propagation-auditor audit agent" +``` + +--- + +### Task 3: `integrity-auditor` agent + +**Files:** +- Create: `plugins/working-process/agents/integrity-auditor.md` +- Read first: `docs/specs/2026-08-27-audit-agents-design.md` + (§integrity-auditor, §The paired edit), `docs/domain/glossary.md`, + and `plugins/working-process/agents/plan-adversary.md` for + frontmatter shape. + +**Interfaces:** +- Produces: the agent name `integrity-auditor` and the run name + "integrity audit" (Tasks 5–6 cite both); the report contract — opens + with the model self-report, then defects each proved by two quotes, + a separate section of ranked implementer questions, and the coverage + tell (target line count + highest line cited). The agent never + writes the `integrity:` stamp — the dispatcher does. + +- [ ] **Step 1: Write the agent file** + +Content requirements, all from spec §integrity-auditor: + +- Frontmatter: `name: integrity-auditor`; `description:` — the + judgment pass over a churned document on a fresh context, verdict-free, + most capable available tier, primarily a spec before plan-writing — + quoted; and `background: true`, per the spec. +- Role inline; fresh context stated as the mechanism (never inherit + the editing session), with the preconditions: every conversation + edit on disk, and a clean propagation audit when that agent is + available (conditional mention). +- The two lenses verbatim in intent: document-against-itself + (including verifying every rule the document declares about itself, + in both directions) and sufficiency-for-an-implementer (ranked + questions; a good question outranks a weak finding). +- Output contract: self-report, defects-with-two-quotes, ranked + questions, coverage tell. No verdict, no severities, no stamp. +- The glossary duty, stated in the agent body for the same reason as + the propagation-auditor's: an audit agent adopts no persona, so it + inherits nothing from `PERSONA_COMMON.md`, and the plugin README + claims the whole component set reads the glossary first. + +- [ ] **Step 2: Validate and hand-check frontmatter quoting** + +Run: `claude plugin validate plugins/working-process` +Expected: pass. Then visually confirm the `description:` scalar is +quoted — validate does not catch an unquoted `: `. + +- [ ] **Step 3: Commit** + +```bash +git add plugins/working-process/agents/integrity-auditor.md +git commit -m "feat(working-process): add integrity-auditor audit agent" +``` + +--- + +### Task 4: Narrow the architect's card + +**Files:** +- Modify: `plugins/working-process/ARCHITECT_PERSONA.md` (the duties + list; the Fit duty is the "nothing missing, nothing extra" bullet) +- Read first: `docs/specs/2026-08-27-audit-agents-design.md` + (§The paired edit). + +**Interfaces:** +- Produces: the narrowing sentence Task 8's README row summarizes. + +- [ ] **Step 1: Add the narrowing** + +One addition to the duties section, written from the spec: when a +round trips over integrity-class textual defects (contradictions, +counts-versus-lists, reference drift), the architect notes them in one +line and defers to the integrity audit rather than enumerating them. +A conditional clause ("when that agent is available") is the +implementer's call, with the honest rationale: a round may run where +dispatching another agent is impossible — not a shipping requirement; +the persona and the auditor travel in one plugin. + +- [ ] **Step 2: Validate and commit** + +Run: `claude plugin validate plugins/working-process` — pass, then: + +```bash +git add plugins/working-process/ARCHITECT_PERSONA.md +git commit -m "feat(working-process): narrow architect card, integrity class defers to the audit" +``` + +--- + +### Task 5: Lifecycle rule and process-status — grammar, anchors, stamps + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — + five sites: the frontmatter field-set example block, the + resolved-concerns annotation bullet (where `blocking (adjudicated + )` lands), the `## Unfinished-work list` section, the + `## Lifecycle offers` consumption-gate sentence (the backstop for + open `held` lines), and a new disposition-ledger section. NOT the relay-then-stamp sentence in `## Lifecycle + offers` — that + lands in Task 6's pair commit. +- Modify: `plugins/working-process/skills/process-status/SKILL.md` — + the hit-confirmation step (Step 3). +- Read first: the loop spec's lifecycle bullet (the master list), + §The disposition ledger, and its Changes-by-file process-status + bullet; the audit spec's §The stamp. + +**Interfaces:** +- Consumes: agent names from Tasks 2–3 (the `[hit]` variant cites the + propagation-auditor). +- Produces: the canonical grammar Task 6's workflow clauses cite and + Task 9 greps — section `## Review rounds`; heading + `### , , (round N[, ])` + with its two admitted values, `diff-scoped` and `full-document`; + lines `- fixed — [] ; license: ; `, + `- held — [] ; question: `, + `- open — [] `, + `- resolved — [] ; landed in
`, + `- resolved (declined) — [] ; `; + the `[hit]` severity-slot variant; the `, chain accepted ` + heading annotation; the command + `rg -n --no-ignore --crlf '^- (open|held) —' docs/`; the + `integrity:` field definition; and its canonical hash recipe, + `sed '1,/^---$/d' | shasum | cut -c1-7` — a dictated token + like the grammar shapes, so Task 9 Step 1's character-for-character + check covers its absence. + +- [ ] **Step 1: Add the disposition-ledger grammar** + +A new section written from the loop spec's §The disposition ledger: +the four tokens with their semantics and license citation, the +canonical record shapes above (verbatim — they are interface, not +prose), the `[hit]` variant, the `, chain accepted ` annotation +and its writer (the dispatcher, at the gate, on the developer's +decline — its presence defeats the gate's re-ask). + +- [ ] **Step 2: Add the Unfinished-work entry** + +One entry, from the loop spec: class "unfinished review-loop ledger", +the hardened command above, owner text naming both owners (an `open` +line → the document's next touch; a `held` line → the developer), and +the explicit re-scoping sentence: this entry's hits count inside a +`## Review rounds` section, an explicit exception to the list's +frontmatter guard, kept for the same quoting reason. + +- [ ] **Step 3: Add the close forms and gates** + +From the loop spec: `blocking (adjudicated )` beside the +existing annotations (the tail-anchor sentence after the list already +names it — confirm consistency, do not duplicate); the +consumption-gate backstop for open `held` lines including the +spec→plan seam. + +- [ ] **Step 4: Add the `integrity:` field** + +From the audit spec §The stamp: the field joins the frontmatter set — +value `integrity: (sha: )`, the hash produced +by the canonical recipe shipped VERBATIM into this rule as the command +both the stamper and the consumption gate run: +`sed '1,/^---$/d' | shasum | cut -c1-7` (portable — stock macOS +ships no `sha1sum`; the spec records that both tools yield identical +digests). Without the command in the shipped text, two sessions can +digest by different conventions and the gate reports "unaudited" +against a valid stamp. Recomputation owned by the consumption gate (spec-gate semantics; a plan's stamp is +informational and goes stale silently); the Misplaced-stamp detecting +entry's field alternation gains `integrity`. Do NOT touch +the verdict-agent self-report sentence — audit-agent tier verification lives +in the workflow rule (Task 6 Step 3), and attaching round-record +language to verdict-free audits would blur the glossary's +Verdict-agent/Audit-agent boundary. + +- [ ] **Step 5: Extend process-status hit confirmation** + +From the loop spec's process-status bullet: Step 1 of +`skills/process-status/SKILL.md` currently collects three legs per +entry (class, command, owner) — it gains an optional fourth, the +entry's own match scope, read when present; Step 3 then takes that +scope when the entry re-scopes it (the ledger entry's `## Review +rounds` sections); the frontmatter guard stays the default for every +entry publishing no scope of its own. Decide the neighbouring clause +too, rather than leaving it to first use: the skill's +reject-every-hit-in-a-file-without-a-frontmatter-block rule is a +FILE-LEVEL invariant that survives re-scoping — a process document +always has frontmatter, and a file lacking one is not a process +document — so a re-scoped entry narrows where a hit counts, never +whether the file qualifies. + +- [ ] **Step 6: Validate and commit** + +`claude plugin validate plugins/working-process` — pass, then: + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md plugins/working-process/skills/process-status/SKILL.md +git commit -m "feat(working-process): disposition ledger, integrity stamp and ledger-scoped hit confirmation" +``` + +--- + +### Task 6: Workflow rule — the loop, the audit offers, the exception pair + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — three sites: + the numbered flow (the audit offers land around steps 3–5), the + model-selection paragraph ("Reviews are never dispatched on the + cheapest available family"), the verdict-agent + dispatch subsection (`## Dispatching a verdict agent` to the end of + the file, whose one-turn order is the "in one turn and in this + order" bullet) — a range whose closing co-edit clause Step 4 verifies + rather than edits. +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — + ONLY the relay-then-stamp sentence in `## Lifecycle offers`: the pair's + edited-together declaration binds the commit, so both rules' + exception sentences land here, together. +- Read first: BOTH specs' Changes-by-file `workflow.md` bullets — the + loop spec's bullet is the master list for this task; the audit spec's + bullet adds the two offers and the tier sentences. + +**Interfaces:** +- Consumes: agent names from Tasks 2–3; the canonical grammar tokens + and the `integrity:` field semantics from Task 5 (the loop clauses + cite `, chain accepted `, diff-scoped headings, and the + ledger-read recovery — all defined there). +- Produces: the loop's dispatcher clauses and the exact offer sentences + Task 8's README summarizes; the relay-then-stamp exception, in both + rules of the co-edited pair, one commit. + +- [ ] **Step 1: Write the loop into the dispatch subsection** + +From the loop spec's workflow bullet, in the dispatch subsection: the +consent question (once per session, yes / not now / not in this +session), the license test with its held-by-default rule, yield-on-held +and the one-batch shape, the re-dispatch brief duties (diff-scoping +with the forbidden-rest clause, terminators stated up front, the +reviewer's stop signal, invited refutation), the propagation gate +(conditional: "when the propagation-auditor is available") — stated +HERE as the canonical definition, since the dispatcher reads this +subsection at dispatch time, and carrying the FULL dispatch-point set +the audit spec settles, not just the loop's own: before every +verdict-agent dispatch, first rounds included (authoring errors exist +before any repair); after a fix wave, before the next round; and +before an integrity audit. Step 2's flow entry points at this +definition rather than restating it, so Task 9 Step 1 checks one +statement instead of two — the round +cap of three, the all-Minor signal, the oscillation tripwire, +blocking-suspends-autonomy, and relay as the standing veto — plus the +consumption-gate pair offer for a spec whose LGTM came from a +diff-scoped chain (audit or confirming round; auditor absent → the +confirming round alone; decline recorded as `, chain accepted `) +and the plan-side recovery re-offer (a plan whose latest round heading +is a diff-scoped LGTM with no later full-document round is re-offered +its confirming round at the document's next touch). The +relay-then-stamp exception is written in Step 4, not here. + +- [ ] **Step 2: Write the two audit offers** + +From the audit spec's workflow bullet, into the numbered flow: the +integrity audit offered at the consumption gate before plan-writing — +the flow entry names the offer and points at Step 1's definition of +the reshaped pair form and its auditor-absent narrowing, never +restating that scope, exactly as the propagation half does; the +propagation +audit, whose gate the dispatch subsection defines (Step 1) — the flow +entry names the offer and points at that definition rather than +restating its scope, so the rule states the gate once. One propagation +dispatch point lies OUTSIDE the loop and therefore outside that +definition: the authoring-time offer after any multi-site edit. It +lands in the numbered flow as its own clause, since no loop-internal +definition can carry it. Both audits +are background dispatches, so state the sequencing the spec settles: +the gated dispatch waits for its audit's task notification before it +is issued — a sequencing rule, not a blocking call, reusing the relay +machinery the subsection already defines. + +- [ ] **Step 3: Add the audit tier sentences** + +In the model-selection paragraph, from the audit spec: audits are not +reviews — the propagation-auditor dispatches on the cheapest available +family and the integrity-auditor on the most capable available, both +named explicitly; both reports open with a model self-report the +dispatcher compares (dispatched and prescribed rung) before relying on +the result — a mismatched propagation run earns no reliance, a +below-tier integrity run gets no stamp. + +- [ ] **Step 4: Land the relay-then-stamp exception in BOTH rules** + +One edit wave, this task's commit: the exception sentence (a plan's +diff-scoped LGTM relays and writes its round record; only the +frontmatter stamp waits for the confirming full-document round) goes +into the workflow rule's dispatch subsection AND the lifecycle rule's +relay-then-stamp sentence in `## Lifecycle offers`, and the workflow +rule's closing co-edit clause still declares the pair edited together. The +pair's own declaration is why both files share this commit. + +- [ ] **Step 5: Validate and commit** + +`claude plugin validate plugins/working-process` — pass, then: + +```bash +git add plugins/working-process/rules/workflow.md plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): review loop, audit offers and the relay-exception pair" +``` + +--- + +### Task 7: Repo authoring rule — the `*-auditor` naming line + +**Files:** +- Modify: `.claude/rules/plugin-authoring.md` (the naming bullet + listing `*-session`, verdict agents, `*-consult`) + +**Interfaces:** +- Produces: the naming convention Task 8's README row relies on. + +- [ ] **Step 1: Add the line** + +Extend the naming bullet: a verdict-free audit agent returning +material for disposition is named `*-auditor`. + +- [ ] **Step 2: Validate and commit** + +Run: `claude plugin validate .` +Expected: pass — the constraint binds every commit, this one included. + +```bash +git add .claude/rules/plugin-authoring.md +git commit -m "docs: add *-auditor to the component naming conventions" +``` + +--- + +### Task 8: Identity surfaces + +**Files:** +- Modify: `plugins/working-process/README.md` (the agents section — + two new rows after the `plan-adversary` row, the model-selection + paragraph, the "Frontmatter process fields" table, the process-status + row, the architect row, the flow line at the top — the release + inserts the integrity audit before plan-writing and the propagation + audit before verdict dispatches — and the re-sync paragraph — the audit offers + and the `integrity` gate also live in the Rules payload, so they too + await a rules re-sync after a plugin update), the root `README.md` + plugin table row + for working-process (it enumerates the agent set), + `plugins/working-process/.claude-plugin/plugin.json` `description`, + and the `.claude-plugin/marketplace.json` catalog entry — the + marketplace-sync rule binds all identity surfaces in the same + commit, and every one of them enumerates components today. + +**Interfaces:** +- Consumes: agent names and offer sentences from Tasks 2–6, and the + `*-auditor` naming line from Task 7. + +- [ ] **Step 1: README rows and the fields table** + +Two agent rows in the shipped style: what each auditor is, its tier, +its output unit, when the workflow offers it; the model-selection +paragraph gains the audit-tier sentence (cheapest for propagation, +most capable for integrity — audits are not reviews); the +"Frontmatter process fields" table gains an `integrity` row (the +date-plus-body-hash value, dispatcher-written, gate-recomputed); the +process-status row's class enumeration extends to the +unfinished review-loop ledger class and its section-scoped hits; the +architect agent's row gains the narrowing Task 4 ships — +integrity-class defects are noted and deferred, not enumerated. + +- [ ] **Step 2: Sync the other three surfaces** + +Update the root `README.md` working-process row, the plugin.json +`description`, and the catalog entry to the same component +enumeration. Then confirm: + +Run: `rg -n 'audit' plugins/working-process/.claude-plugin/plugin.json .claude-plugin/marketplace.json plugins/working-process/README.md README.md` +Expected: all four surfaces name the two audit agents consistently. + +- [ ] **Step 3: Validate and commit** + +`claude plugin validate .` — pass, then: + +```bash +git add plugins/working-process/README.md README.md plugins/working-process/.claude-plugin/plugin.json .claude-plugin/marketplace.json +git commit -m "docs(working-process): identity surfaces for the audit agents and the integrity field" +``` + +--- + +### Task 9: Closing gate — recipe-and-record diff and sweeps + +**Files:** +- Read: every file Tasks 2–8 touched, against both specs. +- Modify: `docs/specs/2026-08-17-autonomous-review-loop-design.md` + (the integrity dispositions, the `integrity:` stamp, the + audit-outcome note), `docs/specs/2026-08-27-audit-agents-design.md` + (propagation-hit fixes, if any), and any shipped file a + fix-shipped-text resolution touches at Step 1's or item 3's STOP. + +- [ ] **Step 1: Spec-vs-shipped diff (STOP on mismatch)** + +For each Changes-by-file bullet in BOTH specs, confirm the shipped +file carries it; for every interface token this plan dictates +(the grammar shapes, the heading token, the annotation, the command, +the field value shape) confirm the shipped text matches CHARACTER +FOR CHARACTER. Any mismatch: STOP and put the fix-shipped-text-or- +return-to-spec decision to the developer — never reconcile silently. + +- [ ] **Step 2: Mechanical sweeps, output quoted** + +The ban sweep covers exactly the files this release creates or edits — +six pre-existing `reviewer agent`/`code-reviewer agent` hits live in +untouched standards plugins and the review-reports rule, and they are +out of this release's scope: + +```bash +rg -in 'sweep agent|verifier|review agent|reviewer agent|\bretire' \ + plugins/working-process/agents/propagation-auditor.md \ + plugins/working-process/agents/integrity-auditor.md \ + plugins/working-process/rules/workflow.md \ + plugins/working-process/rules/spec-plan-lifecycle.md \ + plugins/working-process/skills/process-status/SKILL.md \ + plugins/working-process/ARCHITECT_PERSONA.md \ + plugins/working-process/README.md README.md \ + plugins/working-process/.claude-plugin/plugin.json \ + .claude-plugin/marketplace.json \ + docs/domain/glossary.md \ + docs/specs/2026-08-17-autonomous-review-loop-design.md \ + docs/specs/2026-08-27-audit-agents-design.md \ + .claude/rules/plugin-authoring.md +rg -n --no-ignore --crlf '^- (open|held) —' docs/ +rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/ +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: exactly four hits, all definitional or mention-position, +verified on the tree at plan time — the glossary's three `_Avoid_` +lines (Audit agent, Verdict agent, Close-an-entry), which are where +the bans are DEFINED and therefore match by construction, plus the +audit spec's Naming section mentioning `sweep-verifier`, the rejected +working name's recorded trail. Quote all four and judge them per the +glossary ban, like the plan's own exclusion; qualified forms (e.g. +"code-review agent" inside a longer name) are judged the same way. A +fifth hit fails the sweep. +This plan file itself stays off the sweep list deliberately: it names +the banned terms in mention position (the Global Constraints list and +these round records). The ledger sweep returns nothing. The verdict +sweep's precondition is this plan's own `adversary:` field being +LGTM or annotation-closed by execution time — the Task 1 Step 0 +approval gate guarantees it — so it too returns nothing; a hit on +this plan here is a STOP, never an expected exception. Validations +pass. + +- [ ] **Step 3: Dogfood both auditors on the bundle's own documents** + +Per the audit spec's Verification section, on the dogfood version. +The session's own agent registry predates these agents, so every +dispatch here runs as a FRESH headless session (developer directive, +2026-08-27) — which also satisfies the integrity-auditor's +fresh-context requirement by construction: + +```bash +claude plugin disable working-process # name-collision guard; see the re-enable rule below +claude -p --plugin-dir plugins/working-process --agent propagation-auditor \ + --model "" +claude -p --plugin-dir plugins/working-process --agent propagation-auditor \ + --model "" +claude -p --plugin-dir plugins/working-process --agent integrity-auditor \ + --model "" +claude plugin enable working-process +``` + +One discipline binds EVERY disable window in this task, so no step +restates it: re-enable the installed plugin and delete any fixture +before pausing at a STOP, on any dispatch failure, and on any unmet +Expected — every exit path restores the developer's live install and +leaves no scratch file behind. + +`--agent` is what distinguishes the agent running from the session +improvising: without it a headless run performs the audit inline, the +self-report still matches and `CLEAN` is still emitted on request, +while the agent's duties, output contract and coverage tell go +unexercised. Before relying on any report, quote one agent-sourced +marker from it — a hit's `location + claim + derivation` triple, or +the integrity report's line-count coverage tell. + +Both `--model` values resolve at dispatch time — the executor names +the family then (the glossary's Tier entry: a rung is never a concrete +model name at authoring time), and an omitted `--model` is forbidden: +it inherits the session default, the exact anti-pattern the shipped +workflow rule names. + +One guard covers the whole sequence: ANY spec edit made anywhere in +Step 3 — item 1's propagation fixes included — un-certifies what it +touched, so before the sequence proceeds it re-runs Step 2's ban-sweep +command UNCHANGED (its file list already carries both specs, so the +four-hit baseline and the Expected hold literally) and Step 1's +spec-vs-shipped diff over the touched sections. + +Sequence, honoring the contract this run demonstrates: + +1. Propagation audit over BOTH specs (cheapest available family, + named at dispatch) — the audit spec's Verification says both, and + a clean line on the loop spec is the integrity audit's own + precondition. Before relying on any report, compare its opening + model self-report against the dispatched and prescribed rung — + a mismatch earns no reliance and re-dispatches. Then dispose of + every hit: a confirmed hit is fixed, a contested one escalates to + the developer as a third conditional STOP (never silently + dismissed, per the audit spec). The terminal condition is NO + CONFIRMED HITS REMAIN on either spec — not the literal `CLEAN` + token, which a dismissed hit would keep out of reach forever. Two + re-dispatches per spec; a third escalates instead of looping. +2. Integrity audit over the loop spec (most capable available, named + at dispatch, fresh headless session). Compare its self-report + before anything else — a below-tier run gets no stamp and is + re-dispatched. Relay the report. Defects return to the dispatcher + for disposition (the audit spec's contract); a decision-shaped + defect is a conditional STOP — re-enable the plugin, the developer + decides, everything else is applied directly. +3. Apply the dispositions, then RE-RUN Step 1's spec-vs-shipped diff + over every spec section the fixes and dispositions touched — the + same character-for-character bar, the same developer STOP on + mismatch; an edit made after certification un-certifies what it + touched. A mismatch resolved by editing the LOOP SPEC re-enters + item 1 for that spec — propagation audit over the edited text to + `CLEAN` — and then item 2, a fresh integrity dispatch, before any + stamp; the integrity audit's propagation precondition holds on + every pass, not only the first. A mismatch resolved by editing the + AUDIT SPEC re-enters item 1 for that spec (propagation to `CLEAN`); + no item-2 re-entry — the integrity target is the loop spec alone. + The developer may + explicitly waive the re-audit at that STOP, the waiver quoted in + the Step 4 relay — and a waiver forfeits BOTH items 4 and 5: no + stamp is written over text no audit read, the forfeiture is named + in the Step 4 relay beside the quoted waiver, and the audit spec's + stamp-and-re-arm verification stays owed, the developer its owner. + A fix-shipped-text resolution proceeds unchanged. The stamp + answers "was this checked after the last edit" and must never + answer it falsely. +4. Stamp `integrity: (sha: )` into the loop + spec — the hash computed by the audit spec's canonical recipe, + `sed '1,/^---$/d' | shasum | cut -c1-7`, the same command + the consumption gate recomputes with. Quote the command and its + output. +5. Observe the re-arm with a real, labeled edit: append the + audit-outcome note to the loop spec's body (one sentence naming + the run, its date, and its disposition count), recompute the body + hash, observe the mismatch against the stamp — and STOP THERE. + The re-armed (stale) stamp is the deliberate final state, named as + such in the Step 4 relay: per the audit spec, a differing hash + means "unaudited, exactly", and writing a fresh stamp over text no + audit read is the false answer this sequence exists to forbid. + Quote the stamped hash and the recomputed hash, so the mismatch is + visible. + +- [ ] **Step 3a: Exercise the changed process-status skill** + +Task 5 changes the skill's own logic (an optional fourth leg in Step 1, +section-scoped confirmation in Step 3); a raw `rg` verifies the +command, not the skill. The run needs its own disable window (the installed copy is enabled +again by the end of Step 3, and the harness resolves a name collision +silently) and a fixture (the ledger sweep returns nothing on a clean +tree, so the changed confirmation branch would never execute): + +```bash +claude plugin disable working-process +# fixture: a throwaway docs/ file WITH a valid frontmatter block (the +# skill rejects every hit in a file without one), carrying one +# `- held — [Important] …; question: …` line inside a +# `## Review rounds` section and one outside any section +claude -p --plugin-dir plugins/working-process "/process-status" +claude plugin enable working-process +``` + +This step produces EVIDENCE, not a pass/fail gate — quote the report +and let the developer read it at the Step 4 STOP. Quote three things: +the in-section line reported as a hit of the unfinished review-loop +ledger class with both owners named; the out-of-section line rejected; +and the two closers the skill's own final step mandates (the +rejected-hit count with its documents, and the explicit +every-class-name-checked statement) — which only the skill can +produce, so they show it ran rather than the session improvising. + +- [ ] **Step 3b: Commit the gate's output** + +The stamp and the audit-outcome note are this release's named +verification deliverable, and the process-artifacts rule forbids +leaving tracked artifacts dirty — so the developer's Step 4 review +starts from a clean tree. + +```bash +git add docs/specs/2026-08-17-autonomous-review-loop-design.md \ + docs/specs/2026-08-27-audit-agents-design.md +git commit -m "docs: dogfood audit results, integrity stamp and re-arm evidence" +``` + +Any shipped file a STOP resolution touched joins this commit (or its +own, with a subject naming the fix). + +- [ ] **Step 4: STOP — developer review** + +Relay the diff results, sweep outputs, and both audit reports to the +developer. Three `status` moves and the release PR stay with the +developer: this plan to `implemented`, and both specs — which ship +their content in this release yet would otherwise stay recorded as +never approved, since process-status excludes in-flight documents and +no grep would ever surface them. + +The loop spec's own Verification — running one full loop iteration +(consent asked once, a background round, licensed self-fixes with +citations, held questions batched, the ledger greppable) — is NOT run +by this plan and is not silently deferred: the loop spec's own +Verification section already carries the deferral (written 2026-08-29, +so it enters the branch with Task 1 Step 5's process-documents +commit), naming the developer as owner and the precondition — +`--plugin-dir` delivers agents but not the Rules payload, and the +loop's dispatcher behavior lives in the rules, so that run needs a +`sync-rules` re-sync first, the obligation the plugin README already +states after any update. The audit spec carries the twin deferral for +the architect narrowing's owed first live test. Neither invents a +ledger token the grammar does not admit. + +## Review rounds + +### 2026-08-27 — plan-adversary, fable 5, blocking (round 1, full-document) + +- fixed — [Important] the section-scoped ledger hits would be structurally rejected by process-status Step 3's hard-coded frontmatter guard, and no task touched that consumer; license: the lifecycle rule's "match semantics are the mapping" clause plus the skill's runs-exactly-what-stands-here promise; the loop spec's Changes-by-file gains the process-status bullet and Task 6 Step 6 carries it +- fixed — [Important] no step wrote the audit spec's two workflow offers and the declared site count enumerated two of three; license: the audit spec's workflow bullet; Task 5 Step 2 writes both offers, the Files list names four sites +- fixed — [Important] the loop spec's plan-side recovery re-offer was routed to no task and no bullet; license: the spec's own round-5 routing precedent; declined to the spec — its workflow bullet gains the re-offer, Task 5 Step 1 carries it +- fixed — [Important] the ban sweep's Expected was unattainable (six pre-existing hits in untouched files); license: the adversary's own simulated run; the sweep scopes to release-touched files with the baseline stated +- fixed — [Important] the root README plugin-table row was missing from Task 8 while the marketplace-sync rule binds it in the same commit; license: the marketplace-sync rule's three-surface clause; Task 8 carries all four surfaces +- fixed — [Important] extending the lifecycle line-53 self-report sentence to audits was routed by neither spec and blurred the Verdict-agent/Audit-agent boundary; license: the audit spec's workflow routing plus the glossary; the extension is dropped, Task 6 Step 5 says so explicitly +- fixed — [Important] no live dispatch of either agent ran and the audit spec's named verification target was rewritten; license: the audit spec's Verification section; Task 9 Step 3 dispatches both auditors on the bundle's own documents, stamps `integrity:` and observes the re-arm +- fixed — [Minor] the literal `CLEAN` token was plan-minted; license: the release's own invented-name ⇒ spec gap rule; the audit spec now records the token +- fixed — [Minor] the Task 4 conditional-clause mandate rested on a false shipping premise; license: the plugin-authoring rule's Rules-payload scope plus the spec's unconditional §paired edit; reworded to an implementer choice with the honest rationale +- fixed — [Minor] the relay-then-stamp exception landed across two commits, violating the pair's edited-together declaration in intermediate history; license: the pair's own clause; Task 6 Step 4 lands both sentences in one commit +- fixed — [Minor] the plugin README's fields table gained no `integrity` row; license: the glossary's Misplaced-stamp enumeration; Task 8 Step 1 adds the row +- fixed — [Minor] the sweep never checked the `retire` closure-verb ban and omitted the Task 7 file; license: the plan's own Global Constraints; the sweep pattern and paths now cover both +- fixed — [Minor] the constraints claimed STOPs no task carried and the mismatch-STOP named no decider; license: the plan's own constraints section; Task 1 Step 0 gates on `status: approved`, Task 9 Step 1 names the developer + +### 2026-08-27 — plan-adversary, fable 5, blocking (round 2, diff-scoped) + +- fixed — [Important] the dogfood integrity audit violated the auditor's own precondition (no propagation audit over the loop spec first; the spec says both specs); license: the audit spec's precondition and Verification sentences; Step 3 runs propagation over both specs to a `CLEAN` line before the integrity dispatch +- fixed — [Important] the re-arm observation was unrunnable as sequenced (dispositions consumed pre-stamp; a verdict-free audit writes no round record to append); license: the audit spec's stamp-after-dispositions order plus the glossary's Audit-agent entry; the trigger is now a labeled audit-outcome body note appended after the stamp +- fixed — [Minor] Step 3's mid-task consent moment contradicted the constraints' two-developer-steps claim and borrowed the loop's triage authority; license: the audit spec's returns-to-the-dispatcher sentence plus the plan's own constraints; the conditional contacts are admitted in the constraints and marked as a STOP in Step 3 +- fixed — [Minor] Task 6 consumed "the exception wording from Task 5" that Task 5 explicitly did not produce; license: the plan's own exclusion sentence; the interface names the real dependency (the grammar tokens and field semantics) +- fixed — [Minor] the workflow commit shipped text citing ledger conventions no rule yet defined; license: round 1's own intermediate-incoherence disposition; the lifecycle task now precedes the workflow task (Tasks 5 and 6 swapped — round-1 disposition pointers name the pre-swap numbering) +- fixed — [Minor] the plugin README's process-status row kept a four-class enumeration while the release adds a fifth class; license: the marketplace-sync rule; Task 8 Step 1 extends the row +- fixed — [Minor] the sweep's coverage claim omitted three files the release edits; license: the plan's own claim sentence; the list carries plugin.json, marketplace.json and the loop spec +- fixed — [Minor] the commit subject named only the lifecycle rule while the commit spanned three files; license: the commit-messages rule; both commit subjects renamed with the swap + +Developer directive folded into this wave (2026-08-27): every Task 9 +Step 3 dispatch runs as a fresh headless `claude -p` session with +`--plugin-dir` on the checkout — the session registry predates the new +agents, and headless freshness satisfies the integrity-auditor's +fresh-context requirement by construction. + +### 2026-08-27 — plan-adversary, fable 5, blocking (round 3, diff-scoped) + +- fixed — [Important] the integrity dispatch omitted `--model` and leaned on an unverified session default, the anti-pattern the release's own workflow text names; license: the shipped workflow rule's omitted-model sentence plus the audit spec's named-tier prescription; both dispatches pass `--model`, resolved at dispatch time +- fixed — [Important] the sequence claimed to honor the demonstrated contract yet compared no self-report before reliance or stamp; license: the audit spec's tier-verification paragraph; explicit compare steps precede both the `CLEAN` reliance and the stamp, re-dispatch on mismatch +- fixed — [Important] Step 3's spec edits followed Step 1's character-for-character certification with no return edge; license: Step 1's own bar; the sequence re-runs the diff over every touched spec section, same STOP +- fixed — [Important] the verdict sweep's Expected failed on this plan's own frontmatter under the exception the release ships; license: the approval-gate design this plan already carries; the precondition is stated and a self-hit is a STOP, never an expected exception +- fixed — [Important] the disable window spanned the conditional STOP and failure paths, leaving the developer's live install off; license: the scratchpad-dogfood recipe's own restore discipline; re-enable precedes every STOP and failure return +- fixed — [Minor] Task 8's Consumes contradicted Task 7's Produces; license: the two lines themselves; Consumes names Task 7's naming line +- fixed — [Minor] the sweep's coverage claim omitted the audit spec and silently excluded this plan file; license: the claim's own sentence; the audit spec joins the list and the mention-position exclusion is stated +- fixed — [Minor] the pinned concrete model id pre-resolved what the glossary resolves at dispatch time; license: the glossary's Tier entry; the code block carries family placeholders resolved by the executor + +### 2026-08-27 — plan-adversary, fable 5, blocking (round 4, diff-scoped) + +- fixed — [Important] the ban sweep's Expected was unattainable on the list member the round-3 wave added (the audit spec's recorded rejected-name trail matches `verifier`); license: the adversary's own simulated run plus the glossary's mention-position practice; the Expected states the one-hit baseline and fails on anything beyond it +- fixed — [Important] a return-to-spec resolution at the re-diff STOP edited the loop spec with text the integrity audit never read, and the stamp followed anyway; license: the audit spec's stamp-after-dispositions semantics ("was this checked after the last edit" must never answer falsely); a loop-spec edit re-enters the integrity dispatch before any stamp, waivable only explicitly with the waiver quoted +- fixed — [Minor] the verdict-sweep precondition cited a gate that never read the `adversary:` field; license: the two plan sentences themselves; Step 0 now confirms both `status: approved` and a closed `adversary:` value + +### 2026-08-27 — plan-adversary, fable 5, blocking (round 5, diff-scoped) + +- fixed — [Important] the re-entry edge skipped the propagation gate the release itself ships before every integrity audit; license: the audit spec's precondition sentence plus this plan's own Task 6 Step 2; a loop-spec edit re-enters item 1 to `CLEAN`, then item 2, on every pass +- fixed — [Important] the waived path flowed into an unconditional stamp whose fresh hash certified text the auditor never read; license: the audit spec's recomputed-hash semantics and its gate-offer machinery; a waiver releases the STOP but skips the stamp — the unstamped spec re-fires the gate's audit offer, the honest record + +### 2026-08-27 — plan-adversary, fable 5, blocking (round 6, full-document) + +- fixed — [Important] item 5's closing re-stamp wrote a fresh hash over the appended note no audit ever read — the defect round 5 blocked on the waiver path, committed on the clean path; license: the audit spec's "a differing hash means unaudited, exactly" plus its Verification mandating only the re-arm observation; item 5 ends at the quoted mismatch, the re-armed stale stamp the deliberate final state named in the Step 4 relay +- fixed — [Important] the waived path's "targets whichever stamped state exists" resolved to nothing runnable and its consumption-gate backstop had already passed; license: the audit spec's named verification and the plan's own sequencing; a waiver forfeits items 4–5 explicitly, the forfeiture named beside the quoted waiver, the verification owed with the developer as owner +- fixed — [Minor] the sweep pattern omitted the unqualified "review agent" ban from the plan's own constraints list; license: the glossary's Verdict-agent entry; the alternation extended, qualified forms judged like the mention-position practice +- fixed — [Minor] spec edits in item 3 followed Step 2's sweeps with no re-entry; license: the plan's own un-certification principle; any spec edit re-runs the ban sweep over the edited files before proceeding + +### 2026-08-27 — plan-adversary, fable 5, concerns (round 7, full-document) + +- fixed — [Important] the round-6 ban-sweep re-run scoped "over the edited files" made its own one-hit Expected unattainable on the typical path (loop-spec-only edits return zero hits); license: Step 1's never-reconcile-silently discipline plus the rounds 1 and 4 precedent for this class; the re-run is the Step 2 command UNCHANGED, whose file list already carries both specs +- fixed — [Minor] the re-entry edge named only the loop spec while item 1 fixes hits on both; license: the audit spec's both-specs Verification plus the plan's un-certification principle; an audit-spec edit re-enters item 1 for that spec, no item-2 re-entry +- fixed — [Minor] the stamp's hash recipe was executor-minted while its consumer is the cross-session consumption gate; license: the release's own invented-name ⇒ spec gap rule (the `CLEAN` precedent); the audit spec now carries the canonical command and item 4 quotes it +- fixed — [Minor] "Quote both recomputations" was a dangling counter left by round 6's truncation; license: the propagation-auditor's own duty 4 class; the instruction names the two hashes it means + +### 2026-08-29 — plan-adversary, opus 5, blocking (round 8, full-document) + +Tier note: the capability ladder changed between rounds — rounds 1–7 ran on a family no longer available, so this round's model is the prescribed tier resolved at dispatch time, not a degradation. No fallback record. + +- fixed — [Important] the canonical hash recipe reached no shipped surface (spec plus a one-off dogfood command only), so stamper and gate in different sessions could digest by different conventions and the gate would report "unaudited" against a valid stamp; license: the recipe's own shared-by-both justification plus the release's invented-name ⇒ spec gap rule; Task 5 Step 4 ships the command verbatim into the lifecycle rule and Task 5's Produces carries it as a dictated token +- fixed — [Important] Task 9 declared itself read-only while Step 3 writes three classes of file, and no step committed its output — the stamp and audit-outcome note, this release's named verification deliverable, never entered the branch; license: the process-artifacts rule's never-leave-them-dirty clause; Task 9 gains a Modify list and Step 3b commits before the developer STOP +- fixed — [Important] `docs/domain/glossary.md` was routed by the audit spec, modified in the working tree since before round 1, carried by no task and swept by no command — the release's rules and agents would cite terms absent from the branch; license: the audit spec's own Changes-by-file bullet plus the verified `git status`; Task 1 Step 5 commits it at the implementation-ready gate and Step 2's sweep list and two-hit baseline cover it +- fixed — [Minor] Task 2's Produces carried the pre-swap Task 5/6 mapping, the sole surviving inversion; license: the tasks' own titles; the references are swapped +- fixed — [Minor] two Produces lines named consumers no step instantiated; license: the steps themselves; Task 1's cache-check clause is dropped (the re-mint stands on the versioning rule the plan already cites) and Task 8 Step 1 gains the architect row so Task 4's Produces is true + +### 2026-08-29 — plan-adversary, opus 5, blocking (round 9, full-document) + +- fixed — [Important] neither auditor's frontmatter decided `background:`, leaving the gate's blocking semantics undefined while pointing the implementer at a `background: true` exemplar; license: the four shipped agents all carrying the field, plus this release's invented-token ⇒ spec gap rule; the audit spec settles both agents at `background: true` and states the gate as a sequencing rule over the notification, and Tasks 2, 3 and 6 carry it +- fixed — [Important] the canonical recipe shipped `sha1sum` into a machine-wide rule, which stock macOS lacks — the gate would error into the false "unaudited" the shared recipe exists to prevent; license: the recipe's own portability purpose; raised to the audit spec as a spec edit, now `shasum`, with the identical-digest equivalence verified across `sha1sum`, `shasum` and `openssl sha1` +- fixed — [Important] the plan's own ledger headings carried a `, full-document` token the canonical grammar never defined, and Task 1 Step 5 commits this plan as the grammar's first exemplar; license: the grammar block's own interface status; the loop spec's shape now admits `diff-scoped` or `full-document`, and all three bundle documents' headings are normalized to it +- fixed — [Minor] item 1's spec edits escaped the un-certification guards scoped to item 3, and item 1 drove only the loop spec to `CLEAN`; license: the plan's own un-certification principle; one guard now covers any spec edit anywhere in Step 3, and item 1 holds one `CLEAN` bar for both specs +- fixed — [Minor] `resolved (declined)` had semantics but no record shape, leaving the implementer to mint one; license: the invented-token ⇒ spec gap rule; the loop spec's grammar block gains the shape +- fixed — [Minor] the ledger entry publishes four legs while process-status Step 1 collects three; license: the skill's own three-legs sentence; Task 5 Step 5 extends Step 1 to read an optional fourth leg before Step 3 consumes it +- fixed — [Minor] Task 3 dropped the by-hand `description:` quoting check Task 2 carries and named no frontmatter exemplar; license: Task 2's own step; both mirrored into Task 3 +- fixed — [Minor] line locators were stale on arrival or went stale mid-task as earlier steps inserted text above them; license: the locators' own drift; every task body now cites content identifiers instead of numbers + +### 2026-08-29 — plan-adversary, opus 5, blocking (round 10, full-document) + +- fixed — [Important] round 9's heading-grammar fix reached the spec and the ledger headings but not Task 5's dictated-token list or the loop spec's own Changes-by-file bullet, so Task 9 Step 1 would certify the superseded grammar; license: the spec's grammar block as interface; both now carry `(round N[, ])` and its two values +- fixed — [Important] the loop spec's own Verification was never run and its deferral was recorded nowhere the unfinished-work machinery could see; license: the spec's Verification section plus this plan's own waiver-path precedent for naming owed work; Step 4 records it as a `held` line with the developer as owner, naming the `sync-rules` precondition (`--plugin-dir` delivers agents, not the Rules payload the dispatcher behavior lives in) +- fixed — [Important] nothing established that either auditor was invoked AS an agent — a headless run with a hand-written prompt audits inline, matching self-report and emitting `CLEAN` while the duties and coverage tell go unexercised; license: the plan's own discriminating-observables discipline; the code block passes `--agent ` (verified present in `claude --help`) and the executor must quote one agent-sourced marker before relying on a report +- fixed — [Minor] the `resolved (declined)` shape round 9 added to the spec was absent from Task 5's Produces, which Step 1 ships verbatim; license: the same invented-token rule round 9 applied spec-side; the shape joins the dictated list +- fixed — [Minor] the plugin README's "every component reads the glossary" claim was falsified by two components whose glossary duty no spec decided; license: the plan's own glossary-bans-bind-all-shipped-text constraint plus the propagation-auditor's duty 6 class; both agents state the duty in their bodies, since an audit agent adopts no persona and inherits nothing from `PERSONA_COMMON.md` + +### 2026-08-29 — plan-adversary, opus 5, blocking (round 11, full-document) + +- fixed — [Important] the `held` line round 10 mandated had no shape the shipped grammar admits (no severity, no question, no round heading), in the document committed as the grammar's first exemplar; license: the grammar block this plan ships verbatim plus the invented-token ⇒ spec gap rule; the deferral moved to the loop spec's own Verification section, where the run is defined — no ledger token invented +- fixed — [Important] Step 4's ledger write followed Step 3b's commit, leaving a tracked artifact dirty at the developer STOP — round 8's defect recurring on another file; license: the process-artifacts never-leave-them-dirty clause; the same move resolves it, the deferral now riding Step 3b's spec commit +- fixed — [Important] the propagation gate was routed into two workflow sites with no reconciliation, shipping one rule stated twice while the per-bullet diff passed on the duplicate; license: the audit spec treating them as one gate; the dispatch subsection is named canonical and the flow entry points at it +- fixed — [Important] the process-status skill gained logic no step ever ran — the plan verified the raw `rg` instead; license: round 1's own identification of that consumer as the one that would structurally reject the new hits; Step 3a runs the skill headless and quotes the report +- fixed — [Minor] the code block showed one propagation dispatch while item 1 mandates one per spec; license: item 1's own text; both invocations shown +- fixed — [Minor] Task 7 committed with no validation step; license: the plan's own every-commit constraint; the validate step added +- fixed — [Minor] the plugin README's re-sync paragraph was not extended to the audit offers, so the agents would ship with no installed rule offering them; license: the paragraph's own purpose; Task 8 Step 1 carries it + +### 2026-08-29 — plan-adversary, opus 5, blocking (round 12, full-document) + +- fixed — [Important] Step 3a ran after Step 3's block re-enabled the installed plugin, so the changed skill would run against a live name collision the harness resolves silently; license: the dogfood recipe's own collision guard and restore discipline; Step 3a carries its own disable/enable pair and requires the five-class marker only the plugin-dir copy can produce +- fixed — [Important] two round-11 fixes defeated each other — removing the last `held` line guaranteed zero ledger hits, so Step 3a's Expected was unattainable and the changed confirmation branch never executed; license: the sweep's own verified emptiness; Step 3a builds a two-line fixture (one in-section, one out) and expects both branches observed, deleting it before Step 3b +- fixed — [Important] the integrity-audit offer was routed into two workflow sites with no reconciliation — the defect round 11 fixed for the propagation gate and left standing for its sibling; license: the loop spec settling the pair as one reshaped offer; the flow entry points at the dispatch subsection's definition, mirroring the propagation wording +- fixed — [Important] the architect narrowing shipped with no named test and the audit spec's Verification clause naming one was neither run nor deferred — all three architect rounds on that spec predate the narrowing; license: the loop spec's own deferral precedent from round 11; recorded in the audit spec's Verification section with the developer as owner +- fixed — [Minor] both Files lists declared "four sites" their own steps contradict — under-enumerated in Task 5, over-enumerated in Task 6; license: the steps themselves, re-derived; Task 5 names five real sites, Task 6 names three edited plus one verified-not-modified +- fixed — [Minor] both specs would ship their content while recorded as never approved, and no grep would surface it; license: the lifecycle rule's linear `status`; Step 4's hand-off names three `status` moves, not one +- fixed — [Minor] the plugin README's flow line — the first thing a reader sees — omitted the two gates this release adds; license: the marketplace-sync identity discipline; Task 8 Step 1 carries it + +### 2026-08-29 — plan-adversary, opus 5, blocking (round 13, full-document) + +Diagnosis this round, and the reason the wave below removes seams rather than adding guards: 4 of 5 Importants sat in Task 9's harness, 1 in Task 6, none in Tasks 1–5 or 7–8 — the product half has gone two full rounds without a substantive finding while the harness produced five in two and was accelerating. The reviewer's own words: Step 3/3a had become "a second plan embedded in the first", where "every hardening fix adds a guard, and every guard adds a seam that the next round mines". + +- fixed — [Important] two of the audit spec's four propagation dispatch points reached no step, because rounds 11–12 collapsed the gate to a statement sourced from the loop spec, whose gate is only "before any re-dispatch"; license: the audit spec's own dispatch-point list; Step 1's canonical statement now carries the full set and the authoring-time multi-site offer lands in the numbered flow as its own clause +- fixed — [Important] Step 3a's five-class marker rested on a false premise (the installed 0.13.0 copy ships no process-status skill at all) and discriminated nothing; license: the reviewer's verified install listing plus the skill's own mandated closers; the step invokes `/process-status` and quotes the two closers only the skill produces +- fixed — [Important] item 1's hard `CLEAN` bar had no path for a contested hit, which recurs on every re-dispatch and would put the bar out of reach forever; license: the audit spec's confirm-or-dismiss contract; a dismissal branch, a third conditional STOP in the executor-audit list, "no confirmed hits remain" as the terminal condition, and a two-re-dispatch bound +- fixed — [Important] Step 3a opened a disable window with no failure or STOP path, leaving the developer's install disabled and the fixture on disk; license: the dogfood recipe's restore discipline; ONE blanket sentence now binds every disable window in Task 9 and the per-step clause is deleted — a seam removed, not a guard added +- fixed — [Important] the fixture's shape was unspecified exactly where the changed consumer turns on it (the skill rejects every hit in a file without a frontmatter block, a clause Task 5 Step 5 never scoped); license: the skill's own text; Task 5 Step 5 decides it as a file-level invariant surviving re-scoping, and the fixture carries valid frontmatter +- fixed — [Minor] Step 4 routed the deferral to an action Step 3 does not carry and a commit that will not carry it — both deferrals are already on disk and ride Task 1 Step 5; license: the specs' own text; restated as fact +- fixed — [Minor] Task 6's Files count double-counted the co-edit clause, which sits inside the dispatch subsection the same list declares edited; license: the range's own definition; three sites, the clause verified in Step 4 + +Structural change, not a patch: Step 3a is demoted from a pass/fail gate to EVIDENCE the executor quotes and the developer reads at the Step 4 STOP. + +Loop closed 2026-08-29 by developer adjudication — `blocking +(adjudicated 2026-08-29)`, the form the loop spec defines for a +blocking verdict a developer closes without a fresh round. The +adjudication rests on round 13's own diagnosis: the product tasks +(1–5, 7–8) went two full rounds without a substantive finding, every +round-13 finding was fixed with a cited license, and the remaining +risk sits in Task 9's verification harness, which round 13 advised +simplifying rather than reviewing further. Round 14 was dispatched +diff-scoped over the one product-side fix and stopped unread when the +adjudication landed; nothing from it is recorded. Known residual risk, +named rather than discovered later: Task 9's harness has not been +reviewed since the round-13 simplification, so its choreography is +the least-verified part of this plan. diff --git a/docs/specs/2026-08-17-autonomous-review-loop-design.md b/docs/specs/2026-08-17-autonomous-review-loop-design.md new file mode 100644 index 0000000..c425b5e --- /dev/null +++ b/docs/specs/2026-08-17-autonomous-review-loop-design.md @@ -0,0 +1,429 @@ +--- +ticket: none +date: 2026-08-17 +status: draft +grilled: 2026-08-27 +architect: concerns (resolved 2026-08-27) +--- + +# Autonomous remediation in the review loop + +## Problem + +After an architect or plan-adversary verdict, the dispatching session +today fixes the reviewed document when it has no questions for the +developer and dispatches a fresh round; when it has questions, the next +round waits for the answers. Nothing defines which findings the session +may fix alone, how findings it must not fix alone are held and +surfaced, or when the loop stops. The developer wants the loop to run +with minimal input — the session fixes what it can, and every decision +still lands on the developer's desk exactly once. + +This spec builds on the background-dispatch mechanics that +`2026-08-17-background-verdict-dispatch-design.md` defined and +working-process has since shipped (the relay turn, the single-edit +stamp, subject routing, one live round per document per field) and +would be needed even without them: the triage boundary is about +authority, not delivery. It shares a release with the audit-agents +spec, whose propagation-auditor this loop names as a gate when +available. + +## Design + +### Consent — the loop is the offered unit + +An autonomous re-dispatch is a step nobody individually offered, so the +workflow ethos ("every step is an offer") is met one level up: the +session asks once per Claude Code session, at the first verdict +dispatch, whether the review loop may run autonomously — yes / not now +/ not in this session — states the cap, and honours the answer without +re-asking, mirroring the consult-consent pattern of workflow step 1. A +durable preference belongs in the developer's own instructions and is +respected when present. Without consent, every round behaves as today: +relay, stamp, and the session's proposals wait for the developer. + +### Triage — a citable license, not a judgment + +A finding is self-fixable when the session can cite the decision that +licenses the fix: a statement in the document itself, a glossary term +or `_Avoid_` ban, a recorded ADR, or a previously resolved held line. +The citation is written into the finding's disposition line. No citable +license means the finding is held for the developer. When in doubt, it +is a decision — and is held. + +The license test is the plugin's existing wording/decision boundary +(the elements-of-style clause "binds wording, never decisions"; +grilling applies updates only as decisions land) applied to review +findings. Consequences the rule text states explicitly: + +- Severity is not the line. A Minor finding can be decision-shaped (a + naming call the developer already ruled on); a Critical can be + self-fixable (a contradiction with a recorded ADR — the ADR is the + license). Triage reads the fix's license, never the finding's grade. +- A contradiction between two decision-bearing statements is held; + "fixing for consistency" must not silently pick a winner. +- A finding the session believes is wrong is held with the session's + counter-evidence attached — never silently fixed, never silently + dropped. The session never arbitrates between the reviewer and a + recorded developer decision. +- Only written decisions license fixes. A decision settled in + conversation becomes citable by being written into the document, + which the fix itself accomplishes. + +### The disposition ledger — state lives in the document + +The lifecycle rule already requires a `concerns`/`blocking` round to +record its findings or their disposition in the document body. This +spec gives that record a grammar — one line per finding, with a +disposition token: + +- `open` — written at stamp time, as part of the single-edit stamp the + background spec defines. An `open` line surviving a session means the + remediation never ran; the document's next touch re-offers it. +- `fixed` — self-fixed; the line cites the licensing decision and says + in one clause what changed. +- `held` — needs the developer; the line carries the concrete question + (or the dispute plus counter-evidence), phrased so one short answer + resolves it. +- `resolved ` — closes a held line once the answer lands. The + answer's substance goes into the document's design text; the ledger + line points at it and never duplicates it. `resolved (declined)` + records the developer keeping the document as it was. + +The record's shape is canonical, not improvised — practice produced +three competing conventions across six documents before this spec. The +section is `## Review rounds`; a round opens with +`### , , (round N[, ])` — +the scope token is part of the canonical shape, `diff-scoped` or +`full-document`, omitted only on a round that predates the +distinction; the recovery clause keys on its absence-of-`full-document` +reading, so a full round always says so; +each finding takes one line with an anchored leading token: + + - fixed — [] ; license: ; + - held — [] ; question: + - open — [] + - resolved — [] ; landed in
+ - resolved (declined) — [] ; + +The mandated command is +`rg -n --no-ignore --crlf '^- (open|held) —' docs/` — the list's +hardening flags (`--no-ignore --crlf`), plus `-n` where the shipped +entries use `-l`, deliberately: this entry's hits are confirmed +against section membership, so line positions are needed. A match counts only when +the line sits inside a `## Review rounds` section — the body-side +analogue of the list's frontmatter guard, kept for the same reason: a +document quoting this grammar describes it rather than instantiating +it. A contested propagation hit takes the held shape with `[hit]` in +the severity slot (Sequencing) — the grammar's one severity-token +variant. A spec's accepted chain appends `, chain accepted ` to +its diff-scoped LGTM heading (Re-dispatch briefs) — the grammar's one +heading annotation. + +The ledger is the ask-once mechanism: a resolved held line is a +recorded decision, so when a later round re-raises the same problem the +new finding is folded and cited against it — never re-asked. +Relitigation is prevented by state, not by the reviewer's memory. + +A fix wave that deviates from a reviewer's suggestion records the +deviation and its rationale beside the text they concern — not only in +the ledger — so the next reviewer trips over the reason exactly where +the disagreement lives. + +Two greppable anchors join the lifecycle rule's unfinished-work +discipline: `open` lines (a stamped round whose remediation never ran) +and `held` lines (pending developer questions). The `held` anchor is +load-bearing — a later LGTM round leaves the frontmatter greps clean +while a decision question still pends. No frontmatter counter mirrors +the lines: one home, one grep. + +They join as ONE Unfinished-work entry — one class, an unfinished +review-loop ledger — whose entry text names both owners: an `open` +line's next move belongs to the document's next touch (the re-offer), +a `held` line's to the developer. The entry deliberately re-scopes the +list's frontmatter-only invariant for itself: its hits count inside a +`## Review rounds` section and nowhere else, and the lifecycle-rule +edit carries that re-scoping explicitly rather than leaving the plan +writer to reconcile the collision. + +### Sequencing — the loop yields to the developer + +After relay and stamp, the session triages every finding and applies +the licensed fixes. Then: + +- Held set empty: dispatch the next round without asking, within the + cap. +- Held set non-empty: batch the held questions into one message at the + relay turn — per item: a one-line claim, why it is held, the + question, and options with the session's recommendation — and wait. + A fresh round dispatches only on a document with no findings awaiting + the developer; a round over known-open decisions would re-report them + at the loop's most expensive tier for zero information. The developer + may explicitly order a round on the partial document; every step is + an offer. + +One batch per round is the minimal-input property stated as a +contract: the developer is interrupted exactly once per round, and +only when a decision is genuinely theirs. + +Before any re-dispatch — held set empty or developer-ordered — the +propagation-auditor (audit-agents spec) gates the round when it is +available: the session dispatches it over the repaired document, fixes +its hits, and repeats until the audit comes back clean. A hit's fix is +licensed by its own derivation — a recounted counter or an enumerated +missed call site decides itself — so hits never wait for the developer; +a hit the session believes is wrong escalates as held, like any +contested finding — its held line carries the marker `[hit]` in the +severity slot, because a hit stays ungraded even when contested. +Without the auditor installed, the dispatch proceeds as before. Expensive reviewers read only mechanically consistent +documents — measured on a 22-round client cycle where roughly one +finding in ten was a counter or boundary sentence the top-tier reviewer +policed by prose. + +### Re-dispatch briefs + +The first round reads the whole document; every later round is +diff-scoped — briefed on what changed since the round it follows, +directed to attack the previous wave's fixes first, and forbidden from +re-reviewing the rest. Repair-born defects are the dominant late-round +class in both measured loops (this repo's 2026-08-25 run and a client +project's 22-round cycle, where twelve consecutive rounds traced one +round's repair to the next round's defect), and the one diff-scoped +round in that cycle had the best precision of all rounds at the lowest +reading cost. Diff-scoping also eliminates stale-read findings. + +Every brief states the loop's terminators outright — the cap and the +all-Minor signal below — rather than improvising them late, and asks +the reviewer for its own stop signal: when the round's remaining +findings are all Minor wording residue, say so and judge whether +another round is worth its cost. That judgment concerns the NEXT +round's marginal value, never whether the document is good enough, and +it informs the developer's decision rather than replacing it. + +A diff-scoped LGTM certifies a chain, not a fresh whole-document read: +round 1 read the whole document, and every later wave was reviewed by +the round that followed it — that chain is what the stamped verdict +vouches for. For a spec the chain has a backstop: the consumption +gate's integrity audit (audit-agents spec, when available) re-reads the +whole text before anything is built on it. For a spec whose LGTM came +from a diff-scoped chain, the gate's offer is the pair from the start — +an integrity audit or a confirming full-document round, one question, +never an offer followed by a re-offer of the option just declined; +when the auditor is not installed, the offer carries the confirming +round alone, a tool that is not installed disabling its suggestion, +never the work. Declining is the developer explicitly accepting the +chain, and the acceptance is recorded, not remembered: `, chain +accepted ` appended to the diff-scoped LGTM heading — the +`, waived ` precedent — so the gate never re-asks. Every step an +offer. A plan's consumption gate +(implementation) carries no gated integrity audit, so a plan's loop +never terminates on a diff-scoped LGTM: when a diff-scoped round +returns LGTM on a plan, one full-document confirming round follows, +and the confirming round's verdict is the one stamped. The diff-scoped +LGTM is relayed and its round record written — the +`### , , LGTM (round N, +diff-scoped)` heading is the durable marker that a confirming round is +owed — while the frontmatter stamp alone waits for the confirming +round. That is the one named exception to the relay-then-stamp +sequence, and it lands in both sentences of the co-edited pair: the +workflow rule's dispatch subsection and the lifecycle rule's +relay-then-stamp sentence declare themselves edited together, so the +exception cannot live in only one of them. Recovery reads the ledger, +not the stamp — and it is plan-scoped: a plan whose latest round +heading is a diff-scoped LGTM that no later full-document round +follows owes its confirmation, and the plan's next touch re-offers +it — whatever the frontmatter says, since an annotation-closed or +previously-approved document is grep-clean there. A spec's diff-scoped +LGTM owes nothing standing: it is the loop's normal terminal state, +settled at the consumption gate by the audit, the confirming round, or +the recorded acceptance above. Scoping never spans a close: an annotation close +ends the loop, and a later round on the same document is a new loop's +first round, reading the whole document. + +When the ledger records a deviation from a reviewer's suggestion, the +next round's brief invites refutation of the recorded rationale — the +rationale is not a defence to be protected. Validated in both +directions in one measured round: the invited reviewer upheld the +deviation and refuted its recorded justification, and both corrections +were real. + +### Termination + +- `LGTM` ends the loop — for a plan, only a full-document round's + LGTM does (Re-dispatch briefs). If held lines are still open (the question + outlived its finding), the consumption gate is the backstop: a spec + does not pass to plan-writing, nor a plan to implementation, with + open held lines — they are asked there at the latest. The same guard + covers the spec→plan seam: writing a plan from a spec with open held + lines asks them first. +- `blocking` suspends autonomy entirely: relay, stamp, stop — no + self-fixes from a blocking round. By the architect's own grammar, + blocking means the design cannot deliver its purpose or overrides a + recorded decision; reshaping that is design work and re-enters + through the design conversation, not through remediation. `concerns` + is the autonomy zone; `blocking` never is. (Rejected alternative: + route blocking findings through ordinary triage and rely on the + relay veto — fewer special cases, but it lets a session self-fix + fragments of a design the reviewer judged broken as a whole.) +- Round cap: three autonomous rounds per document per field without + developer contact. Hitting the cap escalates — one batch: what was + fixed, what remains, why — rather than halting silently. Any + developer contact resets the count; the cap bounds unattended spend, + nothing else. +- All-Minor signal: two consecutive rounds whose findings are all + Minor end the unattended run — fix the residue, annotate + `concerns (resolved )`, and escalate with a fresh-round offer + instead of dispatching again. The cap guards spend, the signal guards + sense; both are escalations, never walls. (Measured 2026-08-17 on a + four-round hand-driven loop: the signal would have fired after round + 2, and rounds 3–4 found only what a later plan-adversary round + catches anyway.) +- Oscillation tripwire: a finding re-raised against a `fixed` line is + never re-fixed autonomously — two readings of the same license are a + contested reading; it escalates as held, the flip named. + +A model-cap refusal mid-loop is already a developer contact (the +workflow rule's drop-or-wait question) and is never answered +autonomously. + +Loop closure reuses existing machinery: after answers land, the +session offers a fresh round (replacing the verdict as usual) or the +lifecycle rule's `concerns (resolved )` annotation with its body +note — this loop gives that annotation its natural traffic. A +`blocking` verdict sometimes closes by explicit developer adjudication +rather than a fresh round; the recorded form is +`blocking (adjudicated )`, with the round record as its body +note — convention, not improvisation (first executed 2026-08-17). + +### Held questions across sessions + +Pending held lines re-surface at the document's next touch and at the +consumption gate — not at session start. This matches the background +spec's recovery philosophy: the document is the durable state, and a +gap in it re-offers the step. (Rejected alternative: a session-start +"you owe two answers" digest — more proactive, but it makes every +session pay a scan for a state the gates already catch.) + +## Changes by file + +- `plugins/working-process/rules/workflow.md` — the dispatcher + paragraph gains the loop: the consent question, the license test, + yield-on-held and the batch shape, the re-dispatch brief duties + (diff-scoping, terminators stated up front, the reviewer's stop + signal, invited refutation), the propagation gate (conditional on + the audit-agents spec's component), the round cap, the all-Minor + signal, the oscillation tripwire, blocking-suspends-autonomy, the + note that relay is the standing veto, and the one named exception + to the relay-then-stamp sequence: a plan's diff-scoped LGTM relays + and writes its round record, only the frontmatter stamp waiting for + the confirming full-document round. The consumption-gate offer for a + spec whose LGTM came from a diff-scoped chain lands here too — the + pair question (integrity audit or confirming full-document round), + the confirming-round-alone narrowing when the auditor is absent, and + decline recorded as acceptance — reshaping the singular audit offer + the audit-agents spec routes into this same rule. So does the + plan-side recovery re-offer: a plan whose latest round heading is a + diff-scoped LGTM that no later full-document round follows is + re-offered its confirming round at the document's next touch. +- `plugins/working-process/skills/process-status/SKILL.md` — the + hit-confirmation step takes an entry's own published match scope + when the entry re-scopes it (the ledger entry's `## Review rounds` + sections); the frontmatter guard stays the default for every entry + that publishes no scope of its own. +- `plugins/working-process/rules/spec-plan-lifecycle.md` — the + disposition grammar with its canonical record shapes (the contested- + hit `[hit]` variant, the `, ` heading token (`diff-scoped` | `full-document`), and the + `, chain accepted ` heading annotation included) and license + citation, the `open`/`held` entry in the Unfinished-work list with + its re-scoped match semantics (hits count inside `## Review rounds` + sections, an explicit exception to the list's frontmatter guard) and + the hardened command shape, the `blocking (adjudicated )` + close form, the consumption-gate backstop for open held lines + (including the spec→plan seam), and the relay-then-stamp exception + mirrored into this rule's own sentence of the co-edited pair — the + two rules declare that ordering edited together, so the exception + lands in both or in neither. The `, chain accepted ` + annotation's writer is named here: the dispatcher appends it at the + gate on the developer's decline, and its presence defeats the gate's + re-ask. +- `plugins/working-process/agents/architect.md`, `plan-adversary.md` — + untouched. Triage is the dispatcher's judgment: the reviewer cannot + see what the developer has decided in session, so a reviewer-side + "needs-developer" label would be wrong exactly in the contested + cases (rejected alternative). + +A minor working-process version bump at release, shared with the +audit-agents spec; the change is backward-compatible. + +## Out of scope + +- Code-review remediation — triaging `*-code-review` findings into + fix/plan/spec lanes is the parked review-driven remediation loop + (Private memory), a different pipeline stage. +- Background plan-writing — its own parked feature; the seam guard + here (held spec lines asked before plan-writing) binds it when it + lands. +- Report-contract changes — both reviewer report shapes stay as the + background spec leaves them. + +## Verification + +Dogfooding in this repo: run this spec through the loop it defines — +consent asked once, an architect round in the background, licensed +findings self-fixed with citations, held questions batched once per +round, and the ledger greppable afterwards. + +Deferred, owner named (2026-08-29): the release ships without this +run. `--plugin-dir` delivers agents but not the Rules payload, and the +loop's dispatcher behavior lives in the rules, so the run needs a +`sync-rules` re-sync first — the obligation the plugin README already +states after any update. The developer owns it, on the first real spec +after release. + +Platform fact already proven (2026-08-17, four headless runs): a +`claude -p` session survives a background dispatch, receives the task +notification, and completes the relay→stamp sequence — the loop can +run unattended. + +Deferred, explicitly: a mechanical lint (hook) checking `## Review +rounds` line grammar and anchors is a later release's component, +designed then — nothing in this release depends on it. + +## Review rounds + +### 2026-08-27 — architect, fable 5, blocking (round 1, full-document) + +- resolved 2026-08-27 — [Important] the ledger anchors joined the Unfinished-work list whose shipped invariant counts frontmatter hits only; landed in "The disposition ledger" (section-scoped match semantics, hardened command, one entry naming both owners) +- resolved 2026-08-27 — [Important] a diff-scoped LGTM silently changed what the stamped verdict certifies, with no backstop for plans; landed in "Re-dispatch briefs" (the certification chain stated; a plan's loop never terminates on a diff-scoped LGTM) +- resolved 2026-08-27 — [Important] the release rider shipped a lint hook the spec never designs; landed in "Verification" (deferred to a later release) +- resolved 2026-08-27 — [Minor] a contested hit escalated as held would carry a severity token hits do not have; landed in "Sequencing" (the `[hit]` marker) + +### 2026-08-27 — architect, fable 5, blocking (round 2, diff-scoped) + +- fixed — [Important] the document state between a plan's diff-scoped LGTM and its confirming round was undefined, each reading breaking a recorded convention; license: this spec's own recovery philosophy (the document is the durable state); the not-stamped reading chosen, the relay-then-stamp exception named in the workflow bullet, the Termination bullet qualified +- resolved 2026-08-27 — [Important] the spec-side backstop (integrity audit) is conditional and declinable with no stated absence behavior; landed in "Re-dispatch briefs" (an unaudited diff-chain LGTM re-offers at the consumption gate: integrity audit or a confirming full round; declining both accepts the chain explicitly) +- fixed — [Minor] "the hardened shape every Unfinished-work entry carries" misstated the shipped `-l` shape; license: the shipped lifecycle rule text; the sentence now names the flags and defends `-n` deliberately +- fixed — [Minor] the `[hit]` variant was absent from the canonical grammar block and the lifecycle bullet; license: this spec's own Sequencing decision; both now carry it + +### 2026-08-27 — architect, fable 5, blocking (round 3, diff-scoped) + +- fixed — [Important] the not-stamped reading's greppability guarantee failed on annotation-close and post-approval paths, and discarded the round record with the stamp; license: the workflow rule's stamp-as-one-edit definition plus this spec's own closure structure; the round record carved out as the durable marker, recovery reads the ledger, and an annotation close ends the loop so scoping never spans it +- fixed — [Important] the relay-then-stamp exception was routed to the workflow edit only, splitting a co-edited mirror pair; license: the pair's own edited-together clause in both shipped rules; the exception lands in both sentences and both Changes-by-file bullets name it +- fixed — [Minor] the inserted `[hit]` sentence orphaned the command sentence into a lowercase fragment; license: the sentences themselves; reconnected +- fixed — [Minor] the unavailable path re-offered an uninstalled tool; license: the workflow rule's not-installed-disables-suggestion ethos; the unavailable path carries the confirming round alone + +### 2026-08-27 — architect, fable 5, concerns (round 4, diff-scoped) + +- fixed — [Important] the recovery clause's unscoped subject made a spec's accepted chain re-offer its confirmation forever, with the acceptance unrecorded; license: this spec's own recovery philosophy (durable state, never memory) plus the shipped `, waived ` precedent; recovery scoped to plans, the gate's offer stated as the pair from the start, acceptance recorded as `, chain accepted ` on the heading +- fixed — [Minor] the load-bearing `, diff-scoped` token was absent from the canonical heading shape; license: this spec's own round-2 `[hit]` resolution, the same propagation class; the canonical shape and the lifecycle bullet carry it +- fixed — [Minor] the split re-offer re-offered the option just declined; license: round 2's resolved ledger line (the pair as one question); the gate's offer is the pair from the start + +### 2026-08-27 — architect, fable 5, concerns (round 5, diff-scoped) + +- fixed — [Important] the round-4 gate behavior was fully designed in the body and routed to no file edit, in a two-spec release where the sibling routes the singular audit offer this pair reshapes; license: this spec's own round-3 routing precedent plus its ledger discipline (the rule edit carries the re-scoping explicitly); both Changes-by-file bullets now carry the gate clauses + +Loop closed 2026-08-27 by the resolution annotation, on round 5's own +alternative: the single finding was a two-clause routing edit with no +design content, fixed as suggested, and the whole-text backstop is the +consumption gate's integrity audit this release ships — the exact +mechanism this pair of specs defines. diff --git a/docs/specs/2026-08-27-audit-agents-design.md b/docs/specs/2026-08-27-audit-agents-design.md new file mode 100644 index 0000000..8af0e9c --- /dev/null +++ b/docs/specs/2026-08-27-audit-agents-design.md @@ -0,0 +1,295 @@ +--- +ticket: none +date: 2026-08-27 +status: draft +grilled: 2026-08-27 +architect: LGTM +--- + +# Audit agents — propagation-auditor and integrity-auditor + +## Problem + +Two measured review loops show verdict rounds spending most of their +cost on work that is not design review. In this repo's 8-round +background-verdict-dispatch loop, three consecutive rounds of the most +capable model hand-diffed every prescribed block against the shipped +files. In a client project's 22-round cycle, 9 architect and 13 +adversary rounds produced 204 findings of which zero touched the +architecture: twelve consecutive rounds traced one round's repair to +the next round's defect, and roughly one finding in ten was a counter +or boundary sentence in prose — wrong in nearly every round, twice +wrong after being explicitly "verified". Separately, the architect +reviews textual integrity without a mandate: 11 of 15 findings in the +newest measured spec round were integrity-class, while +`ARCHITECT_PERSONA.md` names none of that duty. + +Nobody in the process owns two questions: *did the repair land +everywhere it had to?* and *does the churned document still hold +together as a text?* Both are policed today by the most expensive +dispatches, casually and late. + +## Design + +### The category + +An **Audit agent** (glossary) reports no verdict and stamps nothing: it +checks a document and returns material for the dispatcher's +disposition. It is dispatched as a gate before expensive work — a clean +audit is a precondition, never a judgment on the design. Audit agents +adopt no persona and are not persona surfaces. Two ship in this spec, +split by the nature of the work: procedural checking a cheap model does +well under instruction, and judgment reading that earns the top tier. + +Rejected shapes, each measured against the evidence: one agent with two +dispatch modes (tier and output contract would change per dispatch, +making the definition conditional); the mechanical agent absorbing the +judgment lenses (judgment on the cheapest family contradicts the +46-item yield the full-context, top-tier run produced); the judgment +agent absorbing the mechanical duties (the top family doing procedural +work casually is the single largest cost inefficiency both loops +measured). + +### propagation-auditor + +The mechanical pass. Dispatched on the **cheapest available family**, +named explicitly — the inverse of the review rule, and the point: every +duty is procedural (parse, enumerate, count, diff), which a capable +model does casually badly and a cheap model does fine when told to +derive by counting. The workflow rule's "reviews are never dispatched +on the cheapest available family" stands untouched — an audit is not a +review. + +**Output: hits** (glossary) — located, binary, each carrying its +derivation. The dispatcher confirms or dismisses each hit; a confirmed +hit's fix is licensed by the derivation itself (a recounted counter, an +enumerated missed consumer decides itself), so hits never wait for the +developer. A hit the dispatching session believes is wrong escalates to +the developer — never silently dismissed. A clean audit reports one +line — the literal token `CLEAN`. The report opens with the model self-report defined for both +auditors in the integrity-auditor's tier-verification paragraph. + +**Dispatch points**: before every verdict-agent dispatch, first rounds +included — authoring errors exist before any repair; after a fix wave, +before the next round (the autonomous-loop spec names this gate, +conditionally); before an integrity audit; and offered after any +multi-site edit during authoring. When the agent is not installed, +every dispatch proceeds as today. + +**Duties.** Each traces to a measured finding class; the agent file +phrases them domain-neutrally, with the marketplace's instantiation +beside each: + +1. **Changed interface → consumer enumeration by parsing, never text + match.** Measured: grep missed 2 of 11 call sites of a changed + signature; an argument-counting parse missed zero. Here: a renamed + rule section, skill, or anchor → every cross-reference. +2. **Prescribed block versus shipped file.** Every verbatim block a + plan dictates, diffed against the file it targets — the + recipe-and-record class that cost three hand-diff rounds. +3. **Added field, label, or state → carrier and consumer chains.** + Flag defined-but-never-consumed and consumed-but-never-defined. +4. **Counters re-derived, never trusted.** Every count a document + asserts is re-derived from what the tool would print or the list + actually holds. +5. **Cross-document identifier diff.** A name the plan uses that the + spec never defines is reported **as a spec gap, not a plan error** — + the invention is the symptom. Measured: one such gap survived nine + rounds as the cycle's deepest Important. +6. **Boundary sentences.** Frontmatter citations of another document's + verdict or counts, table row counts, review-record arithmetic. +7. **Verification simulation.** The document's own verification + commands, run against the document's own replacement texts, before + any reviewer reads either. + +### integrity-auditor + +The judgment pass — the run is an **integrity audit**. Dispatched on +the **most capable available** tier, named explicitly, in a **fresh +context**: the agent must not inherit the editing session, because the +measured cause of textual decay was a ~900-line document churned inside +a session at roughly 650k tokens, and a reviewer carrying that context +carries the blind spot with it. + +The tier is verified, not assumed: the auditor's report opens with a +model self-report (family plus version), and the dispatcher compares it +against the dispatched and prescribed tiers before stamping — a +below-tier run gets no stamp and is re-dispatched. Binary on purpose: +no `*-fallback`-style record machinery, because an unstamped audit +simply re-offers itself. The propagation-auditor's report opens with +the same one-line self-report, compared against the dispatched and +prescribed rung — the cheapest available family — for its exposure +runs the other way: below the cheapest there is no rung, +but an omitted model inherits the session's model, and an over-tier +run does this procedural work casually badly, so a false clean line +would feed the integrity gate unnoticed. A mismatched run earns no +reliance and is re-dispatched at the right rung. + +**Preconditions**: every edit from the conversation written to disk — +the deliverable is text-to-text comparison, so one unsaved decision +manufactures a run of false defects; and a clean propagation audit, +when that agent is available, so the expensive read never polices +arithmetic. + +**Target and moment**: primarily a spec, offered at the consumption +gate before plan-writing — after the architect round and after its +dispositions are applied, which is where churn accumulates. A plan is a +permitted target on explicit request, not a gated one. + +**Duties — two lenses**, the judgment share left after the mechanical +split: + +- *The document against itself*: decisions changed in one section and + restated in their old form in another; claims undermined elsewhere; + unworkable sequencing; and the most portable instruction of the + proven prompt — **verify every rule the document declares about + itself, in both directions**. +- *Sufficiency for an implementer*: read as a careful implementer who + must build from this text and has no other context; report + underspecified places, and a separate section of **ranked implementer + questions** — a good question is worth more than a weak finding. + +**Output**: defects, each proved by two quotes, plus the ranked +questions — never graded, never counted as Findings. The report names +the target's line count and the highest line it cites, so a partial +read exposes itself. The report returns to the dispatcher for +disposition like any relay. + +**The stamp**: the dispatcher writes +`integrity: (sha: )` into the document's +frontmatter after dispositions are applied — the date for the reader, +the hash for the check. The hash is the short SHA-1 of the document +text below the frontmatter's closing `---`, so writing the stamp never +invalidates what it stamps; the canonical recipe, shared by stamper +and gate so the comparison can never mismatch on convention, is +`sed '1,/^---$/d' | shasum | cut -c1-7`. `shasum` rather than +`sha1sum` because the rule installs machine-wide and stock macOS ships +only the former; the two produce identical digests, verified, so a +GNU-only environment may substitute `sha1sum` without changing any +recorded hash. Verdict-free, because the field answers +"was this checked after the last edit" — and the answer is a +comparison, not a clock: a recomputed hash differing from the stamped +one means unaudited, exactly, same-day edits included. (A bare date +fails precisely in the churn scenario the audit exists for — this +bundle's loop spec took seven amendment waves in one day. The +precedent is Drift's rule: always a content-hash comparison, never a +version comparison.) Any change re-arms the stamp, a typo fix +included — conservative on purpose. Staleness joins no Unfinished-work +list entry: it is a recomputation, not a frontmatter grep — and the +consumption gate owns that recomputation: before plan-writing it +recomputes the body hash and compares, a match meaning the standing +stamp satisfies the gate and a mismatch meaning the audit offer fires. +Those are spec-gate semantics: on a plan — a permitted target on +explicit request — the stamp is informational and goes stale silently, +with no plan-side owner. +As a stamped process field, `integrity` joins the Misplaced-stamp +enumeration: the glossary's field list gains it now, the detecting +Unfinished-work entry at implementation. + +### The paired edit — narrowing the architect's card + +`ARCHITECT_PERSONA.md` narrows in the same release: the architect +reviews the design — fit, boundaries, over-engineering, alternatives — +and when a round trips over integrity-class defects it notes them in +one line and defers to the integrity audit instead of spending the +round enumerating them. Without this edit the same findings arrive from +two surfaces at the top tier, and the component pays for nothing: 11 of +15 findings in the measured round were exactly this class. Released +alone, the audit would add a fifth offer and take nothing away — the +narrowing is the other half of the feature, not a courtesy. + +### Naming + +Settled at the 2026-08-27 grilling, with the trail recorded: +`sweep-verifier` (the client postmortem's working name) rejected — +**sweep** in this repo's vocabulary is a mechanical `rg` command with +quoted output, which an agent is not; `coherence-auditor` rejected in +favour of **integrity-auditor**; `consistency-auditor` rejected as a +near-synonym collision with "coherence". The `*-auditor` suffix joins +the naming conventions: a verdict-free audit agent returning material +for disposition is named `*-auditor`. + +## Changes by file + +- `plugins/working-process/agents/propagation-auditor.md` — new; role + inline (like plan-adversary), no persona file; `background: true` + like every agent this plugin ships. +- `plugins/working-process/agents/integrity-auditor.md` — new; role + inline; fresh-context and precondition duties stated in the agent + body; `background: true`. + +Both audits are background dispatches, so a gated dispatch waits for +its audit's task notification before it is issued — the gate is a +sequencing rule, not a blocking call, and it reuses the relay +machinery every other dispatch already uses. +- `plugins/working-process/ARCHITECT_PERSONA.md` — the narrowing. +- `plugins/working-process/rules/workflow.md` — the two offers (the + integrity audit at the pre-plan consumption gate; the propagation + audit before verdict dispatches and after multi-site edits) and the + audit tier sentences: propagation on the cheapest available family, + integrity on the most capable available, both named explicitly, with + the review never-cheapest rule explicitly not applying to audits. +- `plugins/working-process/rules/spec-plan-lifecycle.md` — the + `integrity:` field: placement, the date-plus-body-hash value, the + canonical hash recipe verbatim (stamper and gate run the same + command), and the recomputation semantics. +- `.claude/rules/plugin-authoring.md` — the `*-auditor` naming line. +- `docs/domain/glossary.md` — Audit agent and Hit entries (landed at + the grilling); the Misplaced-stamp entry's field list gains + `integrity` (landed at review round 1). The lifecycle rule's + Misplaced-stamp detecting entry gains the field at implementation. +- Plugin README and manifest description — the identity surfaces the + marketplace-sync rule binds. + +A minor working-process version bump at release, shared with the +autonomous-review-loop spec. + +## Out of scope + +- The autonomous loop itself — its spec; the propagation gate is named + conditionally in both directions. +- The propagation checklist as a distributed authoring rule (parked in + Private memory) — the agent's duty list is self-contained; a future + rule may mirror it for authors, never replace it. +- Seam-review checklist skills for the plan-adversary — parked + separately; every Critical in the measured cycle lived in a seam, and + that class belongs to the `*-plan-review` family, not to audits. +- Per-language machinery. In code repos a compiler owns duties 1–2; + the agent file's domain-neutral phrasing lets a code project benefit + without this spec shipping language support. + +## Verification + +Dogfooding on this bundle's own documents: run the propagation-auditor +over both specs before their architect rounds (cheapest family; expect +hits or a clean line — either proves the contract); run an integrity +audit on the autonomous-loop spec, this bundle's most churned document +(a restored draft plus seven amendment waves in one day), before +plan-writing; stamp `integrity:` and confirm a later edit re-arms it — +the recomputed body hash differs from the stamped one. Deferred, owner named (2026-08-29): all three architect rounds on this +spec predate the narrowing, so its first live test is owed — the +developer owns it, on the next architect round after release. The +sentence below states what that round should show. + +The architect round on this spec doubles as the narrowing's +first live test: its report should defer integrity-class observations +rather than enumerate them. + +## Review rounds + +### 2026-08-27 — architect, fable 5, concerns (round 1, full-document) + +- fixed — [Important] the tier the integrity audit depends on was asserted but unverifiable at stamp time; license: the lifecycle rule's model self-report convention plus this spec's own tier argument; the auditor self-reports, the dispatcher compares, a below-tier run gets no stamp +- fixed — [Minor] `integrity:` extended the Misplaced-stamp enumeration without touching it; license: the glossary's closed Misplaced-stamp field list plus this spec's own duty-5 class; the field list gains `integrity`, the detecting entry at implementation +- fixed — [Minor] the staleness recomputation had no named owner; license: this spec's own consumption-gate design; the gate recomputes the body hash and compares before the offer fires + +### 2026-08-27 — architect, fable 5, concerns (round 2, diff-scoped) + +- fixed — [Important] the tier guard covered only the below-tier direction while the propagation-auditor's exposure runs above (an over-tier run can return a false clean line the integrity gate silently relies on); license: the workflow rule's "in both directions" warning plus this spec's own casually-badly evidence; the propagation report opens with the same self-report, compared against the cheapest family +- fixed — [Minor] the recomputation owner was named only for the spec target while a plan may carry the stamp; license: this spec's own permitted-target sentence plus the sibling spec's no-gated-audit clause; scoped to spec-gate semantics, a plan's stamp informational and stale silently +- fixed — [Minor] "It joins no Unfinished-work list entry" contradicted the Misplaced-stamp detecting entry four lines later; license: the two sentences themselves; scoped to "Staleness joins no Unfinished-work list entry" + +### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped) + +- fixed — [Minor] the propagation comparison target named an absolute family where the mirrored mechanism compares dispatched against prescribed; license: the glossary's Tier entry (a rung resolves at dispatch time); the sentence now mirrors the integrity wording +- fixed — [Minor] the propagation-auditor's self-report duty lived only under the integrity-auditor heading; license: this spec's own tier-verification paragraph defining the duty for both auditors; the propagation Output paragraph now points at it From 46765edac2fa27824812c989cfe2a1617dc8f32d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:24:10 +0200 Subject: [PATCH 029/126] feat(working-process): add propagation-auditor audit agent --- .../agents/propagation-auditor.md | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 plugins/working-process/agents/propagation-auditor.md diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md new file mode 100644 index 0000000..8cfafa9 --- /dev/null +++ b/plugins/working-process/agents/propagation-auditor.md @@ -0,0 +1,152 @@ +--- +name: propagation-auditor +description: "Mechanical propagation audit of a spec or plan before an expensive dispatch: parses changed interfaces to enumerate their consumers, diffs every prescribed block against the file it targets, re-derives every counter, and returns located hits with their derivation — or the single line CLEAN. Verdict-free and persona-free: it stamps nothing and grades nothing, so a clean audit is a precondition for the dispatch that follows, never a judgment on the design. Dispatch before every verdict-agent dispatch, after a fix wave, before an integrity audit, and after any multi-site edit during authoring. Run it on the cheapest available family, named explicitly — every duty is procedural, and the never-cheapest rule governs reviews, which an audit is not. Runs in the background; the report arrives as a task notification." +background: true +--- + +The mechanical pass over a document — the propagation audit. Your +deliverable is a list of hits: located, binary detections, each carrying +the derivation that produced it. You adopt no persona and you return no +verdict. Your report is material for the dispatcher's disposition, and +the dispatch it gates treats a clean audit as a precondition, never as a +judgment on the design. + +## First action: the domain artifacts + +You inherit no persona file and no standing duties, so this duty is +stated here. Before your first check, read the project's domain artifacts +when they exist: `docs/domain/glossary.md` and `docs/domain/adr/`, +resolved against the repo root (`git rev-parse --show-toplevel`) — a +dispatch inherits the session's working directory, which may sit below +the root, and a miss here is silent: a missing glossary and a working +directory below the root look identical. + +Canonical terms and `_Avoid_` bans bind your own wording. They also feed +two duties below: a newly minted ban is an interface change whose +occurrences duty 1 enumerates, and the glossary is a definition source +for duty 5 — a term a document leans on that no canonical entry defines +is the gap that duty reports. + +## Your tier, and the self-report that proves it + +You run on the cheapest available family, named explicitly at dispatch — +the inverse of the rule governing verdict dispatches, and the point of +the split: every duty below is procedural (parse, enumerate, count, +diff), which a capable model does casually badly and a cheap model does +well when told to derive by counting. + +Your report therefore opens with a one-line model self-report, family +plus version, which the dispatcher compares against the dispatched and +the prescribed rung. Your exposure runs upward: below the cheapest family +there is no rung, but an omitted model inherits the session's model, and +an over-tier run does this work casually badly — a false clean line would +then feed the integrity gate unnoticed. A mismatched run earns no +reliance and is re-dispatched at the right rung. + +## Ground rules + +- Derive, never recall. Every hit names the parse, the enumeration, the + count, or the diff that produced it; a claim without one is not a hit. +- A text match is where a check starts, never where it ends. Confirm each + match and account for what the pattern could not reach. +- Re-derive every number from the thing counted. The sentence asserting a + count is the thing under audit, never the evidence for it. +- Report what you found and stop there: no severity, no ranking, no + advice on the design. + +## Duties — walk all seven; each is a class measured in a real loop + +### 1. Changed interface → consumer enumeration by parsing, never text match + +For every interface the document changes — a signature, a name, a +heading, an anchor, a field — enumerate its consumers by parsing the +structure that defines them. Measured: a text match missed 2 of 11 call +sites of a changed signature; an argument-counting parse missed zero. +Here: a renamed rule section, skill, agent, or anchor reaches every +cross-reference to it, and a newly minted glossary `_Avoid_` ban reaches +every shipped occurrence of the banned term. + +### 2. Prescribed block versus shipped file + +Diff every verbatim block the document dictates against the file it +targets — the block that never landed and the shipped text a block no +longer matches are both hits. This is the recipe-and-record class that +cost three consecutive hand-diff rounds of the most capable model. + +### 3. Added field, label, or state → carrier and consumer chains + +Follow every field, label, or state the document adds to both ends of its +chain, and flag defined-but-never-consumed and consumed-but-never-defined. +Here: a new frontmatter process field needs a surface that writes it and a +surface that reads it — the stamper, the gate, the greppable command, the +glossary entry, the README. + +### 4. Counters re-derived, never trusted + +Re-derive every count the document asserts from what the tool would print +or what the list actually holds. Here: the number of skills, agents, +rules, duties, or offers a README, a rule, or a manifest description +claims. + +### 5. Cross-document identifier diff + +Diff the names one document uses against the names its sources define. A +name the plan uses that the spec never defines is a spec gap, not a plan +error — the invention is the symptom, and report it as the gap it is. +Measured: one such gap survived nine rounds as the cycle's deepest +Important. + +### 6. Boundary sentences + +Check every sentence in which one document reports another's state: +frontmatter citations of another document's verdict or counts, a table's +row count against the table, the arithmetic of a review record. Roughly +one finding in ten in the measured cycle was a counter or a boundary +sentence — wrong in nearly every round, twice wrong after being +explicitly verified. + +### 7. Verification simulation + +Run the document's own verification commands against the document's own +replacement texts, before any reader reads either. A command that fails +to match what the document says it matches is a hit; so is a replacement +text that defeats the anchor its own command relies on. + +## Output + +Open with the self-report, one line: + + model: + +A clean audit then reports one line and nothing else — the literal token: + + CLEAN + +Otherwise, one entry per hit: + + — derivation: + +Hits are never graded. Critical, Important, Minor, and every other +severity word stay out of your report: grading belongs to review rounds, +whose unit is a finding. Propose no verdict, and stamp nothing into any +frontmatter. + +## What becomes of your hits + +The dispatcher confirms or dismisses each hit. A confirmed hit's fix is +licensed by the derivation itself — a recounted counter and an enumerated +missed consumer decide themselves — so hits never wait for the developer, +and a hit the dispatching session believes is wrong reaches the developer +rather than a silent dismissal. Write each derivation to stand alone: the +dispatcher acts on it, never on your confidence. + +## Out of bounds + +- Editing the document, or applying the fix a hit implies. +- Design judgment — whether the shape is right ends in a verdict, and + that dispatch is the architect's. +- Reading the document for the judgment defects an integrity audit + hunts: decisions restated in their old form, unworkable sequencing, + underspecified places. That is the sibling pass, on the most capable + available tier and in a fresh context. +- Prose quality, naming taste, and style. From 906fd9bbe8c83d66c43fd19342475d2cd4f56cb4 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:27:13 +0200 Subject: [PATCH 030/126] feat(working-process): add integrity-auditor audit agent --- .../agents/integrity-auditor.md | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 plugins/working-process/agents/integrity-auditor.md diff --git a/plugins/working-process/agents/integrity-auditor.md b/plugins/working-process/agents/integrity-auditor.md new file mode 100644 index 0000000..b7e55c0 --- /dev/null +++ b/plugins/working-process/agents/integrity-auditor.md @@ -0,0 +1,158 @@ +--- +name: integrity-auditor +description: "Judgment audit of a churned design document, read on a fresh context — primarily a spec at the consumption gate before plan-writing: reads the document against itself, verifies in both directions every rule the document declares about itself, and reads it once more as an implementer who must build from this text and has no other context. Returns defects each proved by two quotes, plus a separate section of ranked implementer questions, plus the coverage tell that exposes a partial read. Verdict-free and persona-free: it grades nothing and stamps nothing, so a clean audit is a precondition for the work that follows, never a judgment on the design. Dispatch on the most capable available tier, named explicitly, and in a fresh context — the auditor must not inherit the session that churned the document. Runs in the background; the report arrives as a task notification." +background: true +--- + +The judgment pass over a document — the integrity audit. Your deliverable +is a list of defects, each proved by two quotes, and beside it a ranked +list of the questions an implementer would have to ask before building. +You adopt no persona and you return no verdict. Your report is material +for the dispatcher's disposition, and the work it gates treats a clean +audit as a precondition, never as a judgment on the design. + +## First action: the domain artifacts + +You inherit no persona file and no standing duties, so this duty is +stated here. Before your first read, read the project's domain artifacts +when they exist: `docs/domain/glossary.md` and `docs/domain/adr/`, +resolved against the repo root (`git rev-parse --show-toplevel`) — a +dispatch inherits the session's working directory, which may sit below +the root, and a miss here is silent: a missing glossary and a working +directory below the root look identical. + +Canonical terms and `_Avoid_` bans bind your own wording, and they feed +both lenses below: a term the document leans on that no canonical entry +defines is an underspecified place, and a recorded decision the document +now contradicts is a defect you can prove with two quotes. + +## Your tier, and the self-report that proves it + +You run on the most capable available tier, named explicitly at dispatch. +The judgment below is the share of the work no cheaper rung does — the +mechanical share belongs to the propagation audit, and the split is the +point. + +Your report therefore opens with a one-line model self-report, family +plus version, which the dispatcher compares against the dispatched and +the prescribed tier before stamping. A run below the prescribed tier +earns no stamp and is re-dispatched. Report the model you actually ran +on, never the model the dispatch asked for. + +## Fresh context, and the preconditions it rests on + +You read the document cold. The measured cause of textual decay is a +document of some nine hundred lines churned inside one session at roughly +650k tokens, and a reader carrying that session carries its blind spot: +the decision it remembers agreeing to reads as present whether or not the +text says it. Judge the text in front of you, and treat no claim about it +as settled because a dispatch brief asserts it. + +Two preconditions hold before you read, and your dispatch brief should +confirm both: + +- **Every edit from the conversation is written to disk.** Your + deliverable is a text-to-text comparison, so one unsaved decision + manufactures a run of false defects. +- **The propagation audit is clean**, when that agent is available, so + this expensive read never spends itself policing arithmetic. + +If the brief leaves a precondition unmet — pending edits, a propagation +audit that returned hits — say so in one line and stop. A run against a +stale file wastes the tier and returns defects the developer has already +fixed. + +## Target and moment + +Your primary target is a spec, audited at the consumption gate before +plan-writing: after the architect round and after its dispositions are +applied, which is where the churn accumulates. A plan is a permitted +target on explicit request, never a gated one. Read the whole target, +first line to last. + +## Duties — two lenses; walk both + +### 1. The document against itself + +Read the document as a text that must hold together, and hunt the ways it +no longer does: + +- a decision changed in one section and restated in its old form in + another; +- a claim one section makes that another section undermines; +- sequencing the document prescribes that cannot run in the order given — + a step depending on what a later step produces; +- and the most portable instruction of this lens: **verify every rule the + document declares about itself, in both directions.** A document that + says every entry carries a field is checked entry by entry for the + field, and field by field for an entry the rule never claimed — the + reverse direction is where the survivors hide. + +### 2. Sufficiency for an implementer + +Read the document again as a careful implementer who must build from this +text and has no other context: no conversation, no author to ask. Report +the places that text leaves underspecified — a named surface with no +defined shape, a behaviour prescribed for one case and silent on its +obvious sibling, a value whose source is never named. + +From the same read, produce the ranked implementer questions: what you +would have to ask before writing the first line, hardest blocker first. +A good question is worth more than a weak defect — when a passage leaves +you unsure whether it is wrong or merely unstated, the question outranks +the finding you would have manufactured. + +## Output + +Open with the self-report, one line: + + model: + +Then the defects, one entry each: + + + quote A: "" + quote B: "" + +Two quotes prove a defect; one quote is an impression. A defect you +cannot prove with a second located quote belongs in the questions section +instead, phrased as the question it really is. + +Then the ranked questions, under their own heading, hardest blocker +first — separate from the defects and never mixed into them. + +Close with the coverage tell, one line: + + coverage: lines; highest line cited + +The tell is how a partial read exposes itself, so report both numbers +even when they embarrass the run. + +Defects are never graded and never counted as Findings. Critical, +Important, Minor, and every other severity word stay out of your report: +grading belongs to review rounds. Propose no verdict. + +## What becomes of your report + +The report returns to the dispatcher for disposition like any relay: the +dispatcher decides what each defect costs and applies the fixes, and the +ranked questions go to the developer, who is the only one who can answer +them. + +The `integrity:` frontmatter field is written by the dispatcher after +those dispositions are applied — the field records that the document was +audited after its last edit, so a stamp written before the fixes would +certify the wrong text. You never write it, and you edit no frontmatter +at all. + +## Out of bounds + +- Editing the document, applying a fix, or writing any stamp. +- Design judgment — whether the shape is right, whether the alternatives + were weighed — which ends in a verdict, and that dispatch is the + architect's. +- The mechanical checks of the propagation audit: consumer enumeration, + prescribed blocks diffed against shipped files, re-derived counters, + boundary sentences. That pass runs before yours, on the cheapest + available family, and re-running it here spends the tier on arithmetic. +- Prose quality, naming taste, and style. From 6f03cc4b27a2d6d05c2f0d9b03e703d2b002eec8 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:29:43 +0200 Subject: [PATCH 031/126] feat(working-process): narrow architect card, integrity class defers to the audit --- plugins/working-process/ARCHITECT_PERSONA.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/working-process/ARCHITECT_PERSONA.md b/plugins/working-process/ARCHITECT_PERSONA.md index c940402..0777dc1 100644 --- a/plugins/working-process/ARCHITECT_PERSONA.md +++ b/plugins/working-process/ARCHITECT_PERSONA.md @@ -24,3 +24,10 @@ interactions should be (that belongs to the system designer): argued? - Convention fit: does the design follow the project's established patterns and structures? + +Integrity-class textual defects belong to the integrity audit, not to this +round: a contradiction between two sections, a count that no longer matches +its list, a reference that drifted from what it names. When a round trips +over them, note the class in one line and leave the enumeration to the +`integrity-auditor` dispatch, which proves each defect with two quotes — +enumerating them here spends the top tier twice on one set of findings. From 42e14fae2c4a33641141118d4d1fde921006e2ad Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:36:30 +0200 Subject: [PATCH 032/126] feat(working-process): disposition ledger, integrity stamp and ledger-scoped hit confirmation --- .../rules/spec-plan-lifecycle.md | 115 +++++++++++++++++- .../skills/process-status/SKILL.md | 36 +++--- 2 files changed, 132 insertions(+), 19 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 1e0128c..e5e4ae0 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -18,6 +18,7 @@ grilled: grilling # optional: `grilling` while outcomes are pending; the ISO d architect: LGTM # optional: latest architect verdict (LGTM | concerns | blocking) adversary: LGTM # optional: latest plan-adversary verdict (LGTM | concerns | blocking) architect-fallback: (degraded ) # optional: verdict above produced below the prescribed tier (adversary-fallback: for plans) +integrity: (sha: ) # optional: date of the last integrity audit, plus the body hash it certifies branch: feature/ABC-123-short-name # optional: topic branch of the work base: master # optional: branch the topic branch was cut from --- @@ -32,7 +33,10 @@ base: master # optional: branch the topic branch was cut from - Concerns resolved without a fresh review round keep the verdict and gain a resolution date — `adversary: concerns (resolved 2026-07-16)` — plus a body note saying what resolved them. A fresh round replaces the - whole value as usual. + whole value as usual. A `blocking` verdict the developer closes by + explicit adjudication instead of a fresh round takes the same form with + its own token — `architect: blocking (adjudicated 2026-08-17)` — and + the round's ledger record as that body note. - A verdict produced below the prescribed tier (the model-selection heuristic in the workflow rule) gains a companion `architect-fallback:` / `adversary-fallback:` field: the family alias of the model that @@ -50,6 +54,28 @@ base: master # optional: branch the topic branch was cut from re-arms at the same gate). Declined: the field gains `, waived `. Moving `status` to `implemented` with a bare fallback field stamps the waiver as part of the move. +- `integrity:` records an integrity audit — the run the + `integrity-auditor` agent performs, when it is available — which the + dispatcher stamps once the audit's dispositions are applied: + `integrity: (sha: )`, the date for the reader and + the hash for the check. The hash covers the text below the + frontmatter's closing `---`, so writing the stamp never invalidates what + it stamps. Stamper and gate run one command, so the comparison can never + mismatch on convention: + `sed '1,/^---$/d' | shasum | cut -c1-7` + — `shasum` rather than `sha1sum` because stock macOS ships only the + former, and the two produce identical digests, so a GNU-only environment + may substitute `sha1sum` without changing a recorded hash. The field + carries no verdict: it answers whether the document was checked after + its last edit, and that answer is a comparison rather than a clock. A + recomputed hash differing from the stamped one means unaudited, same-day + edits included; any change re-arms the stamp, a typo fix included. +- A spec's consumption gate owns the recomputation: before plan-writing it + recomputes the body hash and compares, a match meaning the standing + stamp satisfies the gate and a mismatch firing the audit offer. Those + are spec-gate semantics — on a plan, a permitted target on explicit + request, the stamp is informational and goes stale silently. Staleness + joins no Unfinished-work entry: it is a recomputation, not a grep. - Verdict agents self-report the model they ran on (family plus version); the dispatcher compares it against the dispatched and prescribed tiers before stamping, and each round's verdict, model, and date are @@ -58,10 +84,66 @@ base: master # optional: branch the topic branch was cut from - `branch` and `base` appear once the topic branch exists — never guessed up front, omitted entirely when there is no topic branch. +## The disposition ledger + +The body record a `concerns` or `blocking` round owes has a canonical +shape, not an improvised one — practice produced three competing +conventions across six documents before it was written down. The rounds +live under one section, `## Review rounds`, and each round opens with a +heading: + + ### , , (round N[, ]) + +The scope token admits two values, `diff-scoped` and `full-document`, +and is omitted only on a round predating the distinction. A recovery +reading keys on the absence of `full-document`, so a full-document round +always says so. + +Under the heading each finding takes one line, its disposition the +leading token: + + - fixed — [] ; license: ; + - held — [] ; question: + - open — [] + - resolved — [] ; landed in
+ - resolved (declined) — [] ; + +- `open` — written at stamp time, before the findings are triaged. An + `open` line surviving a session means the remediation never ran, and + the document's next touch re-offers it. +- `fixed` — the session fixed the finding alone, licensed by a decision + it can cite: a statement in the document itself, a glossary term or + `_Avoid_` ban, a recorded ADR, or a previously resolved held line. The + citation goes on the line. No citable license means the finding is + held, and a finding that could go either way is a decision. +- `held` — the finding needs the developer. The line carries the + concrete question, or the dispute plus the session's counter-evidence, + phrased so one short answer resolves it. +- `resolved ` — closes a held line once the answer lands. The + answer's substance goes into the document's design text; the ledger + line points at it and never duplicates it. + `resolved (declined)` records the developer keeping the + document as it was. + +Two variants extend those shapes, and nothing else does. A contested hit +from the `propagation-auditor` agent, when it is available, takes the +held shape with `[hit]` in the severity slot, because a hit stays +ungraded even when contested. A spec whose developer accepts a +diff-scoped chain at the consumption gate gains `, chain accepted ` +on that round's LGTM heading: the dispatcher appends it there on the +decline, and its presence defeats the gate's re-ask, as `, waived ` +defeats the re-review offer. + +A resolved held line is a recorded decision. When a later round re-raises +the problem it settled, the new finding is folded and cited against that +line, never asked again — state prevents relitigation, not the +reviewer's memory. + ## Unfinished-work list One entry per class of unfinished process work: the class name, its -command, and the owner of the next move. This section is the list — a +command, and the owner of the next move, plus its own match scope where +the entry re-scopes one. This section is the list — a command published elsewhere, such as the ticket sweep in the ticket-frontmatter rule, is a lookup and not part of it. The `process-status` skill, when available, runs exactly what stands here, @@ -72,7 +154,9 @@ A command returns hits, not Findings. A hit counts only when the matching line sits inside the document's frontmatter block — between the `---` on the file's first line and the `---` that closes it, never a later pair — because a document quoting this convention in its body -describes it rather than instantiating it. +describes it rather than instantiating it. That guard is the default. An +entry re-scopes it only by publishing its own match scope as a fourth +leg, and the review-loop ledger entry below is the one that does. - **Grilling pending** — a session's outcomes are recorded and not yet applied. @@ -83,13 +167,24 @@ describes it rather than instantiating it. `rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/` Owner: a fresh round at the prescribed tier, or the resolution annotation above. +- **Unfinished review-loop ledger** — a disposition line nobody closed: + an `open` line whose remediation never ran, or a `held` line whose + question still waits. + `rg -n --no-ignore --crlf '^- (open|held) —' docs/` + Scope: a hit counts only inside a `## Review rounds` section — this + entry's own re-scoping of the guard above, kept for the same reason, + since a document quoting the grammar describes it rather than + instantiating it. Confirming section membership needs line positions, + which is why this command carries `-n` where the others carry `-l`. + Owner: an `open` line belongs to the document's next touch, which + re-offers the remediation; a `held` line belongs to the developer. - **Pending re-review** — a verdict produced below the prescribed tier, neither refreshed nor waived. `rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/` Owner: the re-review offer at the document's consumption gate. - **Misplaced stamp** — a process field outside the top level of the frontmatter, at any value. - `rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback):' docs/` + `rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback|integrity):' docs/` Owner: the developer; no process surface owns moving a stamp back. The class suppresses per field: it hides the one other class whose published command would match the relocated line, and no other — @@ -103,7 +198,10 @@ match, and that defeat is the recorded closed state. The leading anchors are tolerant on purpose, so a relocated field is still found. The Misplaced stamp command anchors `^\s+` instead, because there the indentation is the defect it looks for rather than an accident to -tolerate. +tolerate. Those anchors all sit on a frontmatter field; the review-loop +ledger entry anchors a leading disposition token instead, so there the +close is a rewrite — `open` or `held` becomes `resolved `, and the +anchor stops matching. ## Lifecycle offers @@ -121,6 +219,13 @@ verdict into the document's field — this sentence and the workflow rule's verdict-agent dispatch subsection state the same ordering and are edited together. +A document's consumption gate is the backstop for its ledger: a spec +does not pass to plan-writing, nor a plan to implementation, while +`held` lines stay open — an LGTM can leave the frontmatter clean while a +decision question still pends, so the gate asks those questions at the +latest. Writing a plan from a spec is that same seam: the held spec +questions are asked before the plan is written, whoever writes it. + The process suggests committing the work's documents under `docs/` at exactly one point — the implementation-ready gate: the developer has approved the plan (the `status` flip to `approved`) and implementation diff --git a/plugins/working-process/skills/process-status/SKILL.md b/plugins/working-process/skills/process-status/SKILL.md index 328c515..f47c26a 100644 --- a/plugins/working-process/skills/process-status/SKILL.md +++ b/plugins/working-process/skills/process-status/SKILL.md @@ -19,12 +19,15 @@ shipped beside this skill, never an installed copy under so that copy is always in step with this skill. Each entry carries three legs: the class name, one command, and the -owner of the next move. Take all three. +owner of the next move. Take all three. An entry may carry a fourth, its +own match scope — where in a document its hits count; take that too +whenever the entry publishes one. The read fails, and the report says so instead of reporting a clean -repo, when the section is missing or an entry lacks a leg. A run that -could not read the list must never look like a run that found no -unfinished work. +repo, when the section is missing or an entry lacks one of the three +legs. A run that could not read the list must never look like a run that +found no unfinished work. A missing fourth leg fails nothing: it means +the entry keeps the default scope. ## Step 2 — run each command @@ -35,18 +38,23 @@ differs from the published one answers a different question. ## Step 3 — confirm every hit A command returns hits. A hit becomes a report line only when its -matching line sits inside the document's frontmatter block: the file's -opening `---` on line 1 and its closing `---`. Read the head of the -file to decide. - -- The line sits inside that block → the hit is real. +matching line sits where the entry says its hits count. The default +scope is the document's frontmatter block: the file's opening `---` on +line 1 and its closing `---`. An entry publishing a scope of its own +replaces that default with what it publishes, and replaces nothing else. +Read the head of the file for the default scope, and the lines above the +match for a scope naming a section. + +- The line sits inside the entry's scope → the hit is real. - The line sits anywhere else → the document quotes the convention instead of instantiating it. Reject the hit. -- The file has no opening `---`, or none closing it → treat it as having - no frontmatter block and reject every hit in it. A file whose - frontmatter never closes is broken for every consumer of frontmatter, - so it surfaces on its next touch rather than here. Say so if asked; - never invent a class for it. +- The file has no opening `---`, or none closing it → reject every hit in + it, whatever scope the entry publishes. A process document always + carries frontmatter, so a file without it is no process document at + all; a file whose frontmatter never closes is broken for every consumer + of frontmatter, so it surfaces on its next touch rather than here. An + entry's own scope narrows where a hit counts, never whether the file + qualifies. Say so if asked; never invent a class for it. ## Step 4 — report From 2fd6fcd59f48e8fa8fd40f9cc38a3ade60ae6e05 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:48:36 +0200 Subject: [PATCH 033/126] feat(working-process): review loop, audit offers and the relay-exception pair --- .../rules/spec-plan-lifecycle.md | 5 +- plugins/working-process/rules/workflow.md | 177 +++++++++++++++++- 2 files changed, 178 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index e5e4ae0..7210b39 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -217,7 +217,10 @@ close, resolved entries sweep to the archive. After any review round, relay the report to the developer, then stamp the verdict into the document's field — this sentence and the workflow rule's verdict-agent dispatch subsection state the same ordering and -are edited together. +are edited together. The order has one named exception, defined in that +subsection: a plan's diff-scoped LGTM is relayed and its round record +written, while only the frontmatter stamp waits for the confirming +full-document round. A document's consumption gate is the backstop for its ledger: a spec does not pass to plan-writing, nor a plan to implementation, while diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index f9b0b99..9559443 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -27,8 +27,21 @@ disables its suggestion — never the work itself. working-process `architect` agent (when available); dispatch and stamping follow the verdict-agent dispatch subsection below. Dispatch it on the most capable available model, named explicitly. -4. **Spec → plan.** Write the implementation plan with - superpowers:writing-plans when available; plans live in `docs/plans/`. + When the `propagation-auditor` agent is available, a propagation + audit gates that dispatch and every later round — the dispatch + subsection below defines the gate and its dispatch points. Offer the + same audit at authoring time as well, after any multi-site edit; + that offer stands outside the loop, so the definition below does not + carry it. +4. **Spec → plan.** At the spec's consumption gate, before the plan is + written, offer an integrity audit when the `integrity-auditor` agent + is available: a fresh-context read of the whole spec, returning + defects and the questions an implementer would have to ask. For a + spec whose LGTM came from a diff-scoped chain the offer takes the + pair form the verdict-agent dispatch subsection defines, and narrows + as that definition says when the auditor is absent. Then write the + implementation plan with superpowers:writing-plans when available; + plans live in `docs/plans/`. 5. **Plan → adversary review.** Before implementing a non-trivial plan, offer a working-process plan-adversary agent dispatch (when available); dispatch and stamping follow the verdict-agent dispatch @@ -50,13 +63,25 @@ disables its suggestion — never the work itself. whatever review surface the matched plugin ships, and that surface owns scope resolution, dispatch, and the report. +Both audits offered above run in the background, so a gated dispatch +waits for its audit's task notification before it is issued — a +sequencing rule rather than a blocking call, running on the relay +machinery the verdict-agent dispatch subsection already defines. + Model selection for these dispatches: always name the model explicitly — an omitted model inherits the session's model, defeating the heuristic in both directions. Reviews are never dispatched on the cheapest available family. Consultations — the `*-consult` agents — dispatch on the most capable available model, named like any dispatch; a consultation is not a review, returns no verdict, and never gets a fallback record or -a re-review offer. When a dispatch is refused because the dispatched +a re-review offer. An audit is not a review either, and the +never-cheapest floor governs reviews alone: the `propagation-auditor` +dispatches on the cheapest available family and the `integrity-auditor` +on the most capable available, each named explicitly. Both reports open +with a model self-report the dispatcher compares against the dispatched +and the prescribed rung before relying on the result — a mismatched +propagation run earns no reliance, and a below-tier integrity run gets +no stamp. When a dispatch is refused because the dispatched model's cap is hit — and only then; any other failure is an ordinary error — ask the developer: drop one family (at most once, never onto the cheapest family) or wait for the reset. A verdict produced below @@ -135,5 +160,151 @@ available: - A consultation (`*-consult`) produces no verdict and nothing to record. +### The review loop + +Rounds after the first form a loop, and the loop is the offered unit — +no single re-dispatch is offered on its own. At the session's first +verdict dispatch, ask once whether the loop may run autonomously — yes +/ not now / not in this session — state the round cap with the +question, and honour the answer for the rest of the Claude Code session +without asking again. A durable preference in the developer's own +instructions is respected when present. Without consent every round +behaves as it did before: relay, stamp, and every proposal waits for +the developer. + +Triage decides each finding by its license, never by its grade. A +finding is self-fixable when the session can cite the decision that +licenses the fix — a statement in the document itself, a glossary term +or `_Avoid_` ban, a recorded ADR, or a previously resolved `held` +line — and the citation goes on the finding's line in the disposition +ledger the spec-plan-lifecycle rule defines. Everything else is held +for the developer, and a finding that could go either way is a +decision. Consequences the loop states outright: + +- Severity is not the line. A Minor finding can be a naming call the + developer already ruled on; a Critical can be a contradiction with a + recorded ADR, which the ADR itself licenses the session to fix. +- A contradiction between two decision-bearing statements is held: + fixing for consistency would pick a winner silently. +- A finding the session believes is wrong is held with the session's + counter-evidence attached — never fixed silently, never dropped + silently. The session never arbitrates between a reviewer and a + recorded developer decision. +- Only written decisions license fixes. A decision settled in + conversation becomes citable by being written into the document, + which the fix itself accomplishes. + +A fix wave that deviates from a reviewer's suggestion records the +deviation and its rationale beside the text they concern — not only in +the ledger — so the next reviewer trips over the reason exactly where +the disagreement lives. + +Once the licensed fixes land, the loop either continues or yields: + +- Held set empty — dispatch the next round without asking, within the + cap. +- Held set non-empty — batch the held questions into one message at the + relay turn (per item: the claim in one line, why it is held, the + question, and the options with the session's recommendation), then + wait. A fresh round dispatches only on a document with nothing + awaiting the developer, since a round over known-open decisions + re-reports them at the loop's most expensive tier for no + information. The developer may still order a round on the partial + document — every step is an offer. + +One batch per round is the contract: the developer is interrupted once +per round, and only over a decision that is genuinely theirs. + +### The propagation gate + +When the `propagation-auditor` agent is available, a clean propagation +audit is the precondition for the dispatches it gates: the session +dispatches the audit over the document, fixes its hits, and repeats +until the audit returns no hits, so an expensive reader only ever meets +a mechanically consistent document. The gate fires before every +verdict-agent dispatch, first rounds included — authoring errors exist +before any repair; after a fix wave, before the next round; and before +an integrity audit. A hit's fix is licensed by its own derivation — a +recounted counter and an enumerated missed call site decide +themselves — so hits never wait for the developer; a hit the session +believes is wrong escalates as held, its line carrying `[hit]` in the +severity slot, because a hit stays ungraded even when contested. +Without the agent installed, every dispatch proceeds as it did before. + +### Re-dispatch briefs + +The first round reads the whole document; every later round is +diff-scoped. Its brief names what changed since the round it follows, +directs the reviewer to attack the previous wave's fixes first, and +forbids re-reviewing the rest — repair-born defects are the dominant +late-round class, and diff-scoping also ends stale-read findings. + +Every brief states the loop's terminators outright — the cap and the +all-Minor signal below — rather than improvising them late, and asks +the reviewer for its own stop signal: when the round's remaining +findings are all Minor wording residue, say so and judge whether +another round earns its cost. That judgment concerns the next round's +marginal value, never whether the document is good enough, and it +informs the developer's decision rather than replacing it. Where the +ledger records a deviation from a reviewer's suggestion, the brief +invites refutation of the recorded rationale — a rationale is evidence +to attack, never a defence to protect. + +### Terminators + +- `LGTM` ends the loop — on a plan, only a full-document round's LGTM + does. +- `blocking` suspends autonomy entirely: relay, stamp, stop. A blocking + round licenses no self-fixes, because reshaping a design the reviewer + judged broken as a whole is design work and re-enters through the + design conversation. `concerns` is the autonomy zone. +- Round cap: three autonomous rounds per document per field without + developer contact. Hitting the cap escalates in one batch — what was + fixed, what remains, why — rather than halting silently, and any + developer contact resets the count. +- All-Minor signal: two consecutive rounds whose findings are all Minor + end the unattended run. Fix the residue, annotate + `concerns (resolved )`, and escalate with an offer of a fresh + round instead of dispatching one. +- Oscillation tripwire: a finding re-raised against a `fixed` line is + never re-fixed autonomously. Two readings of one license are a + contested reading, so it escalates as held, the flip named. + +The cap guards spend and the signal guards sense; both escalate, and +neither is a wall. Relay stays the developer's standing veto — every +report reaches them before the session acts on it — and a model-cap +refusal mid-loop is already developer contact: the drop-or-wait +question above is never answered autonomously. + +### What a diff-scoped LGTM certifies + +A diff-scoped LGTM certifies a chain rather than a fresh whole-document +read: round 1 read the whole document, and every later wave was +reviewed by the round that followed it. What that chain still owes +differs by document. + +For a spec, the consumption gate before plan-writing offers the pair as +one question — an integrity audit or a confirming full-document round — +and never an offer followed by a re-offer of the option just declined. +When the `integrity-auditor` agent is absent the offer carries the +confirming round alone. Declining is the developer accepting the chain +explicitly, and the acceptance is recorded rather than remembered: the +dispatcher appends `, chain accepted ` to the diff-scoped LGTM +heading, and that annotation defeats the gate's re-ask. + +For a plan the loop never terminates on a diff-scoped LGTM: one +full-document confirming round follows, and the confirming round's +verdict is the one stamped. That carries the single named exception to +the relay-then-stamp order above — a plan's diff-scoped LGTM is relayed +and its round record written, and only the frontmatter stamp waits for +the confirming round. Recovery therefore reads the ledger rather than +the stamp: a plan whose latest round heading is a diff-scoped LGTM that +no later full-document round follows is re-offered its confirming round +at the document's next touch, whatever the frontmatter says. + +Scoping never spans a close. An annotation close ends the loop, and a +later round on the same document opens a new one, reading the whole +document again. + This subsection and the lifecycle rule's relay-then-stamp sentence state the same ordering and are edited together. From ec3ab88b2bcd11e47b018450d77b836a107df53b Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:51:06 +0200 Subject: [PATCH 034/126] docs: add *-auditor to the component naming conventions --- .claude/rules/plugin-authoring.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.claude/rules/plugin-authoring.md b/.claude/rules/plugin-authoring.md index d56ea24..42a17b2 100644 --- a/.claude/rules/plugin-authoring.md +++ b/.claude/rules/plugin-authoring.md @@ -13,8 +13,9 @@ paths: - Names are kebab-case. Skills whose content is an open-ended conversation are named `*-session`; formal reviews that end in a verdict are agents; verdict-free consultation agents — one briefing in, one - contribution out, from a fresh isolated context — are named `*-consult`. - Operational skills may prompt for decisions without being + contribution out, from a fresh isolated context — are named `*-consult`; + audit agents returning material for the dispatcher's disposition are named + `*-auditor`. Operational skills may prompt for decisions without being sessions — they are named for what they do (e.g. `sync-rules`). - Author skills with the `skill-creator` skill when it is available — scaffolding, `description:` tuning, and evals; it complements From 77bb9bb87930790f2f19e90b44bfbd4dcab3de7d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 15:56:45 +0200 Subject: [PATCH 035/126] docs(working-process): identity surfaces for the audit agents and the integrity field --- .claude-plugin/marketplace.json | 2 +- README.md | 2 +- .../.claude-plugin/plugin.json | 2 +- plugins/working-process/README.md | 86 ++++++++++++++----- 4 files changed, 67 insertions(+), 25 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 2ce51c5..7579d56 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ { "name": "working-process", "source": "./plugins/working-process", - "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, plus distributed process rules" + "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, propagation-auditor and integrity-auditor audit agents, plus distributed process rules" }, { "name": "python-standards", diff --git a/README.md b/README.md index 76866f5..bedc117 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Marketplace of [Claude Code](https://code.claude.com) plugins by Missing Bits. | Plugin | Docs | Description | |--------|------|-------------| -| `working-process` | [README](plugins/working-process/README.md) | Spec-driven working process: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, two verdict-free consultation agents, distributed process rules | +| `working-process` | [README](plugins/working-process/README.md) | Spec-driven working process: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, two verdict-free consultation agents, propagation-auditor and integrity-auditor audit agents, distributed process rules | | `python-standards` | [README](plugins/python-standards/README.md) | Python coding standards for uv + ruff + pytest + pyright: area skills, code-review stack, plan-review checklist, distributed toolchain rule | | `salesforce-standards` | [README](plugins/salesforce-standards/README.md) | Salesforce coding standards for the sf CLI toolchain: area skills (Apex, LWC, Flow, data/security model, legacy UI), code-review stack, plan-review checklist, distributed toolchain rule | | `project-memory` | [README](plugins/project-memory/README.md) | In-repo project memory: committed Team memory (`docs/memory/`) and per-user Private memory (`.claude/memory/`), with `memory-review-session`, `migrate-memory`, and `redirect-memory` skills, distributed as a Rules payload | diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index 3467ff5..0e9adcc 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "working-process", - "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", + "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, propagation-auditor and integrity-auditor audit agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", "version": "0.14.0-dev.review-loop-audits", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index a9c30cf..f1cdd9e 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -4,7 +4,9 @@ Tech-agnostic tooling for a spec-driven working process on top of the `superpowers` plugin: idea → brainstorming (spec) → grilling-session → architect review → -writing-plans (plan) → plan-adversary → implementation → code review. +integrity audit → writing-plans (plan) → plan-adversary → +implementation → code review — with a propagation audit gating every +verdict dispatch and the integrity audit itself. ## Components @@ -18,7 +20,10 @@ writing-plans (plan) → plan-adversary → implementation → code review. `architect:` frontmatter field by the dispatcher. Dispatched in the background on the most capable available model; the verdict arrives as a task notification and is stamped after the dispatcher relays - the report. + the report. A round that trips over integrity-class textual defects — + a contradiction between two sections, a count adrift from its list, a + reference that drifted from what it names — notes the class in one + line and leaves the enumeration to the integrity audit. - **`architect-session` skill** — the same persona as an interactive in-session consultation: no verdict, no stamping; hands off to a grilling-session or an `architect` dispatch. Triggers: "ask the @@ -45,12 +50,34 @@ writing-plans (plan) → plan-adversary → implementation → code review. come from `*-plan-review` checklist skills. Dispatched in the background, scaled to the plan's size and risk; the verdict arrives as a task notification and is stamped after relay. +- **`propagation-auditor` agent** — the mechanical audit of a spec or + plan: it parses every changed interface to enumerate its consumers, + diffs every prescribed block against the file it targets, re-derives + every counter, and runs the document's own verification commands. Its + unit is the hit: located, binary, and carrying the derivation that + produced it; a clean audit reports the single line `CLEAN`. It grades + nothing, ends in no verdict, and stamps nothing. Dispatched in the + background on the cheapest available family, because every duty is + procedural; the workflow gates every verdict-agent dispatch and every + integrity audit on a clean run, and offers the same audit at + authoring time after any multi-site edit. +- **`integrity-auditor` agent** — the judgment audit of a churned + document, read on a fresh context: the document against itself, then + the document as an implementer who must build from that text alone. + It reports defects, each proved by two located quotes, beside a ranked + list of the questions an implementer would have to ask; it grades + nothing and ends in no verdict. Dispatched in the background on the + most capable available tier, and offered at a spec's consumption gate + before the plan is written. Once its dispositions land, the dispatcher + records the run in the spec's `integrity:` field. - **`process-status` skill** — reports what the process left unfinished - in the current repo: a pending grilling, an unresolved verdict, a - re-review nobody ran, a stamp outside the top level of a frontmatter - block. Runs the Unfinished-work list the lifecycle rule publishes and - fires none of the offers those classes name. Triggers: "what is - unfinished" / "process status". + in the current repo: a pending grilling, an unresolved verdict, an + unfinished review-loop ledger (an `open` or `held` disposition line, + counted only inside a `## Review rounds` section), a re-review nobody + ran, a stamp outside the top level of a frontmatter block. Runs the + Unfinished-work list the lifecycle rule publishes and fires none of + the offers those classes name. Triggers: "what is unfinished" / + "process status". - **`sync-rules` skill** — installs, updates, and uninstalls the rule files shipped by plugins of this marketplace (Rules payloads); see the "Process rules" section. @@ -61,9 +88,10 @@ Each persona is single-sourced in its file at the plugin root — shared duties, the persona boundary, and the consultation contract held once in [PERSONA_COMMON.md](./PERSONA_COMMON.md). `plan-adversary` sources its standing duties from the same shared file without being a -persona. Every component reads `docs/domain/glossary.md` and -`docs/domain/adr/` first, when they exist, so it speaks the project's -language from its first message. +persona; the two `*-auditor` agents inherit neither persona nor standing +duties and carry what they need in their own files. Every component +reads `docs/domain/glossary.md` and `docs/domain/adr/` first, when they +exist, so it speaks the project's language from its first message. ## Requirements @@ -100,6 +128,7 @@ containing a `status` field: | `architect` | `LGTM` \| `concerns` \| `blocking` | latest architect verdict | | `adversary` | `LGTM` \| `concerns` \| `blocking` | latest plan-adversary verdict | | `architect-fallback` / `adversary-fallback` | ` (degraded )` \| ` (chosen )` \| `…, waived ` | verdict produced below the prescribed tier (`degraded` = unchosen, `chosen` = deliberate); re-review pending until re-reviewed or waived | +| `integrity` | ` (sha: )` | last integrity audit — the date for the reader, the body hash for the check; the dispatcher writes it once the audit's dispositions land, and a spec's consumption gate recomputes the hash to decide whether the stamp still holds | A round ending in `concerns` or `blocking` records its findings in the document body. Concerns later resolved without a fresh round keep the @@ -120,18 +149,31 @@ capable for complex or risky plans, one family below for small mechanical ones. Consultations (the `*-consult` agents) dispatch on the most capable available model; like the verdict agents, they run as named background agents — consultations return no verdict, so the fallback machinery -below never applies to them. The verdict agents' relay-then-stamp -sequence lives in the workflow rule's Rules payload: after a plugin -update, run a rules re-sync so the dispatcher side of the behavior -matches the agents (until then the previously installed rules still -carry the older record-the-verdict obligation, so no round is lost). -The model is always named explicitly at dispatch, and -reviews never dispatch on the cheapest available family. A dispatch -refused on the dispatched model's cap offers a one-family drop (once) -or waiting for the reset; a verdict produced below the prescribed tier -gets a fallback record and a re-review offer — grammar and lifecycle in -the spec-plan-lifecycle rule. Agents self-report the model they ran on -(family plus version) so the dispatcher can verify before stamping. +below never applies to them. The model is always named explicitly at +dispatch, and reviews never dispatch on the cheapest available family. +A dispatch refused on the dispatched model's cap offers a one-family +drop (once) or waiting for the reset; a verdict produced below the +prescribed tier gets a fallback record and a re-review offer — grammar +and lifecycle in the spec-plan-lifecycle rule. Agents self-report the +model they ran on (family plus version) so the dispatcher can verify +before stamping. + +An audit is not a review, and that floor governs reviews alone: the +`propagation-auditor` dispatches on the cheapest available family, +since every duty it walks is procedural, and the `integrity-auditor` on +the most capable available tier — each named like any other dispatch. +Both audits end in no verdict, so the fallback machinery leaves them +out as well, and both reports open with a model self-report the +dispatcher checks before relying on the run: a mismatched propagation +run earns no reliance, a below-tier integrity run no stamp. + +The dispatcher's half of all this lives in the workflow rule's Rules +payload — the verdict agents' relay-then-stamp sequence, the two audit +offers, and the `integrity:` gate. After a plugin update, run a rules +re-sync so the dispatcher side matches the agents; until then the +previously installed rules still carry the older record-the-verdict +obligation and make neither audit offer, so no round is lost and the +new gates merely stay silent. ## Process rules From a998161bc573514a2306626cc3c3a53ddee9133e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 16:31:18 +0200 Subject: [PATCH 036/126] docs: apply two integrity-audit dispositions to the loop spec and glossary --- docs/domain/glossary.md | 13 ++++++++----- .../2026-08-17-autonomous-review-loop-design.md | 7 +++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 080eca6..6dad1be 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -236,11 +236,14 @@ _Avoid_: usage point **Unfinished-work list**: The named section of the spec-plan-lifecycle rule holding one entry per -class of unfinished process work — class name, grep command, and the -owner of the next move — and the single definition site for which -classes exist, so a new class costs one edit in the rule and none in -the consumers that run it. A command's output is hits to confirm -against the frontmatter block, never Findings. +class of unfinished process work — class name, grep command, the owner +of the next move, and optionally the entry's own match scope — and the +single definition site for which classes exist. A class that accepts +the default scope costs one edit in the rule and none in the consumers +that run it; a class that publishes its own scope costs a consumer edit +too, and the ledger class is the first. A command's output is hits to +confirm against the entry's scope — the frontmatter block by default — +never Findings. _Avoid_: anchor list, debt list **Misplaced stamp**: diff --git a/docs/specs/2026-08-17-autonomous-review-loop-design.md b/docs/specs/2026-08-17-autonomous-review-loop-design.md index c425b5e..e8c9065 100644 --- a/docs/specs/2026-08-17-autonomous-review-loop-design.md +++ b/docs/specs/2026-08-17-autonomous-review-loop-design.md @@ -137,6 +137,13 @@ load-bearing — a later LGTM round leaves the frontmatter greps clean while a decision question still pends. No frontmatter counter mirrors the lines: one home, one grep. +A plan's owed confirming round has no anchor of its own and needs none: +its marker is the latest round heading with no later full-document +round after it, which is a comparison across headings rather than a +match on one line. Recovery reads the ledger for it, at the document's +next touch, the way it reads any state no single line can carry — the +two anchors above stay the only greppable ones. + They join as ONE Unfinished-work entry — one class, an unfinished review-loop ledger — whose entry text names both owners: an `open` line's next move belongs to the document's next touch (the re-offer), From 80b9ea621700b2981547433261f87d4478b6a6e2 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 16:41:55 +0200 Subject: [PATCH 037/126] fix(working-process): close the final review's gate, anchor and attribution findings --- docs/specs/2026-08-27-audit-agents-design.md | 13 +++++++++ plugins/working-process/README.md | 7 +++-- .../rules/spec-plan-lifecycle.md | 5 ++-- plugins/working-process/rules/workflow.md | 29 ++++++++++++++----- .../skills/process-status/SKILL.md | 13 +++++---- 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/docs/specs/2026-08-27-audit-agents-design.md b/docs/specs/2026-08-27-audit-agents-design.md index 8af0e9c..fb49031 100644 --- a/docs/specs/2026-08-27-audit-agents-design.md +++ b/docs/specs/2026-08-27-audit-agents-design.md @@ -125,6 +125,19 @@ run does this procedural work casually badly, so a false clean line would feed the integrity gate unnoticed. A mismatched run earns no reliance and is re-dispatched at the right rung. +*Observed limitation (2026-08-29).* A live dogfood dispatched two +propagation runs under one named model — the dispatched string was +`claude-haiku-4-5-20251001` both times — and they self-reported +"haiku 4" and "claude-3-5-haiku-20241022". At the rung the comparison +held: both self-reports land on the cheapest available family, so both +runs were relied on correctly. At family plus version it did not: the +two strings disagree, and neither matches the dispatched one. A model +knows its rung more reliably than its own version, so the version half +of the comparison can fire on an otherwise correct run. The +prescription above stands unchanged — narrowing it to the rung is the +developer's call, and this paragraph records the measurement rather +than pre-empting it. + **Preconditions**: every edit from the conversation written to disk — the deliverable is text-to-text comparison, so one unsaved decision manufactures a run of false defects; and a clean propagation audit, diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index f1cdd9e..a972e63 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -167,9 +167,10 @@ out as well, and both reports open with a model self-report the dispatcher checks before relying on the run: a mismatched propagation run earns no reliance, a below-tier integrity run no stamp. -The dispatcher's half of all this lives in the workflow rule's Rules -payload — the verdict agents' relay-then-stamp sequence, the two audit -offers, and the `integrity:` gate. After a plugin update, run a rules +The dispatcher's half of all this lives in the plugin's Rules payload — +the verdict agents' relay-then-stamp sequence and the two audit offers +in the workflow rule, the `integrity:` stamp and its +recompute-and-compare gate in the spec-plan-lifecycle rule. After a plugin update, run a rules re-sync so the dispatcher side matches the agents; until then the previously installed rules still carry the older record-the-verdict obligation and make neither audit offer, so no round is lost and the diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 7210b39..5632ff9 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -186,8 +186,9 @@ leg, and the review-loop ledger entry below is the one that does. frontmatter, at any value. `rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback|integrity):' docs/` Owner: the developer; no process surface owns moving a stamp back. - The class suppresses per field: it hides the one other class whose - published command would match the relocated line, and no other — + The class suppresses per field: it hides any other class whose + published command would match the relocated line — at most one, and + for a field no other command names, such as `integrity`, none — itself excluded, since its own command matches every process field. Match semantics are the mapping, so a class published later needs no extra rule. diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 9559443..e28f991 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -36,10 +36,18 @@ disables its suggestion — never the work itself. 4. **Spec → plan.** At the spec's consumption gate, before the plan is written, offer an integrity audit when the `integrity-auditor` agent is available: a fresh-context read of the whole spec, returning - defects and the questions an implementer would have to ask. For a - spec whose LGTM came from a diff-scoped chain the offer takes the - pair form the verdict-agent dispatch subsection defines, and narrows - as that definition says when the auditor is absent. Then write the + defects and the questions an implementer would have to ask. The + offer fires unless a standing `integrity:` stamp still matches the + spec's recomputed body hash — a match means the standing stamp + satisfies the gate, and the spec-plan-lifecycle rule owns that + comparison. For a spec whose LGTM came from a diff-scoped chain the + offer takes the pair form the verdict-agent dispatch subsection + defines, and narrows as that definition says when the auditor is + absent. The brief + confirms the auditor's two preconditions: every edit from the + conversation is written to disk, since one unsaved decision + manufactures a run of false defects; and the propagation gate below + is clean, when that agent is available. Then write the implementation plan with superpowers:writing-plans when available; plans live in `docs/plans/`. 5. **Plan → adversary review.** Before implementing a non-trivial plan, @@ -134,7 +142,9 @@ available: verify the agent's model self-report (the comparison the lifecycle rule defines), relay the report to the developer, then stamp the verdict (`LGTM` | `concerns` | `blocking`) into the reviewed - document's `architect:` / `adversary:` frontmatter field. + document's `architect:` / `adversary:` frontmatter field. The order + has one named exception, defined under *What a diff-scoped LGTM + certifies* below: a plan's diff-scoped LGTM. - The relay carries the verdict, the model self-report, and every finding in substance — condense narrative prose, never drop a finding or its severity. @@ -142,6 +152,9 @@ available: the lifecycle rule defines — lands as one edit, body record first where edit granularity forces separate writes, and goes to the document named in the report, never to "the most recent dispatch". + The same exception splits that one edit: on a plan's diff-scoped + LGTM the round record lands while the frontmatter stamp waits for + the confirming round. - The sequence ends the delivery, not the loop: after relay and stamp the session may fix the document and dispatch a fresh round, or put its questions to the developer first. @@ -306,5 +319,7 @@ Scoping never spans a close. An annotation close ends the loop, and a later round on the same document opens a new one, reading the whole document again. -This subsection and the lifecycle rule's relay-then-stamp sentence -state the same ordering and are edited together. +The `## Dispatching a verdict agent` section above — its bullet list +and every subsection under it, this one included — and the lifecycle +rule's relay-then-stamp sentence state the same ordering and are edited +together. diff --git a/plugins/working-process/skills/process-status/SKILL.md b/plugins/working-process/skills/process-status/SKILL.md index f47c26a..603846b 100644 --- a/plugins/working-process/skills/process-status/SKILL.md +++ b/plugins/working-process/skills/process-status/SKILL.md @@ -42,8 +42,10 @@ matching line sits where the entry says its hits count. The default scope is the document's frontmatter block: the file's opening `---` on line 1 and its closing `---`. An entry publishing a scope of its own replaces that default with what it publishes, and replaces nothing else. -Read the head of the file for the default scope, and the lines above the -match for a scope naming a section. +Read the head of the file in every case, whatever scope the entry +publishes — the third bullet below turns on whether the file opens and +closes a frontmatter block at all — and, for a scope naming a section, +read the lines above the match as well. - The line sits inside the entry's scope → the hit is real. - The line sits anywhere else → the document quotes the convention @@ -64,9 +66,10 @@ the class distinguishes fields, and the owner the entry carries. Read the owner from the entry — never supply one from your own knowledge of the process. -Misplaced stamp suppresses per field: it hides the one other class whose -published command would match the relocated line — itself excluded, -since its own command matches every process field. Match semantics are +Misplaced stamp suppresses per field: it hides any other class whose +published command would match the relocated line — at most one, and for +some fields none — itself excluded, since its own command matches every +process field. Match semantics are the mapping, so you never need process knowledge to find it and a class published later works the same way. Name the field on the line, so the developer can see which class went quiet. From c51c0074f558bdf9e1bcd37da3f0900765de1f4e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 18:13:53 +0200 Subject: [PATCH 038/126] docs: mark the review-loop and audit-agents spec pair and plan as implemented --- docs/plans/2026-08-27-review-loop-and-audit-agents.md | 2 +- docs/specs/2026-08-17-autonomous-review-loop-design.md | 2 +- docs/specs/2026-08-27-audit-agents-design.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/plans/2026-08-27-review-loop-and-audit-agents.md b/docs/plans/2026-08-27-review-loop-and-audit-agents.md index 2e6ddc0..ac18f8a 100644 --- a/docs/plans/2026-08-27-review-loop-and-audit-agents.md +++ b/docs/plans/2026-08-27-review-loop-and-audit-agents.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-08-27 -status: approved +status: implemented adversary: blocking (adjudicated 2026-08-29) branch: feature/review-loop-audits base: develop diff --git a/docs/specs/2026-08-17-autonomous-review-loop-design.md b/docs/specs/2026-08-17-autonomous-review-loop-design.md index e8c9065..d167356 100644 --- a/docs/specs/2026-08-17-autonomous-review-loop-design.md +++ b/docs/specs/2026-08-17-autonomous-review-loop-design.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-08-17 -status: draft +status: implemented grilled: 2026-08-27 architect: concerns (resolved 2026-08-27) --- diff --git a/docs/specs/2026-08-27-audit-agents-design.md b/docs/specs/2026-08-27-audit-agents-design.md index fb49031..d97096d 100644 --- a/docs/specs/2026-08-27-audit-agents-design.md +++ b/docs/specs/2026-08-27-audit-agents-design.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-08-27 -status: draft +status: implemented grilled: 2026-08-27 architect: LGTM --- From c31d915a1d3e5e3a73a3213179760f4a24befaa8 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Sat, 29 Aug 2026 18:14:27 +0200 Subject: [PATCH 039/126] chore: mint release versions - working-process 0.14.0, project-memory 0.5.0 --- plugins/project-memory/.claude-plugin/plugin.json | 2 +- plugins/working-process/.claude-plugin/plugin.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/project-memory/.claude-plugin/plugin.json b/plugins/project-memory/.claude-plugin/plugin.json index d7fb59c..afafaf4 100644 --- a/plugins/project-memory/.claude-plugin/plugin.json +++ b/plugins/project-memory/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "project-memory", "description": "In-repo project memory for Claude Code sessions — committed Team memory (docs/memory/) and git-ignored per-user Private memory (.claude/memory/); a Rules payload plus memory-review-session, migrate-memory, and redirect-memory skills", - "version": "0.4.0", + "version": "0.5.0", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["memory", "notes", "ideas", "knowledge", "rules"] diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index 0e9adcc..78b950b 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, propagation-auditor and integrity-auditor audit agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0-dev.review-loop-audits", + "version": "0.14.0", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From eb5758e8795c79eff9706d4c9b4a2f88d18251dd Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 31 Aug 2026 10:14:35 +0200 Subject: [PATCH 040/126] chore: scope the standards-rule-tags rule to plugins/ --- .claude/rules/standards-rule-tags.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.claude/rules/standards-rule-tags.md b/.claude/rules/standards-rule-tags.md index 5d70a1b..096be8c 100644 --- a/.claude/rules/standards-rule-tags.md +++ b/.claude/rules/standards-rule-tags.md @@ -1,3 +1,8 @@ +--- +paths: + - "plugins/**" +--- + # Standards plugins — rule tags and severity Binding for every Standards plugin in this repo (`salesforce-standards`, From 6e4687adef5bd8083388856fe0a8ae89e869f437 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 1 Sep 2026 16:28:45 +0200 Subject: [PATCH 041/126] docs: give the integrity audit report a home under docs/audits --- ...-autonomous-review-loop-integrity-audit.md | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 docs/audits/2026-08-29-autonomous-review-loop-integrity-audit.md diff --git a/docs/audits/2026-08-29-autonomous-review-loop-integrity-audit.md b/docs/audits/2026-08-29-autonomous-review-loop-integrity-audit.md new file mode 100644 index 0000000..2660442 --- /dev/null +++ b/docs/audits/2026-08-29-autonomous-review-loop-integrity-audit.md @@ -0,0 +1,170 @@ +--- +ticket: none +date: 2026-08-29 +agent: integrity-auditor +model: claude-opus-5 +target: ../specs/2026-08-17-autonomous-review-loop-design.md +coverage: 429/429 +--- + +# Integrity audit — the autonomous review loop spec + +An `integrity-auditor` dispatch read +`docs/specs/2026-08-17-autonomous-review-loop-design.md` on a fresh +context and returned eleven defects and ten ranked implementer +questions at full coverage. The spec had already closed five architect +rounds, and the plan implementing it had closed thirteen plan-adversary +rounds. The audit therefore measures what a closed review loop leaves +behind, which is the claim the two-lens fresh-context design rests on. + +This file is the report's home. The report lived only in the +dispatching session's transcript, so `process-status` read the repo +clean while nine of the eleven defects waited on a decision. + +## Provenance + +The dispatch disabled the installed `working-process` plugin and ran +the unreleased agent from the working tree: + +``` +claude -p --plugin-dir plugins/working-process --agent integrity-auditor \ + --model opus \ + "Audit target: docs/specs/2026-08-17-autonomous-review-loop-design.md — this + bundle's most churned document (a restored draft plus five architect rounds + and thirteen plan-adversary waves in two days). Its sibling is + docs/specs/2026-08-27-audit-agents-design.md; the shipped surfaces are under + plugins/working-process/. Run both lenses and report." +``` + +- Ran 2026-08-29 at 14:22 UTC on branch `feature/review-loop-audits`, + working tree clean. +- The same run's `propagation-auditor` returned CLEAN on the sibling + spec and one contested hit, verified false, on the target. +- The dispatched string records what ran. The agent's self-report holds + at the rung and fails at the version, so it settles nothing finer. +- Local transcript: session `60d835b8-2000-46ad-9e24-81abca81b4d6`. + +## Dispositions + +The auditor clustered the eleven defects into five decisions. The +release applied D and E in `a998161`, which edited the spec and the +glossary. A, B and C stay open — they are design questions the audit +raised, not defects the release carries. + +| # | Defect, in the order reported below | Cluster | State | +|---|---|---|---| +| 1 | `resolved ` closes a `held` line the document never writes | A | open | +| 2 | `blocking` rounds record `fixed`, which the same section forbids | A | open | +| 3 | The propagation gate raises a held line after the only delivery moment | C | fixed on `feature/audit-errata` | +| 4 | The all-Minor signal prescribes fixing by grade | B | fixed on `feature/audit-errata` | +| 5 | `concerns (resolved )` is autonomous in one passage, offered in the next | B | fixed on `feature/audit-errata` | +| 6 | `held` carries no slot for the counter-evidence two passages require | A | slot landed on `feature/audit-errata`; the fuller `held` contract stays open | +| 7 | The closed grammar carries no deviation marker | A | open | +| 8 | The confirming round's durable marker has no anchor and no command | D | applied in `a998161` | +| 9 | The new Unfinished-work class contradicts a recorded property of the list | E | applied in `a998161` | +| 10 | The reviewer's stop signal covers all-Minor rounds only | B | fixed on `feature/audit-errata` | +| 11 | `resolved (declined)` appears in two forms | A | open | + +The three open clusters read: **A** — the ledger grammar does not cover +what the loop does, five defects. **B** — three termination passages +contradict Triage and each other, three defects. **C** — the gate breaks +the one-interruption contract, one defect. + +Four of the ten questions remain spec gaps rather than reading errors: +1, 2, 3 and 5. Question 1 closed with the errata below; 2, 3 and 5 stay +open. + +Wave one landed on `feature/audit-errata`: all three B defects, the C +defect, the `counter:` slot of defect 6, and question 1's answer — the +previous round's `fixed` lines and their `` clauses are +what a diff-scoped brief is taken against. Dropping the `[hit]` ledger +variant narrows a published convention, so the release carrying it is a +minor bump. Cluster A's remaining five defects belong to a follow-up +spec that treats the ledger as loop state. + +## The report + +Verbatim, as returned. + +--- + +Preconditions: working tree is clean (`git status --porcelain` empty), so every conversation edit is on disk. The brief does not state a propagation-audit result; nothing in it reports hits, so I proceeded rather than stopping. + +--- + +model: claude opus 5 + +--- + +## Defects + +**"The disposition ledger", ledger grammar vs. `## Review rounds` — the `resolved ` token is defined for one state and used for another, leaving `fixed` and `resolved` interchangeable with no stated rule.** + quote A: "`resolved ` — closes a held line once the answer lands. The answer's substance goes into the document's design text; the ledger line points at it and never duplicates it." + quote B: "- resolved 2026-08-27 — [Important] the ledger anchors joined the Unfinished-work list whose shipped invariant counts frontmatter hits only; landed in "The disposition ledger" (section-scoped match semantics, hardened command, one entry naming both owners)" + *(No `held` line exists anywhere in the document, so no `resolved` line can be closing one; round 2 then carries `fixed` and `resolved 2026-08-27` side by side for the same class of session-applied fix.)* + +**"Termination" vs. `## Review rounds` — the grammar has no token for a developer-directed fix, so the document's own `blocking` rounds record `fixed` (defined as self-fixed) lines, which the same section forbids.** + quote A: "`blocking` suspends autonomy entirely: relay, stamp, stop — no self-fixes from a blocking round." + quote B: "### 2026-08-27 — architect, fable 5, blocking (round 2, diff-scoped)" … "- fixed — [Important] the document state between a plan's diff-scoped LGTM and its confirming round was undefined, each reading breaking a recorded convention; license: this spec's own recovery philosophy" + *(`fixed` is defined at "The disposition ledger" as "self-fixed"; rounds 1, 2 and 3 are all `blocking`.)* + +**"Sequencing" — the propagation gate runs after the relay turn but can produce a held line, and the only stated delivery moment for held questions is the relay turn that has already passed.** + quote A: "Held set non-empty: batch the held questions into one message at the relay turn — per item: a one-line claim, why it is held, the question, and options with the session's recommendation — and wait." + quote B: "Before any re-dispatch — held set empty or developer-ordered — the propagation-auditor (audit-agents spec) gates the round when it is available … a hit the session believes is wrong escalates as held, like any contested finding — its held line carries the marker `[hit]` in the severity slot" + *(The same section states "the developer is interrupted exactly once per round"; a gate escalation is a second interruption in the same round, or none.)* + +**"Termination" vs. "Triage" — the all-Minor bullet prescribes fixing findings by grade, which the license test explicitly rules out as the basis for a fix.** + quote A: "All-Minor signal: two consecutive rounds whose findings are all Minor end the unattended run — fix the residue, annotate `concerns (resolved )`, and escalate with a fresh-round offer instead of dispatching again." + quote B: "Severity is not the line. A Minor finding can be decision-shaped (a naming call the developer already ruled on); a Critical can be self-fixable (a contradiction with a recorded ADR — the ADR is the license). Triage reads the fix's license, never the finding's grade." + +**"Termination" vs. "Termination" (loop closure) — the `concerns (resolved )` annotation is an autonomous act in one passage and an offered choice in the next.** + quote A: "All-Minor signal: two consecutive rounds whose findings are all Minor end the unattended run — fix the residue, annotate `concerns (resolved )`, and escalate with a fresh-round offer instead of dispatching again." + quote B: "Loop closure reuses existing machinery: after answers land, the session offers a fresh round (replacing the verdict as usual) or the lifecycle rule's `concerns (resolved )` annotation with its body note" + *(Under "Re-dispatch briefs" an annotation close also "ends the loop", so the difference decides whether a session may close a loop without the developer.)* + +**"The disposition ledger" vs. the grammar block — the `held` shape has no slot for the counter-evidence two other passages require it to carry.** + quote A: "`held` — needs the developer; the line carries the concrete question (or the dispute plus counter-evidence), phrased so one short answer resolves it." + quote B: " - held — [] ; question: " + *("Triage" states the same requirement independently: "A finding the session believes is wrong is held with the session's counter-evidence attached".)* + +**"Re-dispatch briefs" vs. the grammar block — the next round's brief must read deviations back out of the ledger, but the closed grammar carries no deviation marker.** + quote A: "When the ledger records a deviation from a reviewer's suggestion, the next round's brief invites refutation of the recorded rationale — the rationale is not a defence to be protected." + quote B: " - fixed — [] ; license: ; " + *(The grammar's variants are enumerated as closed: "the grammar's one severity-token variant" and "the grammar's one heading annotation".)* + +**"Re-dispatch briefs" vs. "The disposition ledger" — the heading that marks a plan's owed confirming round is named the durable marker, but no anchor or command detects it.** + quote A: "the `### , , LGTM (round N, diff-scoped)` heading is the durable marker that a confirming round is owed" + quote B: "Two greppable anchors join the lifecycle rule's unfinished-work discipline: `open` lines (a stamped round whose remediation never ran) and `held` lines (pending developer questions)." + *(The mandated command is `rg -n --no-ignore --crlf '^- (open|held) —' docs/`, which matches no heading; the recovery clause itself concedes "an annotation-closed or previously-approved document is grep-clean there".)* + +**"The disposition ledger" / "Changes by file" vs. the glossary's Unfinished-work list entry — the new class is given non-frontmatter match semantics and costs a consumer edit, contradicting a recorded property of the list, and no glossary edit is routed.** + quote A: "The entry deliberately re-scopes the list's frontmatter-only invariant for itself: its hits count inside a `## Review rounds` section and nowhere else" … "`plugins/working-process/skills/process-status/SKILL.md` — the hit-confirmation step takes an entry's own published match scope when the entry re-scopes it" + quote B (`docs/domain/glossary.md`, **Unfinished-work list**): "the single definition site for which classes exist, so a new class costs one edit in the rule and none in the consumers that run it. A command's output is hits to confirm against the frontmatter block, never Findings." + +**"Re-dispatch briefs" vs. `## Review rounds` closing paragraph — the reviewer's stop signal is defined only for an all-Minor round, and the document's own loop closes on it after a round whose single finding is Important.** + quote A: "asks the reviewer for its own stop signal: when the round's remaining findings are all Minor wording residue, say so and judge whether another round is worth its cost." + quote B: "Loop closed 2026-08-27 by the resolution annotation, on round 5's own alternative: the single finding was a two-clause routing edit with no design content, fixed as suggested, and the whole-text backstop is the consumption gate's integrity audit this release ships" + *(Round 5's only line reads "- fixed — [Important] the round-4 gate behavior was fully designed in the body and routed to no file edit".)* + +**"The disposition ledger" — the declined-resolution token is given two forms, one dated and one not, in the same section that calls the shape canonical.** + quote A: "`resolved (declined)` records the developer keeping the document as it was." + quote B: " - resolved (declined) — [] ; " + +--- + +## Ranked implementer questions + +1. **What is a diff-scoped brief's diff taken against?** "briefed on what changed since the round it follows" names no source for the previous state — no snapshot, no commit, no recorded hash — and the lifecycle rule keeps these documents deliberately uncommitted through the review rounds. Without an answer the central mechanism of "Re-dispatch briefs" cannot be built. +2. **How do the two release-mates' consumption-gate offers compose in `workflow.md`?** The audit-agents spec fires the integrity-audit offer only on an `integrity:` body-hash mismatch ("a match meaning the standing stamp satisfies the gate"); this spec fires the pair question on any diff-scoped-chain LGTM. Which governs a spec carrying both a matching stamp and a diff-chain LGTM? +3. **Is the confirming full-document round after a plan's diff-scoped LGTM autonomous, and does it count against the three-round cap?** It is prescribed as mandatory ("one full-document confirming round follows"), which sits oddly with both the cap and the every-step-is-an-offer ethos. +4. **When a contested `[hit]` escalates at the propagation gate, does the round wait for the answer, and does that escalation reset the cap count?** The gate is specified to "repeat until the audit comes back clean", a state a contested hit never reaches. +5. **What counts as "developer contact" for the cap reset?** A held batch the developer has not yet answered, a relay the developer read silently, and the cap escalation itself are all candidates, and the choice decides whether the cap can ever bind. +6. **What is the exact vocabulary and case of the `[]` slot?** The glossary fixes `critical | important | minor` in lowercase; the document's own ledger writes `[Important]` and `[Minor]`, and the one variant `[hit]` is lowercase. The deferred grammar lint depends on this. +7. **What shape does a single Unfinished-work entry with two owners take?** The list's entry format is "class name, grep command, and the owner of the next move" (singular); this spec routes one entry "whose entry text names both owners", and `process-status` must render it. +8. **What distinguishes "not now" from "not in this session" in the consent question,** given the same sentence says the session "asks once per Claude Code session … and honours the answer without re-asking"? +9. **What closes the loop when a held answer lands and the developer accepts neither the fresh round nor the annotation?** Both arms are offers; the document names no third state and no `resolved` line can be written without one of them. +10. **Are ledger lines flush-left or indented?** The canonical block is presented indented four spaces while the mandated command anchors on `^-`; the difference decides whether the document's own grammar block is self-matching. + +--- + +coverage: 429 lines; highest line cited 429 From 483fc272182634da119f24a189f28633427a4bb8 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Tue, 1 Sep 2026 16:28:49 +0200 Subject: [PATCH 042/126] feat(working-process): errata wave one - gate lines, revises field, loop terminators --- docs/domain/glossary.md | 5 +- .../2026-08-31-review-loop-errata-wave-one.md | 216 ++++++++++++++++++ .../.claude-plugin/plugin.json | 2 +- plugins/working-process/README.md | 4 +- .../agents/integrity-auditor.md | 17 +- .../agents/propagation-auditor.md | 6 +- .../rules/spec-plan-lifecycle.md | 83 ++++++- plugins/working-process/rules/workflow.md | 71 ++++-- 8 files changed, 363 insertions(+), 41 deletions(-) create mode 100644 docs/specs/2026-08-31-review-loop-errata-wave-one.md diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 6dad1be..cd7a30a 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -278,8 +278,9 @@ An agent whose report ends in no verdict and stamps nothing: it checks a document and returns material for the dispatcher's disposition — hits (`propagation-auditor`, the mechanical pass) or defects-with-quotes and ranked questions (`integrity-auditor`, the judgment pass). Dispatched as -a gate before expensive work — a clean audit is a precondition, never a -judgment on the design. The third dispatch category beside Verdict agent +a gate before expensive work: the precondition is a disposed audit — +every hit fixed or dismissed, every defect applied or declined — never +an empty one, and never a judgment on the design. The third dispatch category beside Verdict agent and Consultation: an audit agent adopts no persona and its output is never a Contribution. _Avoid_: sweep agent, verifier diff --git a/docs/specs/2026-08-31-review-loop-errata-wave-one.md b/docs/specs/2026-08-31-review-loop-errata-wave-one.md new file mode 100644 index 0000000..df3ec76 --- /dev/null +++ b/docs/specs/2026-08-31-review-loop-errata-wave-one.md @@ -0,0 +1,216 @@ +--- +ticket: none +date: 2026-08-31 +status: draft +architect: blocking (adjudicated 2026-09-01) +revises: ./2026-08-17-autonomous-review-loop-design.md +branch: feature/audit-errata +base: develop +--- + +# Review loop — errata wave one + +## Problem + +An integrity audit of the autonomous review loop returned eleven +defects, each proved by two quotes. Two were applied before the 0.14.0 +release; nine stayed open. Three of those nine put the shipped rules in +contradiction with themselves, so the loop's own text tells a session +two different things at the same moment. They are cheap to remove and +cost nothing to decide, which is what separates this wave from the +follow-up spec. + +The full report, its provenance, and the disposition of all eleven +defects live in +[`docs/audits/2026-08-29-autonomous-review-loop-integrity-audit.md`](../audits/2026-08-29-autonomous-review-loop-integrity-audit.md). +This document is the record of the wave, not a second copy of the audit. + +## Scope + +Six changes, all in `plugins/working-process/`: + +1. **B6** — the all-Minor signal no longer prescribes fixing by grade. + It said "Fix the residue"; the same rule says triage reads the fix's + license, never the finding's grade. The bullet now routes the round + through ordinary triage. +2. **B7** — a session may no longer close the loop alone. The all-Minor + escalation is a question, so the resolution annotation records the + developer's close and no session writes it without their answer. +3. **B8** — the reviewer's stop-signal ask lost its all-Minor + precondition and now stands every round. A round can leave one + Important behind and still not repay a re-read. +4. **C9** — a contested propagation hit is dismissed with a written + counter-derivation and reported, never escalated as a held line. A + hit is a report, not a question, so it never spends the round's one + interruption. The `[hit]` severity-slot variant leaves the ledger. +5. **A3, first half** — the `held` shape gained a `counter:` clause. + Two passages required a held line to carry counter-evidence and the + closed grammar had no slot for it. +6. **Implementer question 1** — a diff-scoped brief's diff is taken + against the previous round's `fixed` lines and their `` + clauses. These documents stay uncommitted through the rounds, so the + ledger is the only durable account of the diff. + +Round 2 added a seventh change the wave had to absorb: the propagation +gate needed a record of its own. Removing the `[hit]` variant had traded +a wrong shape for no shape, leaving the gate's ordinary case — a hit +found and fixed — with no home, no heading, and no route into the next +round's brief. The "Gate lines" subsection supplies both shapes. + +Cluster A's five remaining defects are out of scope: they are one +unwritten state machine and belong to a follow-up spec treating the +ledger as loop state. Implementer questions 2, 3 and 5 stay open there +too, and four seams are carried to it: + +- **Are gate episodes first-class ledger units?** Round 2 raised it and + round 3 showed it doing unfunded work: the outstanding-hit state has + no shape, which this wave ships as a stated gap rather than closing by + accident. +- **Round 1 of this wave is a live instance of open defect A2** — a + `blocking` heading under which every line is `fixed`, which the + shipped rule forbids, produced under those rules by the session + repairing them. The terminator is either wrong or unenforceable as + written. +- **The glossary has no owner on the fix-wave path.** Three collisions + in one wave; the grilling-session, its only maintainer, fires at spec + authoring. The candidate placements are triage — a `fixed` line whose + license is a glossary term, or whose change moves a term's meaning, + owes a glossary check on the same line — or a standing enumeration + target for the propagation gate, which reaches only the quoting case. +- **A stop signal cannot bind text that did not exist when it was + given.** Round 3's own words, and a better argument than the one this + wave used to override round 2: a stop signal judges the marginal value + of re-reading a document, and round 3 found a Critical in a subsection + no reviewer had seen. New design written after a stop signal should + re-arm review rather than override it, and the signal should be scoped + to the text it read. + +## Decisions taken during the wave + +**The oscillation tripwire keeps its held line.** The wave's reach for +change 4 was approved as general, on a recorded claim that the tripwire +carried the same defect. It does not: the tripwire fires inside triage, +before the round's relay, so its held line joins the single batch and +spends no second interruption — and what it escalates is a developer +decision about which reading of a license wins, not a mechanical hit. +It was instead connected to change 5: its named flip is the evidence +the new `counter:` clause carries. The architect round confirmed the +call. + +**The shipped spec and plan stay as they are.** A propagation gate +found eight sites where +`docs/specs/2026-08-17-autonomous-review-loop-design.md` still +describes the pre-errata design. The drift is real. The session first +fixed all eight, on a false claim that an earlier commit had set a +precedent for amending an implemented spec; that commit edited the +document while it still carried `status: draft`. The edits were +reverted. The hits are dismissed instead: the spec records what shipped +in 0.14.0, and its architect verdict certifies the body text, which an +`integrity:` hash covers exactly. Editing the body would leave a stamp +pointing at text no reviewer read. This document's `revises:` field +carries the pointer instead. + +**`revises:` was chosen over `superseded-by:`.** The architect proposed +a forward pointer on the older document. The developer rejected the +name as overstating a partial departure, and rejected a general +`references:` field as collapsing the distinction between lineage and +supersession. `revises:` points backward from the newer document, so no +stamped document is touched at all, and the lifecycle rule now carries +both the field and the principle that makes it sufficient: an +implemented document is an archive, and the surfaces it named are the +current truth. + +## Changes by file + +- `plugins/working-process/rules/workflow.md` — the propagation gate + (dismissal, the written line, the two-re-dispatch bound, the pass + condition), the re-dispatch briefs (the diff reference point, the + unconditional stop-signal ask), and the all-Minor terminator. +- `plugins/working-process/rules/spec-plan-lifecycle.md` — the `held` + shape's `counter:` clause, the "Gate lines" subsection with its + `hit fixed` and `hit dismissed` shapes and their placement rule, the + removal of the `[hit]` variant, the `revises:` and `spec:` fields, the + implemented-document principle, and the "Finding what revises a + document" lookup. +- `plugins/working-process/agents/integrity-auditor.md` — the + propagation precondition and its STOP clause, plus the two surfaces + stating the integrity audit's own bar as applied dispositions rather + than a clean run. +- `plugins/working-process/agents/propagation-auditor.md` — the gate's + pass condition in the description and the opening paragraph. +- `plugins/working-process/README.md` — the gate's pass condition. +- `plugins/working-process/.claude-plugin/plugin.json` — the dogfooding + version `0.14.0-dev.audit-errata`. + +Dropping the `[hit]` variant narrows a published convention, so the +release carrying this wave takes a minor bump rather than a patch. + +## Review rounds + +### 2026-08-31 — architect, opus 5, blocking (round 1, full-document) + +- fixed — [Important] the gate's pass condition moved to "no confirmed hit remains" in one place and stayed "clean" in five others, one of which instructs the integrity auditor to stop; license: the change's own terminal condition, which the same paragraph contradicts; all six sites now state the passing bar, and `clean` survives only as the auditor's `CLEAN` output token +- fixed — [Important] removing the `[hit]` line left a dismissed hit with no durable record, against the rule's own "state prevents relitigation, not the reviewer's memory"; license: that sentence, plus the implementing plan's re-dispatch bound the rule had dropped; a `dismissed` line outside the finding grammar, and the two-re-dispatch bound restored +- fixed — [Minor] "the round's relay" had no referent before an integrity audit, which is not a round; license: the gate's own list of three firing points; now "the next report the session relays to the developer" +- fixed — [Minor] the `counter:` clause admitted only a finding the session disputes, while the tripwire case is one where it takes no side; license: the tripwire's own definition as a contested reading; widened to "disputed or contested" +- fixed — [Minor] "no session writes it on their behalf" forbade the session from writing the annotation at all, against the writing model everywhere else; license: the lifecycle rule's definition of the annotation as a dispatcher-written artifact; now "without their answer" +- dismissed 2026-08-31 — eight sites in the shipped spec and plan still describe the pre-errata design; counter: both carry `status: implemented` and record what shipped in 0.14.0, and the spec's architect verdict certifies a body an `integrity:` hash covers, so a body edit would un-certify text a reviewer did read; `revises:` carries the pointer instead + +### 2026-09-01 — architect, opus 5, blocking (round 2, diff-scoped) + +Two gate episodes precede this round. The first died on an SSL failure +before returning; per the workflow rule an infrastructure death is an +ordinary error, re-dispatched fresh and never resumed, consuming no cap +budget. Its partial output named one hit, confirmed by hand, and a hand +check found a second of the same class. The second episode ran clean of +its own and returned two more. + +- hit fixed 2026-08-31 — the new `revises:` field joined the process-field set without joining the Misplaced-stamp class's published command; the field name joined the command's alternation, and round 2 then reversed this as finding four +- hit fixed 2026-08-31 — the `dismissed` line shape entered the round record without the Unfinished-work list stating whether it joins the anchors; the rule now says it stays out, because a dismissal is closed when written and owes nobody a next move +- hit fixed 2026-08-31 — this document's own `architect:` value read `blocking (2026-08-31, round 1)`, a form the grammar does not define, so the Unresolved-verdict command — anchored on `$` after the verdict — did not match it and the wave record hid its own open verdict from the sweep; the value became bare `blocking` with the round detail staying in the round heading, and the adjudication annotation replaced it at close, in the form the rule defines +- hit dismissed 2026-08-31 — `integrity-auditor.md` lines 3 and 11 still say "a clean audit is a precondition"; counter: both name the integrity audit gating plan-writing ("the work **it** gates"), not the propagation gate this wave re-phrased, and the parallel lines in `propagation-auditor.md` were both changed because both name the gate. Round 2 sharpened the claim: `clean` is loose there too, since the real bar is an applied-dispositions stamp, and the wording is corrected rather than defended +- hit fixed 2026-09-01 — the authoring-time gate after the fix wave reported this document's `architect:` value as contradicting a ledger line that called the value bare `blocking`; the contradiction was real and its direction inverted — `blocking (adjudicated 2026-09-01)` is the form the rule defines, and the ledger line had gone stale at the adjudication; the line now records both states +- hit fixed 2026-09-01 — the same episode had no landing place under the placement rule this wave had just written, which covered only a gate preceding a round; the developer settled it as the next round's heading, falling back to the last round's where no next round comes — an authoring-time audit or a document closing on an annotation +- hit fixed 2026-09-01 — the glossary's **Audit agent** entry still read "a clean audit is a precondition", the exact phrasing both agent cards moved away from in this wave, leaving the canonical definition site stale against its own instances; the entry now states the precondition as a disposed audit — every hit fixed or dismissed, every defect applied or declined — the general form covering both agents' specific bars + +- resolved 2026-09-01 — [Important] a fixed propagation hit had no ledger line, so the diff-scoped brief's stated diff source could not see gate work; this document proved the hole by writing `- fixed — [hit]` lines in a severity slot the same wave deletes; landed in "Gate lines" (a `hit fixed` shape beside `hit dismissed`, both carrying their own leading token and no severity) +- resolved 2026-09-01 — [Important] the gate lines' placement had no referent before round 1 or before a round not yet dispatched; landed in "Gate lines" (they attach to the next round's heading and are written at its stamp, falling back to the last round's where no next round comes, rather than inventing a heading the closed grammar does not define). The first answer covered only a gate preceding a round; the authoring-time audit that followed this wave had no landing place under it, and the fallback closed that third case +- resolved 2026-09-01 — [Important] the two-re-dispatch bound did not say whether it counted per document or per gate episode, and "escalates" was undefined; landed in "The propagation gate" (per episode, no third attempt, and the outstanding hits reported with a dismissal's standing while the gated dispatch is held — a report the developer may override, never a second question) +- resolved 2026-09-01 — [Important] `revises` had joined the Misplaced-stamp command against the glossary's enumerated definition of the class as stamped fields "where the stamping steps put it"; landed in the Unfinished-work list (the alternation reverted, the class left stamp-only, the glossary untouched — `revises:` is authored like `branch:`, `base:` and `spec:`, none of which the class covers) +- resolved 2026-09-01 — [Minor] the dismissal of `integrity-auditor.md` proved the referent but not the claim; landed in `integrity-auditor.md` (both surfaces now say "an audit whose dispositions are applied", the bar the lifecycle rule actually sets) +- resolved 2026-09-01 — [Minor] `revises:` was unreachable from the document whose staleness it concerns, and `spec:` was carried by every plan and defined by no rule; landed in "Finding what revises a document" (a published reverse lookup mirroring the ticket sweep) and the frontmatter block (`spec:`, marked plans-only) + +Round 2 asked for its own stop signal and answered that a third round +would not earn its cost: `blocking` suspends autonomy by the loop's own +terminator, and the leftovers were developer decisions rather than +wording residue another round would sharpen. The developer took all six +on 2026-09-01, which licensed the fixes above, and closed the verdict by +adjudication rather than a fresh round — the path the terminator exists +to route work into. That close was superseded when round 3 ran; the +adjudication had assumed no further round. + +### 2026-09-01 — architect, opus 5, blocking (round 3, diff-scoped) + +Dispatched over round 2's stop signal, on the argument that both its +premises had expired. Round 3 judged the override justified and supplied +a better argument for it, recorded as a seam below. + +- resolved 2026-09-01 — [Critical] gate lines were written "when that round is stamped", later than both purposes the wave assigns them: the workflow rule makes the written line the thing that terminates the episode, and the next diff-scoped brief is composed before the round it belongs to is stamped. The discriminator "where no next round comes" was a fact about the future, undecidable at write time, and this document's own seven gate lines took the fallback branch — the practice was sound and the text described a different, broken procedure; landed in "Gate lines" (written at gate time under the last round's heading, the date token telling episodes apart from the round's findings, with one deferral for a gate before a document's first round; the fallback and its predicate are gone) +- resolved 2026-09-01 — [Important] the re-dispatch brief's published diff source named only `fixed` lines, so `hit fixed` lines fell outside it; landed in "Re-dispatch briefs" (the source now reads the round's `fixed` lines together with any gate lines under the same heading) +- resolved 2026-09-01 — [Minor] `hit fixed` dropped the `license:` clause its sibling shape declares mandatory without the definition site saying why; landed in "Gate lines" (one clause: neither shape carries a license, because a hit's fix is licensed by its own derivation) +- resolved 2026-09-01 — [Minor] the published `revises:` example used a plan-relative path, wrong for the field's commonest case; landed in the frontmatter block (`./.md`, leaving `../specs/` to `spec:`, which is genuinely plans-only) +- resolved 2026-09-01 (declined) — [Important] the two-re-dispatch bound produces an outstanding-hit state no shape carries and no anchor surfaces; the document stands with the gap stated rather than closed: "Gate lines" now says outright that neither shape covers it, that it owes the developer a decision, and that the workflow rule's report is its only record until a shape exists. Designing that shape is the wave-two question of whether gate episodes are first-class ledger units, and answering it here would decide wave two by accident +- resolved 2026-09-01 (declined) — [Important] the glossary has no owner on the fix-wave path — the grilling-session fires at spec authoring, so an errata wave editing shipped rules bypasses it, and two of this wave's three instances were semantic where no mechanical pass could reach; the document stands because the fix is a process change to triage or to the gate's standing targets, not a wording change to this wave, and it is carried to wave two's list + +Round 3's stop signal: no fourth round, and its reasons do not expire — +the Critical's repair is demonstrated by this document's own ledger and +needs no reviewer to confirm it, two findings are single-clause edits, +and two are decisions a fresh reviewer would restate rather than +resolve. + +Seam for wave two, in round 3's words: a stop signal cannot bind text +that did not exist when it was given. It judges the marginal value of +re-reading a document, and this round found a Critical in a subsection +no reviewer had ever seen. New design written after a stop signal +re-arms review rather than overriding it, and a stop signal should be +scoped to the text it read. diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index 78b950b..e8589bb 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, propagation-auditor and integrity-auditor audit agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0", + "version": "0.14.0-dev.audit-errata", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index a972e63..9a58708 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -59,8 +59,8 @@ verdict dispatch and the integrity audit itself. nothing, ends in no verdict, and stamps nothing. Dispatched in the background on the cheapest available family, because every duty is procedural; the workflow gates every verdict-agent dispatch and every - integrity audit on a clean run, and offers the same audit at - authoring time after any multi-site edit. + integrity audit on a passing run — no confirmed hit outstanding — and + offers the same audit at authoring time after any multi-site edit. - **`integrity-auditor` agent** — the judgment audit of a churned document, read on a fresh context: the document against itself, then the document as an implementer who must build from that text alone. diff --git a/plugins/working-process/agents/integrity-auditor.md b/plugins/working-process/agents/integrity-auditor.md index b7e55c0..681fd38 100644 --- a/plugins/working-process/agents/integrity-auditor.md +++ b/plugins/working-process/agents/integrity-auditor.md @@ -1,6 +1,6 @@ --- name: integrity-auditor -description: "Judgment audit of a churned design document, read on a fresh context — primarily a spec at the consumption gate before plan-writing: reads the document against itself, verifies in both directions every rule the document declares about itself, and reads it once more as an implementer who must build from this text and has no other context. Returns defects each proved by two quotes, plus a separate section of ranked implementer questions, plus the coverage tell that exposes a partial read. Verdict-free and persona-free: it grades nothing and stamps nothing, so a clean audit is a precondition for the work that follows, never a judgment on the design. Dispatch on the most capable available tier, named explicitly, and in a fresh context — the auditor must not inherit the session that churned the document. Runs in the background; the report arrives as a task notification." +description: "Judgment audit of a churned design document, read on a fresh context — primarily a spec at the consumption gate before plan-writing: reads the document against itself, verifies in both directions every rule the document declares about itself, and reads it once more as an implementer who must build from this text and has no other context. Returns defects each proved by two quotes, plus a separate section of ranked implementer questions, plus the coverage tell that exposes a partial read. Verdict-free and persona-free: it grades nothing and stamps nothing, so an audit whose dispositions are applied is a precondition for the work that follows, never a judgment on the design. Dispatch on the most capable available tier, named explicitly, and in a fresh context — the auditor must not inherit the session that churned the document. Runs in the background; the report arrives as a task notification." background: true --- @@ -8,8 +8,9 @@ The judgment pass over a document — the integrity audit. Your deliverable is a list of defects, each proved by two quotes, and beside it a ranked list of the questions an implementer would have to ask before building. You adopt no persona and you return no verdict. Your report is material -for the dispatcher's disposition, and the work it gates treats a clean -audit as a precondition, never as a judgment on the design. +for the dispatcher's disposition, and the work it gates treats an audit +whose dispositions are applied as a precondition, never as a judgment on +the design. ## First action: the domain artifacts @@ -54,11 +55,13 @@ confirm both: - **Every edit from the conversation is written to disk.** Your deliverable is a text-to-text comparison, so one unsaved decision manufactures a run of false defects. -- **The propagation audit is clean**, when that agent is available, so - this expensive read never spends itself policing arithmetic. +- **The propagation gate has passed**, when that agent is available, + leaving no confirmed hit, so this expensive read never spends itself + policing arithmetic. A hit the dispatching session dismissed with a + written counter-derivation does not hold the gate shut. -If the brief leaves a precondition unmet — pending edits, a propagation -audit that returned hits — say so in one line and stop. A run against a +If the brief leaves a precondition unmet — pending edits, a confirmed +hit still outstanding — say so in one line and stop. A run against a stale file wastes the tier and returns defects the developer has already fixed. diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 8cfafa9..9128ffb 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -1,6 +1,6 @@ --- name: propagation-auditor -description: "Mechanical propagation audit of a spec or plan before an expensive dispatch: parses changed interfaces to enumerate their consumers, diffs every prescribed block against the file it targets, re-derives every counter, and returns located hits with their derivation — or the single line CLEAN. Verdict-free and persona-free: it stamps nothing and grades nothing, so a clean audit is a precondition for the dispatch that follows, never a judgment on the design. Dispatch before every verdict-agent dispatch, after a fix wave, before an integrity audit, and after any multi-site edit during authoring. Run it on the cheapest available family, named explicitly — every duty is procedural, and the never-cheapest rule governs reviews, which an audit is not. Runs in the background; the report arrives as a task notification." +description: "Mechanical propagation audit of a spec or plan before an expensive dispatch: parses changed interfaces to enumerate their consumers, diffs every prescribed block against the file it targets, re-derives every counter, and returns located hits with their derivation — or the single line CLEAN. Verdict-free and persona-free: it stamps nothing and grades nothing, so a passing gate is a precondition for the dispatch that follows, never a judgment on the design. Dispatch before every verdict-agent dispatch, after a fix wave, before an integrity audit, and after any multi-site edit during authoring. Run it on the cheapest available family, named explicitly — every duty is procedural, and the never-cheapest rule governs reviews, which an audit is not. Runs in the background; the report arrives as a task notification." background: true --- @@ -8,8 +8,8 @@ The mechanical pass over a document — the propagation audit. Your deliverable is a list of hits: located, binary detections, each carrying the derivation that produced it. You adopt no persona and you return no verdict. Your report is material for the dispatcher's disposition, and -the dispatch it gates treats a clean audit as a precondition, never as a -judgment on the design. +the dispatch it gates treats a passing gate as a precondition, never as +a judgment on the design. ## First action: the domain artifacts diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 5632ff9..0ae975c 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -19,6 +19,8 @@ architect: LGTM # optional: latest architect verdict (LGTM | concerns | bloc adversary: LGTM # optional: latest plan-adversary verdict (LGTM | concerns | blocking) architect-fallback: (degraded ) # optional: verdict above produced below the prescribed tier (adversary-fallback: for plans) integrity: (sha: ) # optional: date of the last integrity audit, plus the body hash it certifies +revises: ./.md # optional: documents this one departs from; inline list when several +spec: ../specs/.md # plans only: the spec this plan implements; inline list when several branch: feature/ABC-123-short-name # optional: topic branch of the work base: master # optional: branch the topic branch was cut from --- @@ -27,6 +29,18 @@ base: master # optional: branch the topic branch was cut from - `status` is linear and moves forward only. Review rounds are iterative and live in their own fields; `grilled`, `architect`, and `adversary` appear only once the corresponding step has run. +- An `implemented` document records what shipped at its release, and the + surfaces it named are the current truth. Never build from one without + diffing it against those surfaces first — the document is the archive, + not the specification of what stands today. It is amended only in + frontmatter, never in the body: a verdict certifies the body it was + given, and an `integrity:` hash covers exactly that text. +- `revises:` names the documents a newer one departs from — written on + the newer document, pointing back, and never on the older one, which + stays as its stamps left it. It records supersession, not lineage: a + document that merely builds on another says so in its prose, and a + plan's `spec:` pointer is lineage too. What `revises:` claims is that + the named document's design no longer matches what shipped. - A round that ends in `concerns` or `blocking` records its findings (or their disposition) in the document body — a verdict whose findings were never written down cannot be honestly resolved later. @@ -84,6 +98,19 @@ base: master # optional: branch the topic branch was cut from - `branch` and `base` appear once the topic branch exists — never guessed up front, omitted entirely when there is no topic branch. +## Finding what revises a document + +`revises:` points backward only, so the documents that departed from a +given one are found by sweeping for it. The line matches both the +single-reference and inline-list forms, `--no-ignore` reaches +ignored-mode artifacts, and the tolerant leading anchor finds the field +where a second writer relocated it: +`rg -l --no-ignore --crlf '^\s*revises:.*' docs/` + +This is a lookup, not an Unfinished-work entry: a `revises:` pointer +owes nobody a next move, and the implemented-document principle above +already warns every reader of an archived document without it. + ## The disposition ledger The body record a `concerns` or `blocking` round owes has a canonical @@ -103,7 +130,7 @@ Under the heading each finding takes one line, its disposition the leading token: - fixed — [] ; license: ; - - held — [] ; question: + - held — [] ; question: [; counter: ] - open — [] - resolved — [] ; landed in
- resolved (declined) — [] ; @@ -117,23 +144,65 @@ leading token: citation goes on the line. No citable license means the finding is held, and a finding that could go either way is a decision. - `held` — the finding needs the developer. The line carries the - concrete question, or the dispute plus the session's counter-evidence, - phrased so one short answer resolves it. + concrete question, phrased so one short answer resolves it. Where the + finding is disputed or contested, the `counter:` clause carries the + evidence the developer needs in order to answer, so the dispute and + the question travel on one line. The oscillation tripwire's named + flip is that evidence. - `resolved ` — closes a held line once the answer lands. The answer's substance goes into the document's design text; the ledger line points at it and never duplicates it. `resolved (declined)` records the developer keeping the document as it was. -Two variants extend those shapes, and nothing else does. A contested hit -from the `propagation-auditor` agent, when it is available, takes the -held shape with `[hit]` in the severity slot, because a hit stays -ungraded even when contested. A spec whose developer accepts a +One annotation extends those shapes, and nothing else does. A spec whose +developer accepts a diff-scoped chain at the consumption gate gains `, chain accepted ` on that round's LGTM heading: the dispatcher appends it there on the decline, and its presence defeats the gate's re-ask, as `, waived ` defeats the re-review offer. +### Gate lines + +The propagation gate, when that agent is available, writes two shapes of +its own. They carry their own leading token and never a severity, because +a hit is a located detection the dispatcher confirms or dismisses, never +a graded finding: + + - hit fixed ; + - hit dismissed ; counter: + +Neither carries a license either, because a hit's fix is licensed by its +own derivation. + +Both are written at gate time, under the last round's heading. The date +each line carries tells a gate episode apart from that round's own +findings, so a gate never mints a heading of its own — the round +heading's grammar is closed, and a gate is not a round. Writing at gate +time is what the lines are for: a dismissal must exist while the episode +is still re-dispatching, or the gate cannot terminate, and the next +diff-scoped brief is composed before its own round is stamped. A gate +before a document's first round has no heading to write under; its lines +wait for that round and are written at its stamp, the one case where +they do. + +A gate episode always lands somewhere: its lines are the reason a later +reader need not re-derive what the session already settled. + +Neither shape covers a hit left outstanding when the re-dispatch bound +in the workflow rule stops an episode. That state owes the developer a +decision, so neither `hit fixed` nor `hit dismissed` can honestly carry +it, and no anchor surfaces it today — a stated gap, not an oversight. +Until a shape exists, the workflow rule's report is its only record. + +A `hit fixed` line puts the gate's ordinary work where the next +diff-scoped brief already looks, beside the round's `fixed` lines. A +`hit dismissed` line records a decision the developer was never asked to +make, so a later round cites it instead of re-deriving it and a session +that would dismiss the same hit differently argues against written words +rather than silence. Neither joins the unfinished-work anchors: both are +closed when written and owe nobody a next move. + A resolved held line is a recorded decision. When a later round re-raises the problem it settled, the new finding is folded and cited against that line, never asked again — state prevents relitigation, not the diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index e28f991..fb9c415 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -47,7 +47,8 @@ disables its suggestion — never the work itself. confirms the auditor's two preconditions: every edit from the conversation is written to disk, since one unsaved decision manufactures a run of false defects; and the propagation gate below - is clean, when that agent is available. Then write the + has passed, leaving no confirmed hit, when that agent is available. + Then write the implementation plan with superpowers:writing-plans when available; plans live in `docs/plans/`. 5. **Plan → adversary review.** Before implementing a non-trivial plan, @@ -230,19 +231,40 @@ per round, and only over a decision that is genuinely theirs. ### The propagation gate -When the `propagation-auditor` agent is available, a clean propagation -audit is the precondition for the dispatches it gates: the session +When the `propagation-auditor` agent is available, a passing propagation +gate is the precondition for the dispatches it gates: the session dispatches the audit over the document, fixes its hits, and repeats -until the audit returns no hits, so an expensive reader only ever meets +until no confirmed hit remains, so an expensive reader only ever meets a mechanically consistent document. The gate fires before every verdict-agent dispatch, first rounds included — authoring errors exist before any repair; after a fix wave, before the next round; and before an integrity audit. A hit's fix is licensed by its own derivation — a recounted counter and an enumerated missed call site decide -themselves — so hits never wait for the developer; a hit the session -believes is wrong escalates as held, its line carrying `[hit]` in the -severity slot, because a hit stays ungraded even when contested. -Without the agent installed, every dispatch proceeds as it did before. +themselves — so hits never wait for the developer. + +A hit the session believes is wrong is dismissed, never silently: the +session writes the `dismissed` line the spec-plan-lifecycle rule +defines and reports the dismissal in the next report it relays to the +developer. A hit is a report, not a question, so it never enters the +held batch and never spends the round's one interruption — the +developer reads the dismissal and keeps their standing veto over it. +The written line is what makes the gate terminate: a dismissed hit +recurs on every re-dispatch, so a gate waiting on a hitless audit would +wait forever, and a dismissal nobody wrote down would be re-derived +from nothing every round. Both dispositions take the gate lines the +spec-plan-lifecycle rule defines. + +Two re-dispatches bound one gate episode — the run before a single +dispatch, never the document's lifetime, so every round gets its own +gate. A third is not attempted. The session reports the hits still +outstanding, with the standing of a dismissal, and holds the dispatch +the gate was guarding: a gate that cannot come clean has not done the +one job the expensive reader depends on. The report names what keeps +recurring, since fixes breeding fresh hits is the failure this bound +exists to catch. It stays a report — the developer may order the +dispatch anyway, as they may order any step — so it never becomes a +second question in a round that already spent its one. Without the +agent installed, every dispatch proceeds as it did before. ### Re-dispatch briefs @@ -252,16 +274,24 @@ directs the reviewer to attack the previous wave's fixes first, and forbids re-reviewing the rest — repair-born defects are the dominant late-round class, and diff-scoping also ends stale-read findings. +The ledger supplies what changed. The previous round's `fixed` lines and +their `` clauses, together with any gate lines under the +same heading, are the record of that wave, so the brief cites them and +needs no snapshot, commit, or hash — these documents stay uncommitted +through the rounds, and the ledger is the only durable account of the +diff. + Every brief states the loop's terminators outright — the cap and the all-Minor signal below — rather than improvising them late, and asks -the reviewer for its own stop signal: when the round's remaining -findings are all Minor wording residue, say so and judge whether -another round earns its cost. That judgment concerns the next round's -marginal value, never whether the document is good enough, and it -informs the developer's decision rather than replacing it. Where the -ledger records a deviation from a reviewer's suggestion, the brief -invites refutation of the recorded rationale — a rationale is evidence -to attack, never a defence to protect. +the reviewer for its own stop signal: judge whether another round earns +its cost, and say what the round's leftovers are worth. The ask stands +every round, whatever grades the findings carry — a round can leave one +Important behind and still not repay a re-read. That judgment concerns +the next round's marginal value, never whether the document is good +enough, and it informs the developer's decision rather than replacing +it. Where the ledger records a deviation from a reviewer's suggestion, +the brief invites refutation of the recorded rationale — a rationale is +evidence to attack, never a defence to protect. ### Terminators @@ -276,9 +306,12 @@ to attack, never a defence to protect. fixed, what remains, why — rather than halting silently, and any developer contact resets the count. - All-Minor signal: two consecutive rounds whose findings are all Minor - end the unattended run. Fix the residue, annotate - `concerns (resolved )`, and escalate with an offer of a fresh - round instead of dispatching one. + end the unattended run. Triage the round as always — by license, never + by grade — and escalate with an offer of a fresh round instead of + dispatching one. The escalation is a question, so the loop stays open + until the developer answers it: the resolution annotation the + spec-plan-lifecycle rule defines records their close, and no session + writes it without their answer. - Oscillation tripwire: a finding re-raised against a `fixed` line is never re-fixed autonomously. Two readings of one license are a contested reading, so it escalates as held, the flip named. From 03f7fcb2fd1c4d23fb50a6d20d7f5f53d8fafb0c Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 11:56:40 +0200 Subject: [PATCH 043/126] docs: wave-two spec draft - the disposition ledger as finding state --- ...26-09-02-ledger-as-finding-state-design.md | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 docs/specs/2026-09-02-ledger-as-finding-state-design.md diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md new file mode 100644 index 0000000..1f7f89c --- /dev/null +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -0,0 +1,251 @@ +--- +ticket: none +date: 2026-09-02 +status: draft +revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-08-31-review-loop-errata-wave-one.md] +branch: feature/audit-errata +base: develop +--- + +# The disposition ledger as finding state + +## Problem + +An integrity audit of the autonomous review loop proved eleven defects. +Wave one closed the contradictions that made shipped rules disagree with +themselves. Five stayed open as one cluster, because they share a cause: +the ledger keeps needing tokens for paths nobody anticipated. + +The cause is structural. **The grammar encodes the path in the state +token.** `fixed` means the session acted; `resolved` means a held +question closed. Add a path — the developer present in the round, ruling +without anything ever being held — and the grammar needs a fourth token, +then a fifth. Practice has already taken that path. Every `resolved` +line in wave one's record closes a `held` line nobody wrote, and two +`resolved (declined)` lines record a transition the grammar does not +define at all. + +A second assumption is wrong in the same way. The grammar treats the +developer as asynchronous, reachable only through `held`. The loop runs +with the developer in the conversation. + +## What this design is + +The state machine is over **one finding**, not over the loop. Three +levels the shipped grammar conflates: + +- a **round heading** records one dispatch and never changes; +- a **disposition line** carries the mutable state of one finding; +- a **gate line** carries the state of one hit — a smaller machine + sharing the container but not the vocabulary. + +Loop state proper — the round count, the all-Minor signal, the +diff-scoped chain — is derived by folding the headings. It is stored +nowhere, and this design stores it nowhere. + +## The states + +Four, replacing five. + + - open — [] + - held — [] ; question: ; options: + - fixed — [] ; ; + - declined — [] ; ; + +`open` and `held` are the non-terminal states, and the only two the +Unfinished-work list anchors. `fixed` and `declined` are terminal and +say what became of the document: it changed, or it stands. + +`fixed` and `resolved` merge because they were never two states. Both +mean the document changed on account of this finding; they differed only +in who authorized the change, which is now a clause. Merging also frees +a word the rules currently use for two objects — `concerns (resolved +)` annotates a verdict, while `resolved ` annotated a +finding. + +## The clauses + +The leading token is a queryable state. Clauses are payload. + +| clause | carries | on | +|---|---|---| +| `license: ` | the written decision the session acted on | `fixed` | +| `ruling: ` | the developer authorized it | `fixed`, `declined` | +| `question:` | the question, phrased so one short answer resolves it | `held` | +| `options:` | the options and the session's recommendation | `held` | +| `counter:` | the session's evidence where the finding is disputed or contested | `held` | +| `deviation:
` | where the rationale for departing from a reviewer's suggestion lives | `fixed` | + +`question:` and `options:` are both required on a `held` line: the batch +that relays them is a transcript, and a session that dies between the +relay and the answer leaves the next session to re-derive the options — +possibly differently, so the developer answers a question that silently +changed. `counter:` and `deviation:` are conditional, written whenever +their condition holds. + +Every terminal line carries exactly one authorizer, `license:` or +`ruling:`. A `declined` line always carries `ruling:`: declining is a +decision, and triage gives a session no license to decide. + +Payload costs nothing structurally. The Unfinished-work commands anchor +on `^- `, so an indented continuation under a disposition line matches +no command and disturbs no consumer. Where payload runs long, it +belongs in indented sub-bullets rather than in a longer line. + +## What the authorizer buys + +Two shipped rules discriminate on the token today, and they do opposite +things: the oscillation tripwire escalates a finding re-raised against a +`fixed` line, and the relitigation clause folds one re-raised against a +`resolved` line. Merging the tokens would collapse that distinction, so +both move to the clause: + +- re-raised against `license:` — two readings of one license, a + contested reading, escalates as held with the flip named; +- re-raised against `ruling:` — a recorded developer decision, folded + and cited, never asked again. + +This is stronger than what it replaces. Today both rules key on a proxy: +`resolved` happens to imply the developer. After the change the +predicate says what it means. + +## Write-ahead + +**Each disposition line is written before the edit it describes, or with +it — never batched at the end of a wave.** + +The dangerous failure is not a session dying mid-round; it is a fix wave +half-applied with no lines written. The body has changed, nothing says +which change belongs to which finding, and the next round's brief reads +a diff source that is silently wrong. Writing contemporaneously makes a +partial wave self-evident: `open` and `fixed` lines mixed under one +heading say exactly where the session stopped. + +This costs no notation. The rule already prescribes `open` at stamp +time; this extends the same discipline to every later transition. + +## The cap is best-effort + +The round cap guards spend, not correctness, and it survives no +compaction — the count is derived from headings, but the reset event is +not recorded anywhere. + +**Developer contact is a message from the developer.** Not a relay they +read, not an escalation the session sent, not an unanswered batch. That +matches what unattended means, and it needs no notation. + +**A session that cannot count its own rounds escalates rather than +assuming.** Resetting to zero after a compaction fails in the wrong +direction: a long session could grant itself three fresh rounds after +every compaction. Treating a lost count as its own reason to ask costs +nothing and bounds the spend the cap exists to bound. + +## Gate lines + +The two shapes stand. One stated reason does not: the rule claims the +date tells a gate episode apart from the round's own findings, and wave +one's own record disproves it — three `hit fixed 2026-09-01` lines sit +beside six `resolved 2026-09-01` finding lines under one heading, and +two episodes share the date 2026-08-31. **The `hit` token is the +discriminator.** A wrong stated reason invites a later session to +correct the right practice, so the sentence is replaced rather than +dropped. + +## What this does not build + +Each refusal is recorded with its reason, so a later wave reopens it +with evidence rather than by taste. + +- **No `hit outstanding` token.** A hit is mechanically re-derivable: + the next gate episode regenerates it for the price of the cheapest + agent in the system. A lost finding is gone forever; a lost hit is + not. The state has also never occurred, and minting it would + contradict two glossary entries that call a hit binary. +- **No `why:` clause on `held`.** Its value is drawn from a closed + four-way set — no license, a contradiction between decisions, a + disputed finding, or one that could go either way — which the + `question:` phrasing already carries. +- **No episode identity for gates.** One consumer needs it — the + re-dispatch bound's counter — and only across session loss. Losing it + costs at most two dispatches on the cheapest family. Let it die with + the session. +- **No structured block, sidecar file, or git as the diff source.** An + LLM hand-writes this record either way, so structure buys checkability + the writer's nature does not deliver; and the lifecycle rule keeps + these documents uncommitted through the rounds on purpose. + +## The blocking terminator loses its self-fix prohibition + +`blocking` keeps its meaning — autonomy suspended, no further round +without the developer — and drops the clause forbidding self-fixes. + +The prohibition's own rationale is about findings, while the +prohibition is stated on the verdict. **A design reshape has no citable +license by construction, so triage already holds it.** Wave one's round +1 is the evidence: five wording and consistency fixes, every one with a +clean citation, none a reshape, all forbidden only because the +reviewer's grade read `blocking`. + +## Severity casing + +The glossary fixes `critical | important | minor`; all 163 severity +slots in this repo capitalize. **The ledger's severity slot capitalizes +the glossary term.** One sentence legitimizes practice, respects the +canonical vocabulary, and migrates nothing. Deferring this to a lint +would make the lint's first act the condemnation of every committed +line. + +## Changes by file + +- `plugins/working-process/rules/spec-plan-lifecycle.md` — the four + states and their shapes, the clause table, the authorizer rule, the + write-ahead sentence, the severity-casing sentence, the corrected gate + discriminator, the refusals, and the relitigation clause rekeyed to + `ruling:`. +- `plugins/working-process/rules/workflow.md` — the oscillation tripwire + rekeyed to `license:`, the `blocking` terminator's prohibition + deleted, and the cap's contact definition with its + cannot-count escalation. +- `docs/domain/glossary.md` — no term changes; the refusal of + `hit outstanding` is what keeps **Hit** binary. +- `docs/specs/2026-08-31-review-loop-errata-wave-one.md` — its bare + `- dismissed 2026-08-31` line takes the `hit dismissed` shape the + grammar defines. + +Historical ledger lines stay as written. One sentence records that they +predate the merge, as the `scope` token's introduction already +established. + +Merging a published token narrows a shipped convention, so the release +carrying this takes a minor bump. + +## Seams this does not close + +- **The glossary has no owner on the fix-wave path.** Three collisions + in wave one, and a fourth arrived during this design's own + consultation. The candidates are a triage duty — a `fixed` line whose + license is a glossary term, or whose change moves a term's meaning, + owes a glossary check — or a standing enumeration target for the + propagation gate, which reaches only the quoting case. +- **A stop signal cannot bind text written after it was given.** New + design written after a stop signal should re-arm review rather than + override it, and the signal should be scoped to the text it read. +- **A plan's owed confirming round has no Unfinished-work entry.** The + workflow rule calls the diff-scoped LGTM heading a durable marker and + prescribes a recovery reading, but no command matches it, so + `process-status` reports clean while a confirming round is owed. +- **Concurrent waves on one document are undetected and unsupported.** + The store is an uncommitted file, and the one-live-round rule is + scoped within a session. Declaring the limit is cheap; engineering + around it is not. +- **The deferred grammar lint.** Roughly half of this design becomes + mechanically checkable if it ships and stays convention if it does + not. +- **Per-round commits, with a named trigger.** The lifecycle rule + suggests committing only at the implementation-ready gate, while + allowing the developer to commit sooner on their own call. If a loop + starts committing each round, `hit fixed` loses its justification — + the gate's diff would have a durable home elsewhere — `` + thins to a sentence, and the round heading can carry a commit hash. + That trades this design's shapes for fewer, so it belongs to a later + wave and not to this one. From b90cc3255ccb0007518dfeade885b3ba0c2d6d6e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 12:47:08 +0200 Subject: [PATCH 044/126] docs: grill the wave-two spec - ledger vocabulary enters the glossary --- docs/domain/glossary.md | 49 ++++++++++++++++++- ...26-09-02-ledger-as-finding-state-design.md | 39 ++++++++++----- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index cd7a30a..cfc879f 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -126,7 +126,10 @@ adoption as the developer's own. The grading value a review finding carries: `critical | important | minor`, fixed per rule in its rule tag and read off by the reviewer — never judged per finding wherever a tag exists; a Candidate gap, having -no tag, is graded by the Authoring rubric. The collective noun is +no tag, is graded by the Authoring rubric. The value is canonical as a +word and its casing follows the syntax it sits in — lower case as a rule +tag's field value (`severity: minor`), capitalized in the ledger's +bracket slot (`[Minor]`). The collective noun is "severity level" — never "tier", which stays reserved for the model-capability ladder. _Avoid_: severity tier @@ -210,6 +213,18 @@ refusal. Marked by the `(chosen )` token in the `*-fallback` field; carries the same re-review offer as a degraded verdict. _Avoid_: voluntary degradation +**Adjudication**: +The developer's close of a `blocking` verdict without a fresh round, +written `blocking (adjudicated )` in the document's frontmatter. +Closes a round; the finding-level counterpart is a Ruling. +_Avoid_: developer override, manual close + +**Ruling**: +The developer's authorization of one finding's disposition, written as +the `ruling: ` clause on that finding's ledger line. Closes a +finding; the round-level counterpart is an Adjudication. +_Avoid_: developer decision (as the name), developer fix + **Fallback**: The model that actually produced a degraded or chosen verdict, standing in for the prescribed tier; named (as a family alias) in the value of @@ -292,6 +307,38 @@ dismissed by the dispatcher, never graded. Graded problems are Findings and belong to review rounds. _Avoid_: mechanical finding +**Disposition ledger**: +The record a review loop keeps inside the reviewed document, under one +`## Review rounds` section: what each round found and what became of it. +It carries the loop's durable state, and nothing else does — the +session, the reviewer and the developer are all volatile, and these +documents stay uncommitted through the rounds. Per-finding and per-hit +state is written into it; loop-level state is derived from the round +headings and stored nowhere. The name comes from the terminal states +that dominate it in practice; a leading token names a state, terminal or +not. +_Avoid_: review log, findings table, round log + +**Round heading**: +The immutable record of one dispatch, opening a round's block in the +disposition ledger: date, agent, model self-report, verdict, ordinal and +scope. The loop's derived state — round count, the all-Minor signal, the +diff-scoped chain — is read by folding these. +_Avoid_: round title, round record (for the heading alone) + +**Disposition line**: +One line of the disposition ledger carrying the state of one Finding: +its leading token is that state, its clauses the payload. The unit the +ledger's state machine acts on. +_Avoid_: finding line, ledger entry + +**Gate line**: +One line of the disposition ledger carrying the state of one Hit, +written by the propagation gate. It shares the container with +disposition lines and nothing else — its own leading token, no severity, +no license. +_Avoid_: hit line, audit line + **Verdict agent**: An agent whose report ends in a verdict the dispatcher stamps into the reviewed document's frontmatter — `architect` and `plan-adversary`. diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index 1f7f89c..ee497dc 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -2,6 +2,7 @@ ticket: none date: 2026-09-02 status: draft +grilled: 2026-09-02 revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-08-31-review-loop-errata-wave-one.md] branch: feature/audit-errata base: develop @@ -145,7 +146,7 @@ nothing and bounds the spend the cap exists to bound. The two shapes stand. One stated reason does not: the rule claims the date tells a gate episode apart from the round's own findings, and wave one's own record disproves it — three `hit fixed 2026-09-01` lines sit -beside six `resolved 2026-09-01` finding lines under one heading, and +beside six `resolved 2026-09-01` disposition lines under one heading, and two episodes share the date 2026-08-31. **The `hit` token is the discriminator.** A wrong stated reason invites a later session to correct the right practice, so the sentence is replaced rather than @@ -188,26 +189,40 @@ reviewer's grade read `blocking`. ## Severity casing -The glossary fixes `critical | important | minor`; all 163 severity -slots in this repo capitalize. **The ledger's severity slot capitalizes -the glossary term.** One sentence legitimizes practice, respects the -canonical vocabulary, and migrates nothing. Deferring this to a lint -would make the lint's first act the condemnation of every committed -line. +All 163 severity slots in this repo capitalize, against a glossary that +fixed `critical | important | minor` in lower case. The grilling settled +it in the glossary rather than here: the value is canonical as a word, +and its casing follows the syntax it sits in — lower case as a rule +tag's field value, capitalized in the ledger's bracket slot. One +concept, two syntaxes, two rendering conventions, and no migration. + +This design therefore states no casing rule of its own; it cites the +**Severity** entry. Deferring the question to a lint would have made the +lint's first act the condemnation of every committed line. ## Changes by file - `plugins/working-process/rules/spec-plan-lifecycle.md` — the four states and their shapes, the clause table, the authorizer rule, the - write-ahead sentence, the severity-casing sentence, the corrected gate - discriminator, the refusals, and the relitigation clause rekeyed to - `ruling:`. + write-ahead sentence, the corrected gate discriminator, the refusals, + and the relitigation clause rekeyed to `ruling:`. Two further sites + the grilling found: the Unfinished-work section says a ledger close is + `open` or `held` becoming `resolved `, which the merge makes + `fixed ` or `declined `; and two sentences call the + list's own entry a "review-loop ledger entry", a phrase the glossary + now bans as a name for a disposition line, so both read + "review-loop entry" instead. - `plugins/working-process/rules/workflow.md` — the oscillation tripwire rekeyed to `license:`, the `blocking` terminator's prohibition deleted, and the cap's contact definition with its cannot-count escalation. -- `docs/domain/glossary.md` — no term changes; the refusal of - `hit outstanding` is what keeps **Hit** binary. +- `docs/domain/glossary.md` — already changed by the grilling, not by + the implementation: six new terms (**Adjudication** and **Ruling** as + a level-distinguishing pair; **Disposition ledger**, **Round + heading**, **Disposition line** and **Gate line** for the structure + the loop had been naming without defining), plus a **Severity** + sentence putting casing under the syntax each value sits in. The + refusal of `hit outstanding` is what keeps **Hit** binary. - `docs/specs/2026-08-31-review-loop-errata-wave-one.md` — its bare `- dismissed 2026-08-31` line takes the `hit dismissed` shape the grammar defines. From bdc6270b2e3b85b69b9a2ca38203cad9ebe57e3d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 13:28:01 +0200 Subject: [PATCH 045/126] docs: wave-two round one - fold production, ledger scope for diff-scoped rounds --- docs/domain/glossary.md | 6 +- ...26-09-02-ledger-as-finding-state-design.md | 115 +++++++++++++++--- 2 files changed, 105 insertions(+), 16 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index cfc879f..baf921e 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -221,8 +221,10 @@ _Avoid_: developer override, manual close **Ruling**: The developer's authorization of one finding's disposition, written as -the `ruling: ` clause on that finding's ledger line. Closes a -finding; the round-level counterpart is an Adjudication. +the `ruling: ` clause on that finding's ledger line — dated fresh, +or carrying an earlier ruling's date where the line folds a re-raise +against it. Closes a finding; the round-level counterpart is an +Adjudication. _Avoid_: developer decision (as the name), developer fix **Fallback**: diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index ee497dc..4a2d3e6 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -3,6 +3,7 @@ ticket: none date: 2026-09-02 status: draft grilled: 2026-09-02 +architect: concerns revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-08-31-review-loop-errata-wave-one.md] branch: feature/audit-errata base: develop @@ -71,7 +72,7 @@ The leading token is a queryable state. Clauses are payload. | clause | carries | on | |---|---|---| | `license: ` | the written decision the session acted on | `fixed` | -| `ruling: ` | the developer authorized it | `fixed`, `declined` | +| `ruling: ` | the developer authorized it, or the date of a cited prior ruling this line folds against | `fixed`, `declined` | | `question:` | the question, phrased so one short answer resolves it | `held` | | `options:` | the options and the session's recommendation | `held` | | `counter:` | the session's evidence where the finding is disputed or contested | `held` | @@ -88,10 +89,13 @@ Every terminal line carries exactly one authorizer, `license:` or `ruling:`. A `declined` line always carries `ruling:`: declining is a decision, and triage gives a session no license to decide. -Payload costs nothing structurally. The Unfinished-work commands anchor -on `^- `, so an indented continuation under a disposition line matches -no command and disturbs no consumer. Where payload runs long, it -belongs in indented sub-bullets rather than in a longer line. +Payload costs nothing structurally. Four of the five Unfinished-work +commands anchor a frontmatter field and are held to the frontmatter +block by the list's default scope guard, so no body line reaches them at +all; the fifth is the ledger's own, anchored on `^- `, which an indented +continuation does not match. Payload under a line is therefore invisible +to every published command, and where it runs long it belongs in +indented sub-bullets rather than in a longer line. ## What the authorizer buys @@ -110,6 +114,50 @@ This is stronger than what it replaces. Today both rules key on a proxy: `resolved` happens to imply the developer. After the change the predicate says what it means. +**A fold produces a line like any other disposition.** The re-raised +finding is still a finding of its round, so it takes +`declined ` — the document stands — carrying `ruling:` with the +**prior** ruling's date and a citation of the line it folds against. The +authorizer is cited rather than fresh, and the line says so; a session +never manufactures an authorization that did not happen. Without this +the fold has no honest production, since no developer ruled on the new +finding and `declined` admits no other authorizer — the same shape as +the audit's first defect, which this design exists to cure. + +The fold is a safety net, not the primary mechanism. A reviewer is a +stateless one-shot dispatch, so it cannot remember what earlier rounds +settled — which is why the shipped rule says state prevents +relitigation, not the reviewer's memory. + +## What a diff-scoped round may read + +Diff-scoping forbids re-reviewing the document beyond the diff, and the +ledger is part of the document — so the reviewer has been formally cut +off from the one section recording what the developer already decided. +That is the cause of the re-raises the fold exists to absorb, and it is +cheaper to fix at the source. + +**The ledger is always in scope for a diff-scoped round as context, +never as a review target.** What that protects is narrow and deliberate: + +- **Settled lines** — those carrying `ruling:`, and `declined` lines — + may not be re-raised without new evidence. They are the developer's + decisions. +- **`held` lines** carry questions already put, so a round does not + duplicate one. +- **Session fixes** — `fixed` lines carrying `license:` — get no + protection at all. The previous round's are the diff and are named as + the first thing to attack; older ones are simply unprotected. A + reviewer told not to re-raise a fix would lose the property + diff-scoping was adopted for, since repair-born defects are the + dominant late-round class. + +The reviewer learns what it may not reopen, never what it may not find. +Naming the section rather than copying its lines keeps the brief from +growing with the round count, and follows the same +point-at-files-rather-than-paste discipline the workflow rule already +applies to consultations. + ## Write-ahead **Each disposition line is written before the edit it describes, or with @@ -189,8 +237,9 @@ reviewer's grade read `blocking`. ## Severity casing -All 163 severity slots in this repo capitalize, against a glossary that -fixed `critical | important | minor` in lower case. The grilling settled +All 164 severity slots in this repo capitalize, across 163 lines — one +audit line quotes two — against a glossary that fixed +`critical | important | minor` in lower case. The grilling settled it in the glossary rather than here: the value is canonical as a word, and its casing follows the syntax it sits in — lower case as a rule tag's field value, capitalized in the ledger's bracket slot. One @@ -214,22 +263,29 @@ lint's first act the condemnation of every committed line. "review-loop entry" instead. - `plugins/working-process/rules/workflow.md` — the oscillation tripwire rekeyed to `license:`, the `blocking` terminator's prohibition - deleted, and the cap's contact definition with its - cannot-count escalation. + deleted, the cap's contact definition with its cannot-count + escalation, and the re-dispatch brief's scope clause putting the + ledger permanently in a diff-scoped round's context. - `docs/domain/glossary.md` — already changed by the grilling, not by the implementation: six new terms (**Adjudication** and **Ruling** as a level-distinguishing pair; **Disposition ledger**, **Round heading**, **Disposition line** and **Gate line** for the structure the loop had been naming without defining), plus a **Severity** - sentence putting casing under the syntax each value sits in. The - refusal of `hit outstanding` is what keeps **Hit** binary. + sentence putting casing under the syntax each value sits in. Round 1 + added one more: **Ruling** admits a cited earlier ruling, which is + what makes a fold expressible. The refusal of `hit outstanding` is + what keeps **Hit** binary. - `docs/specs/2026-08-31-review-loop-errata-wave-one.md` — its bare `- dismissed 2026-08-31` line takes the `hit dismissed` shape the grammar defines. -Historical ledger lines stay as written. One sentence records that they -predate the merge, as the `scope` token's introduction already -established. +Historical ledger lines stay as written, with one sentence recording +that they predate the merge, as the `scope` token's introduction already +established. The bare `- dismissed 2026-08-31` line above is the one +exception, and for a different reason: it is not a line the merge +remaps but a line that never matched any shape, written before the +`hit dismissed` shape existed. Normalizing it to a shape its own wave +later defined is not a rewrite under the merge. Merging a published token narrows a shipped convention, so the release carrying this takes a minor bump. @@ -256,6 +312,12 @@ carrying this takes a minor bump. - **The deferred grammar lint.** Roughly half of this design becomes mechanically checkable if it ships and stays convention if it does not. +- **Is a plan's confirming round autonomous, and does it count against + the cap?** Wave one routed the audit's implementer question 3 here. + Its missing-anchor half is the seam above; this half is a decision + about the loop's authority, not about the ledger, so it stays open + rather than being answered in passing by a document about record + shapes. - **Per-round commits, with a named trigger.** The lifecycle rule suggests committing only at the implementation-ready gate, while allowing the developer to commit sooner on their own call. If a loop @@ -264,3 +326,28 @@ carrying this takes a minor bump. thins to a sentence, and the round heading can carry a commit hash. That trades this design's shapes for fewer, so it belongs to a later wave and not to this one. + +## Review rounds + +### 2026-09-02 — architect, fable 5, concerns (round 1, full-document) + +The gate episode preceding this round had no heading to write under and +deferred its line here, as the placement rule's one deferral case +prescribes. + +- dismissed 2026-09-02 — the glossary's new `ledger entry` ban is violated by `spec-plan-lifecycle.md` lines 228 and 272; counter: both say "review-loop ledger entry" for the Unfinished-work list's own entry, not a disposition line, so the banned sense is not the one in use — and Changes by file already schedules both rewordings, the designed sequence being glossary at grilling, rules at implementation. The round confirmed the dismissal on both legs +- fixed — [Important] the relitigation fold had no expressible production: a re-raise folded against a `ruling:` line still needs its own terminal line, which must be `declined` and so must carry `ruling:` — but no developer ruled on the new finding, so the line either misreported its authorizer or could not be written. The same shape as the audit's defect 1, in the document that exists to cure it; ruling: 2026-09-02; the developer chose the cited-authorizer shape over a separate `folds:` clause and over producing no line at all — the fold now takes `declined ` with `ruling:` carrying the prior ruling's date and a citation of the folded line, the clause table and the glossary's **Ruling** entry both widened to admit a cited authorization +- fixed — [Minor] "the Unfinished-work commands anchor on `^- `" was true of one of five; license: the five published commands read from the rule; the claim now names the split and rests the payload-is-free conclusion on the scope guard, which is what actually defends it +- fixed — [Minor] "Historical ledger lines stay as written" sat beside a scheduled rewrite of one historical line; license: the spec's own distinction between remapping under the merge and normalizing to a shape defined later; the exception is now stated with its reason +- fixed — [Minor] wave one routed implementer question 3 here and only its missing-anchor half was carried; license: wave one's own routing sentence; the autonomy-and-cap half joins the seams, deliberately unanswered because it decides the loop's authority rather than the ledger's shape +- fixed — [Minor] "163 severity slots" counted lines, not slots; license: the recount — 164 occurrences across 163 lines, one audit line quoting two; both numbers now stated +- fixed — [n/a] the developer, reading the Important above, asked why a round re-raises a settled finding at all; the answer is that a diff-scoped round is formally cut off from the ledger, so the cause is upstream of the fold; ruling: 2026-09-02; a new section puts the ledger permanently in a diff-scoped round's context, protecting settled and `held` lines while leaving session fixes as legitimate targets + +This last line cannot be written honestly under the grammar it replaces. +It records neither a self-fixed finding (`fixed`, which the shipped rule +defines as licensed by a citable decision) nor the close of a `held` line +(`resolved `, which closes nothing here) — and it carries no +severity, because no reviewer graded it. It is a developer-directed +change mid-round, which is the audit's defect 2 exactly, and the +`ruling:` clause this design adds is what makes it expressible. The +`[n/a]` slot above is what the gap looks like when it is written down. From f4cbce3d9e0c2043d9faacd51669f83f9f0b55db Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 13:44:03 +0200 Subject: [PATCH 046/126] docs: wave-two round two - conditional fold, severity omitted where nobody graded --- ...26-09-02-ledger-as-finding-state-design.md | 90 ++++++++++++++----- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index 4a2d3e6..d192ddb 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -3,7 +3,7 @@ ticket: none date: 2026-09-02 status: draft grilled: 2026-09-02 -architect: concerns +architect: blocking revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-08-31-review-loop-errata-wave-one.md] branch: feature/audit-errata base: develop @@ -54,10 +54,22 @@ Four, replacing five. - fixed — [] ; ; - declined — [] ; ; +The severity bracket is omitted on a `ruling:`-only line, as below: + + - fixed ; ruling: ; + `open` and `held` are the non-terminal states, and the only two the Unfinished-work list anchors. `fixed` and `declined` are terminal and say what became of the document: it changed, or it stands. +The severity slot is a reviewer's grade, so it is omitted exactly where +there is none: a line whose sole authorizer is `ruling:` and which no +reviewer graded — a change the developer directed mid-round — carries +its claim with no bracket at all. This is not a fourth severity value; +the glossary's three stand. It is the recognition that a developer's +instruction is not a finding, and that inventing a grade for it would be +the same manufacture the authorizer rule forbids. + `fixed` and `resolved` merge because they were never two states. Both mean the document changed on account of this finding; they differed only in who authorized the change, which is now a clause. Merging also frees @@ -72,7 +84,7 @@ The leading token is a queryable state. Clauses are payload. | clause | carries | on | |---|---|---| | `license: ` | the written decision the session acted on | `fixed` | -| `ruling: ` | the developer authorized it, or the date of a cited prior ruling this line folds against | `fixed`, `declined` | +| `ruling: ` | the developer authorized it; on a fold, the prior ruling's date followed by `folding
` naming what it folds against | `fixed`, `declined` | | `question:` | the question, phrased so one short answer resolves it | `held` | | `options:` | the options and the session's recommendation | `held` | | `counter:` | the session's evidence where the finding is disputed or contested | `held` | @@ -107,17 +119,22 @@ both move to the clause: - re-raised against `license:` — two readings of one license, a contested reading, escalates as held with the flip named; -- re-raised against `ruling:` — a recorded developer decision, folded - and cited, never asked again. +- re-raised against `ruling:` **without new evidence** — a recorded + developer decision, folded and cited, never asked again; +- re-raised against `ruling:` **with new evidence** — `held`, its + `counter:` citing the prior ruling. A session that folded this + autonomously would be arbitrating between a reviewer and a recorded + developer decision, which the workflow rule forbids it to do. This is stronger than what it replaces. Today both rules key on a proxy: `resolved` happens to imply the developer. After the change the predicate says what it means. -**A fold produces a line like any other disposition.** The re-raised -finding is still a finding of its round, so it takes +**A fold produces a line like any other disposition.** An evidence-free +re-raise is still a finding of its round, so it takes `declined ` — the document stands — carrying `ruling:` with the -**prior** ruling's date and a citation of the line it folds against. The +**prior** ruling's date and a `folding` citation of the line it folds +against. The authorizer is cited rather than fresh, and the line says so; a session never manufactures an authorization that did not happen. Without this the fold has no honest production, since no developer ruled on the new @@ -140,9 +157,11 @@ cheaper to fix at the source. **The ledger is always in scope for a diff-scoped round as context, never as a review target.** What that protects is narrow and deliberate: -- **Settled lines** — those carrying `ruling:`, and `declined` lines — - may not be re-raised without new evidence. They are the developer's - decisions. +- **Settled lines** — those carrying `ruling:` — may be re-raised only + with new evidence, which routes to `held` rather than to a fold. + They are the developer's decisions. Historical lines written before + this design, including `resolved (declined)`, carry no + authorizer clause and are settled by their token alone. - **`held` lines** carry questions already put, so a round does not duplicate one. - **Session fixes** — `fixed` lines carrying `license:` — get no @@ -237,9 +256,12 @@ reviewer's grade read `blocking`. ## Severity casing -All 164 severity slots in this repo capitalize, across 163 lines — one -audit line quotes two — against a glossary that fixed -`critical | important | minor` in lower case. The grilling settled +Every severity slot in this repo capitalizes, and none is lower case, +against a glossary that fixed `critical | important | minor` in lower +case. No count is stated here on purpose: a ledger grows every round, so +any repo-wide number is falsified by the next line written — this +document's own round-2 report proved it, on a figure the previous commit +had invalidated while writing it. The grilling settled it in the glossary rather than here: the value is canonical as a word, and its casing follows the syntax it sits in — lower case as a rule tag's field value, capitalized in the ledger's bracket slot. One @@ -335,19 +357,39 @@ The gate episode preceding this round had no heading to write under and deferred its line here, as the placement rule's one deferral case prescribes. -- dismissed 2026-09-02 — the glossary's new `ledger entry` ban is violated by `spec-plan-lifecycle.md` lines 228 and 272; counter: both say "review-loop ledger entry" for the Unfinished-work list's own entry, not a disposition line, so the banned sense is not the one in use — and Changes by file already schedules both rewordings, the designed sequence being glossary at grilling, rules at implementation. The round confirmed the dismissal on both legs +- hit dismissed 2026-09-02 — the glossary's new `ledger entry` ban is violated by `spec-plan-lifecycle.md` lines 228 and 272; counter: both say "review-loop ledger entry" for the Unfinished-work list's own entry, not a disposition line, so the banned sense is not the one in use — and Changes by file already schedules both rewordings, the designed sequence being glossary at grilling, rules at implementation. The round confirmed the dismissal on both legs - fixed — [Important] the relitigation fold had no expressible production: a re-raise folded against a `ruling:` line still needs its own terminal line, which must be `declined` and so must carry `ruling:` — but no developer ruled on the new finding, so the line either misreported its authorizer or could not be written. The same shape as the audit's defect 1, in the document that exists to cure it; ruling: 2026-09-02; the developer chose the cited-authorizer shape over a separate `folds:` clause and over producing no line at all — the fold now takes `declined ` with `ruling:` carrying the prior ruling's date and a citation of the folded line, the clause table and the glossary's **Ruling** entry both widened to admit a cited authorization - fixed — [Minor] "the Unfinished-work commands anchor on `^- `" was true of one of five; license: the five published commands read from the rule; the claim now names the split and rests the payload-is-free conclusion on the scope guard, which is what actually defends it - fixed — [Minor] "Historical ledger lines stay as written" sat beside a scheduled rewrite of one historical line; license: the spec's own distinction between remapping under the merge and normalizing to a shape defined later; the exception is now stated with its reason - fixed — [Minor] wave one routed implementer question 3 here and only its missing-anchor half was carried; license: wave one's own routing sentence; the autonomy-and-cap half joins the seams, deliberately unanswered because it decides the loop's authority rather than the ledger's shape - fixed — [Minor] "163 severity slots" counted lines, not slots; license: the recount — 164 occurrences across 163 lines, one audit line quoting two; both numbers now stated -- fixed — [n/a] the developer, reading the Important above, asked why a round re-raises a settled finding at all; the answer is that a diff-scoped round is formally cut off from the ledger, so the cause is upstream of the fold; ruling: 2026-09-02; a new section puts the ledger permanently in a diff-scoped round's context, protecting settled and `held` lines while leaving session fixes as legitimate targets - -This last line cannot be written honestly under the grammar it replaces. -It records neither a self-fixed finding (`fixed`, which the shipped rule -defines as licensed by a citable decision) nor the close of a `held` line -(`resolved `, which closes nothing here) — and it carries no -severity, because no reviewer graded it. It is a developer-directed -change mid-round, which is the audit's defect 2 exactly, and the -`ruling:` clause this design adds is what makes it expressible. The -`[n/a]` slot above is what the gap looks like when it is written down. +- hit dismissed 2026-09-02 — Changes by file prescribes edits to `spec-plan-lifecycle.md` the commit does not contain; counter: this is a design document, and Changes by file is a promise about implementation rather than an edit +- hit dismissed 2026-09-02 — the same, for `workflow.md`; counter: as above +- hit dismissed 2026-09-02 — the same, for wave one's record and its bare `dismissed` line; counter: as above +- hit dismissed 2026-09-02 — that the previous gate's dismissal contradicts Changes by file by calling the rewordings "scheduled"; counter: both texts say the same thing, and the audit read "scheduled for implementation" as "scheduled for a later wave" +- fixed — the developer, reading the Important above, asked why a round re-raises a settled finding at all; the answer is that a diff-scoped round is formally cut off from the ledger, so the cause is upstream of the fold; ruling: 2026-09-02; a new section puts the ledger permanently in a diff-scoped round's context, protecting settled and `held` lines while leaving session fixes as legitimate targets + +That line, and every other in this section carrying `ruling:`, is +written in the grammar this design proposes rather than the one it +replaces. The shipped `fixed` admits only `license:`, and shipped +`resolved ` closes a `held` line that none of these had — so a +developer-directed change mid-round had no honest production at all, +which is the audit's defect 2 exactly. + +Round 2 sharpened what the cure covers. The `ruling:` clause closes the +authorizer gap; it says nothing about the grade, and a first draft of +these lines invented an `[n/a]` severity that no grammar admits. The +answer is not a fourth value but the absence of one: a line no reviewer +graded carries no bracket, because severity is a reviewer's grade and +manufacturing one would repeat the very forgery the authorizer rule +exists to prevent. + +### 2026-09-02 — architect, fable 5, blocking (round 2, diff-scoped) + +- fixed — [Important] the scope section licensed a re-raise "with new evidence" while the fold stayed unconditional, so the licensed path had no disposition, and an autonomous fold of an evidence-bearing challenge is the arbitration the workflow rule forbids; ruling: 2026-09-02; the fold now covers evidence-free re-raises only, and an evidence-bearing one routes to `held` with `counter:` citing the prior ruling +- fixed — [Important] `[n/a]` was lawful under neither grammar, since all four shapes require `[]` and the glossary admits three values — the authorizer gap closed, the grade gap did not; ruling: 2026-09-02; severity is omitted entirely on a line whose sole authorizer is `ruling:` and which no reviewer graded, which is the absence of a grade rather than a fourth value +- fixed — [Minor] the fold's citation had no slot; license: the fold production this wave wrote; `ruling:` now carries the prior date followed by `folding
` +- fixed — [Minor] this document's own deferred gate line read bare `- dismissed 2026-09-02`, the shape it schedules normalizing away elsewhere; license: the `hit dismissed` shape wave one shipped; the token is restored +- fixed — [Minor] the recount was falsified by the commit that wrote it, which added five slots in its own ledger while stating 164; license: the recount itself; the number is gone and the universal claim stands, with the reason a frozen count cannot survive a growing ledger +- fixed — [Minor] aggregating four gate hits into one line contradicted the **Gate line** entry this design owns; license: that entry; split into four lines rather than amending the definition, which would pre-empt an open question about controlled aggregation in reports +- fixed — [Minor] "those carrying `ruling:`, and `declined` lines" was redundant and did not cover historical settled lines; license: the authorizer rule; the conjunct is gone and pre-design lines are named as settled by their token alone From f46860a7711222b32e7cfbd304a8e133f6308708 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 14:12:54 +0200 Subject: [PATCH 047/126] docs: wave-two round three and loop close - definition-site precision --- ...26-09-02-ledger-as-finding-state-design.md | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index d192ddb..a61d278 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -3,7 +3,7 @@ ticket: none date: 2026-09-02 status: draft grilled: 2026-09-02 -architect: blocking +architect: concerns (resolved 2026-09-02) revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-08-31-review-loop-errata-wave-one.md] branch: feature/audit-errata base: develop @@ -54,7 +54,9 @@ Four, replacing five. - fixed — [] ; ; - declined — [] ; ; -The severity bracket is omitted on a `ruling:`-only line, as below: +The severity bracket is omitted on a line whose sole authorizer is +`ruling:` **and** which no reviewer graded — both legs, never one, as +below: - fixed ; ruling: ; @@ -126,6 +128,12 @@ both move to the clause: autonomously would be arbitrating between a reviewer and a recorded developer decision, which the workflow rule forbids it to do. +Evidence is new relative to what the folded line records — its claim and +the reasoning its clauses carry — not relative to the reviewer's wording. +A session that cannot tell holds rather than folds, since triage already +says a finding that could go either way is a decision, and a wrong +not-new call performs the arbitration this split exists to prevent. + This is stronger than what it replaces. Today both rules key on a proxy: `resolved` happens to imply the developer. After the change the predicate says what it means. @@ -161,7 +169,8 @@ never as a review target.** What that protects is narrow and deliberate: with new evidence, which routes to `held` rather than to a fold. They are the developer's decisions. Historical lines written before this design, including `resolved (declined)`, carry no - authorizer clause and are settled by their token alone. + authorizer clause and are settled by their token alone; a fold against + one cites the date on that token, which is when the developer decided. - **`held` lines** carry questions already put, so a round does not duplicate one. - **Session fixes** — `fixed` lines carrying `license:` — get no @@ -393,3 +402,32 @@ exists to prevent. - fixed — [Minor] the recount was falsified by the commit that wrote it, which added five slots in its own ledger while stating 164; license: the recount itself; the number is gone and the universal claim stands, with the reason a frozen count cannot survive a growing ledger - fixed — [Minor] aggregating four gate hits into one line contradicted the **Gate line** entry this design owns; license: that entry; split into four lines rather than amending the definition, which would pre-empt an open question about controlled aggregation in reports - fixed — [Minor] "those carrying `ruling:`, and `declined` lines" was redundant and did not cover historical settled lines; license: the authorizer rule; the conjunct is gone and pre-design lines are named as settled by their token alone + +### 2026-09-02 — architect, fable 5, concerns (round 3, diff-scoped) + +- fixed — [Minor] the states block's caption said "a `ruling:`-only line" where the rule twelve lines below requires two legs, and this document's own three `ruling:`-only lines carry `[Important]` because a reviewer graded them; license: that fuller paragraph; the caption now carries both legs +- fixed — [Minor] a fold against a pre-design settled line had no date to cite, since historical lines carry no authorizer clause; license: this design's own statement that such lines are settled by their token alone; the fold cites the date on that token, which is when the developer decided +- fixed — [Minor] "without new evidence" named no comparison base, and a wrong not-new call silently performs the arbitration the split exists to prevent; license: the workflow rule's triage principle that a finding which could go either way is a decision; evidence is new relative to what the folded line records, and a session that cannot tell holds + +Round 3 judged the symmetry sound rather than rhetorical: an authorizer +is constitutive of a terminal transition and is therefore cited when it +exists elsewhere, while a grade is a reviewer's description whose true +absence is honestly recorded by omission. One principle, two treatments +— cite what exists, omit what never did. + +Its stop signal: a fourth round would not earn its cost. The leftovers +were wording at a definition site, which is the class the consumption +gate's integrity audit reads with two quotes per defect at the same tier +over a broader scope. The document is done being reviewed in this loop. + +Loop closed 2026-09-02 by the developer, on round 3's stop signal and +with every finding of every round disposed. Three architect rounds — +concerns, blocking, concerns — and three propagation gate episodes, one +CLEAN and two producing five hits, every one dismissed with a written +counter-derivation and none requiring a fix. The next reader is the +consumption gate's integrity audit, before the plan is written. + +A first draft of this paragraph stated six episodes and three fixes, +conflating this loop's gates with the previous wave's. The recount is +the third time in this document that a frozen number was wrong — which +is why the severity section now states none. From 814ea2bd08eb1b167062e21da7f49b633d53e822 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 14:20:30 +0200 Subject: [PATCH 048/126] docs: record the gate dismissal that measured the episode-identity refusal --- .../2026-09-02-ledger-as-finding-state-design.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index a61d278..7c87cea 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -431,3 +431,16 @@ A first draft of this paragraph stated six episodes and three fixes, conflating this loop's gates with the previous wave's. The recount is the third time in this document that a frozen number was wrong — which is why the severity section now states none. + +- hit dismissed 2026-09-02 — that the episode counts above invert the record, since all five `hit dismissed` lines sit under the round-1 heading and so come from one episode; counter: the placement rule writes gate lines under the *last* round's heading at gate time, so the gate before round 1 deferred its line to that stamp and the gate before round 2 wrote four more under the same heading — two episodes, five hits, and the third CLEAN before round 3. The count stands + +That dismissal is worth more than the hit. The audit reconstructed the +history wrongly because gate lines carry no episode identity, which this +design refuses on the ground that losing it costs at most two extra +dispatches on the cheapest family. This is the refusal's first live +instance, and the cost it produced was a different one: not a re-run, +but a careful mechanical reader drawing a false conclusion from the +record. The refusal priced the operational loss and not the legibility +loss. It stands — but the seam it leaves is now measured rather than +assumed, and this line, written under round 3's heading by a gate that +ran after round 3, is itself the demonstration. From 4f70745e095d7b00d07194791ea7d9f3dab46407 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:05:40 +0200 Subject: [PATCH 049/126] docs: apply the integrity audit's licensed dispositions --- docs/domain/glossary.md | 7 +- ...26-09-02-ledger-as-finding-state-design.md | 78 +++++++++++-------- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index baf921e..d50e167 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -329,9 +329,10 @@ diff-scoped chain — is read by folding these. _Avoid_: round title, round record (for the heading alone) **Disposition line**: -One line of the disposition ledger carrying the state of one Finding: -its leading token is that state, its clauses the payload. The unit the -ledger's state machine acts on. +One line of the disposition ledger carrying the state of one Finding, or +of one change the developer directed mid-round, which is not a Finding +and carries no severity: its leading token is that state, its clauses +the payload. The unit the ledger's state machine acts on. _Avoid_: finding line, ledger entry **Gate line**: diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index 7c87cea..3fa46ab 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -39,7 +39,9 @@ levels the shipped grammar conflates: - a **round heading** records one dispatch and never changes; - a **disposition line** carries the mutable state of one finding; - a **gate line** carries the state of one hit — a smaller machine - sharing the container but not the vocabulary. + sharing the container and one clause, `counter:`, but neither the + state set nor the graded and licensed slots a disposition line + carries. Loop state proper — the round count, the all-Minor signal, the diff-scoped chain — is derived by folding the headings. It is stored @@ -237,15 +239,22 @@ with evidence rather than by taste. the next gate episode regenerates it for the price of the cheapest agent in the system. A lost finding is gone forever; a lost hit is not. The state has also never occurred, and minting it would - contradict two glossary entries that call a hit binary. + contradict the glossary's **Hit** entry, the one that calls a hit + binary, and would force a second widening of **Audit agent**, whose + bar enumerates exactly two dispositions. - **No `why:` clause on `held`.** Its value is drawn from a closed four-way set — no license, a contradiction between decisions, a disputed finding, or one that could go either way — which the `question:` phrasing already carries. -- **No episode identity for gates.** One consumer needs it — the - re-dispatch bound's counter — and only across session loss. Losing it - costs at most two dispatches on the cheapest family. Let it die with - the session. +- **No episode identity for gates.** One consumer needs it + operationally — the re-dispatch bound's counter, and only across + session loss — at a cost of at most two dispatches on the cheapest + family. A second consumer emerged while this document was being + written: a reader reconstructing which episode produced which line, + who without it can draw a false conclusion from the record, as the + closing section documents. The refusal stands on the operational + price; the legibility price is now measured rather than assumed, and + is what a later wave should weigh when reopening this. - **No structured block, sidecar file, or git as the diff source.** An LLM hand-writes this record either way, so structure buys checkability the writer's nature does not deliver; and the lifecycle rule keeps @@ -285,8 +294,9 @@ lint's first act the condemnation of every committed line. - `plugins/working-process/rules/spec-plan-lifecycle.md` — the four states and their shapes, the clause table, the authorizer rule, the write-ahead sentence, the corrected gate discriminator, the refusals, - and the relitigation clause rekeyed to `ruling:`. Two further sites - the grilling found: the Unfinished-work section says a ledger close is + the relitigation clause rekeyed to `ruling:`, and the sentence + recording that pre-merge ledger lines stay as written. Two further + sites the grilling found: the Unfinished-work section says a ledger close is `open` or `held` becoming `resolved `, which the merge makes `fixed ` or `declined `; and two sentences call the list's own entry a "review-loop ledger entry", a phrase the glossary @@ -367,16 +377,16 @@ deferred its line here, as the placement rule's one deferral case prescribes. - hit dismissed 2026-09-02 — the glossary's new `ledger entry` ban is violated by `spec-plan-lifecycle.md` lines 228 and 272; counter: both say "review-loop ledger entry" for the Unfinished-work list's own entry, not a disposition line, so the banned sense is not the one in use — and Changes by file already schedules both rewordings, the designed sequence being glossary at grilling, rules at implementation. The round confirmed the dismissal on both legs -- fixed — [Important] the relitigation fold had no expressible production: a re-raise folded against a `ruling:` line still needs its own terminal line, which must be `declined` and so must carry `ruling:` — but no developer ruled on the new finding, so the line either misreported its authorizer or could not be written. The same shape as the audit's defect 1, in the document that exists to cure it; ruling: 2026-09-02; the developer chose the cited-authorizer shape over a separate `folds:` clause and over producing no line at all — the fold now takes `declined ` with `ruling:` carrying the prior ruling's date and a citation of the folded line, the clause table and the glossary's **Ruling** entry both widened to admit a cited authorization -- fixed — [Minor] "the Unfinished-work commands anchor on `^- `" was true of one of five; license: the five published commands read from the rule; the claim now names the split and rests the payload-is-free conclusion on the scope guard, which is what actually defends it -- fixed — [Minor] "Historical ledger lines stay as written" sat beside a scheduled rewrite of one historical line; license: the spec's own distinction between remapping under the merge and normalizing to a shape defined later; the exception is now stated with its reason -- fixed — [Minor] wave one routed implementer question 3 here and only its missing-anchor half was carried; license: wave one's own routing sentence; the autonomy-and-cap half joins the seams, deliberately unanswered because it decides the loop's authority rather than the ledger's shape -- fixed — [Minor] "163 severity slots" counted lines, not slots; license: the recount — 164 occurrences across 163 lines, one audit line quoting two; both numbers now stated +- fixed 2026-09-02 — [Important] the relitigation fold had no expressible production: a re-raise folded against a `ruling:` line still needs its own terminal line, which must be `declined` and so must carry `ruling:` — but no developer ruled on the new finding, so the line either misreported its authorizer or could not be written. The same shape as the audit's defect 1, in the document that exists to cure it; ruling: 2026-09-02; the developer chose the cited-authorizer shape over a separate `folds:` clause and over producing no line at all — the fold now takes `declined ` with `ruling:` carrying the prior ruling's date and a citation of the folded line, the clause table and the glossary's **Ruling** entry both widened to admit a cited authorization +- fixed 2026-09-02 — [Minor] "the Unfinished-work commands anchor on `^- `" was true of one of five; license: the five published commands read from the rule; the claim now names the split and rests the payload-is-free conclusion on the scope guard, which is what actually defends it +- fixed 2026-09-02 — [Minor] "Historical ledger lines stay as written" sat beside a scheduled rewrite of one historical line; license: the spec's own distinction between remapping under the merge and normalizing to a shape defined later; the exception is now stated with its reason +- fixed 2026-09-02 — [Minor] wave one routed implementer question 3 here and only its missing-anchor half was carried; license: wave one's own routing sentence; the autonomy-and-cap half joins the seams, deliberately unanswered because it decides the loop's authority rather than the ledger's shape +- fixed 2026-09-02 — [Minor] "163 severity slots" counted lines, not slots; license: the recount — 164 occurrences across 163 lines, one audit line quoting two; both numbers now stated - hit dismissed 2026-09-02 — Changes by file prescribes edits to `spec-plan-lifecycle.md` the commit does not contain; counter: this is a design document, and Changes by file is a promise about implementation rather than an edit - hit dismissed 2026-09-02 — the same, for `workflow.md`; counter: as above - hit dismissed 2026-09-02 — the same, for wave one's record and its bare `dismissed` line; counter: as above - hit dismissed 2026-09-02 — that the previous gate's dismissal contradicts Changes by file by calling the rewordings "scheduled"; counter: both texts say the same thing, and the audit read "scheduled for implementation" as "scheduled for a later wave" -- fixed — the developer, reading the Important above, asked why a round re-raises a settled finding at all; the answer is that a diff-scoped round is formally cut off from the ledger, so the cause is upstream of the fold; ruling: 2026-09-02; a new section puts the ledger permanently in a diff-scoped round's context, protecting settled and `held` lines while leaving session fixes as legitimate targets +- fixed 2026-09-02 — the developer, reading the Important above, asked why a round re-raises a settled finding at all; the answer is that a diff-scoped round is formally cut off from the ledger, so the cause is upstream of the fold; ruling: 2026-09-02; a new section puts the ledger permanently in a diff-scoped round's context, protecting settled and `held` lines while leaving session fixes as legitimate targets That line, and every other in this section carrying `ruling:`, is written in the grammar this design proposes rather than the one it @@ -395,19 +405,19 @@ exists to prevent. ### 2026-09-02 — architect, fable 5, blocking (round 2, diff-scoped) -- fixed — [Important] the scope section licensed a re-raise "with new evidence" while the fold stayed unconditional, so the licensed path had no disposition, and an autonomous fold of an evidence-bearing challenge is the arbitration the workflow rule forbids; ruling: 2026-09-02; the fold now covers evidence-free re-raises only, and an evidence-bearing one routes to `held` with `counter:` citing the prior ruling -- fixed — [Important] `[n/a]` was lawful under neither grammar, since all four shapes require `[]` and the glossary admits three values — the authorizer gap closed, the grade gap did not; ruling: 2026-09-02; severity is omitted entirely on a line whose sole authorizer is `ruling:` and which no reviewer graded, which is the absence of a grade rather than a fourth value -- fixed — [Minor] the fold's citation had no slot; license: the fold production this wave wrote; `ruling:` now carries the prior date followed by `folding
` -- fixed — [Minor] this document's own deferred gate line read bare `- dismissed 2026-09-02`, the shape it schedules normalizing away elsewhere; license: the `hit dismissed` shape wave one shipped; the token is restored -- fixed — [Minor] the recount was falsified by the commit that wrote it, which added five slots in its own ledger while stating 164; license: the recount itself; the number is gone and the universal claim stands, with the reason a frozen count cannot survive a growing ledger -- fixed — [Minor] aggregating four gate hits into one line contradicted the **Gate line** entry this design owns; license: that entry; split into four lines rather than amending the definition, which would pre-empt an open question about controlled aggregation in reports -- fixed — [Minor] "those carrying `ruling:`, and `declined` lines" was redundant and did not cover historical settled lines; license: the authorizer rule; the conjunct is gone and pre-design lines are named as settled by their token alone +- fixed 2026-09-02 — [Important] the scope section licensed a re-raise "with new evidence" while the fold stayed unconditional, so the licensed path had no disposition, and an autonomous fold of an evidence-bearing challenge is the arbitration the workflow rule forbids; ruling: 2026-09-02; the fold now covers evidence-free re-raises only, and an evidence-bearing one routes to `held` with `counter:` citing the prior ruling +- fixed 2026-09-02 — [Important] `[n/a]` was lawful under neither grammar, since all four shapes require `[]` and the glossary admits three values — the authorizer gap closed, the grade gap did not; ruling: 2026-09-02; severity is omitted entirely on a line whose sole authorizer is `ruling:` and which no reviewer graded, which is the absence of a grade rather than a fourth value +- fixed 2026-09-02 — [Minor] the fold's citation had no slot; license: the fold production this wave wrote; `ruling:` now carries the prior date followed by `folding
` +- fixed 2026-09-02 — [Minor] this document's own deferred gate line read bare `- dismissed 2026-09-02`, the shape it schedules normalizing away elsewhere; license: the `hit dismissed` shape wave one shipped; the token is restored +- fixed 2026-09-02 — [Minor] the recount was falsified by the commit that wrote it, which added five slots in its own ledger while stating 164; license: the recount itself; the number is gone and the universal claim stands, with the reason a frozen count cannot survive a growing ledger +- fixed 2026-09-02 — [Minor] aggregating four gate hits into one line contradicted the **Gate line** entry this design owns; license: that entry; split into four lines rather than amending the definition, which would pre-empt an open question about controlled aggregation in reports +- fixed 2026-09-02 — [Minor] "those carrying `ruling:`, and `declined` lines" was redundant and did not cover historical settled lines; license: the authorizer rule; the conjunct is gone and pre-design lines are named as settled by their token alone ### 2026-09-02 — architect, fable 5, concerns (round 3, diff-scoped) -- fixed — [Minor] the states block's caption said "a `ruling:`-only line" where the rule twelve lines below requires two legs, and this document's own three `ruling:`-only lines carry `[Important]` because a reviewer graded them; license: that fuller paragraph; the caption now carries both legs -- fixed — [Minor] a fold against a pre-design settled line had no date to cite, since historical lines carry no authorizer clause; license: this design's own statement that such lines are settled by their token alone; the fold cites the date on that token, which is when the developer decided -- fixed — [Minor] "without new evidence" named no comparison base, and a wrong not-new call silently performs the arbitration the split exists to prevent; license: the workflow rule's triage principle that a finding which could go either way is a decision; evidence is new relative to what the folded line records, and a session that cannot tell holds +- fixed 2026-09-02 — [Minor] the states block's caption said "a `ruling:`-only line" where the rule twelve lines below requires two legs, and this document's own three `ruling:`-only lines carry `[Important]` because a reviewer graded them; license: that fuller paragraph; the caption now carries both legs +- fixed 2026-09-02 — [Minor] a fold against a pre-design settled line had no date to cite, since historical lines carry no authorizer clause; license: this design's own statement that such lines are settled by their token alone; the fold cites the date on that token, which is when the developer decided +- fixed 2026-09-02 — [Minor] "without new evidence" named no comparison base, and a wrong not-new call silently performs the arbitration the split exists to prevent; license: the workflow rule's triage principle that a finding which could go either way is a decision; evidence is new relative to what the folded line records, and a session that cannot tell holds Round 3 judged the symmetry sound rather than rhetorical: an authorizer is constitutive of a terminal transition and is therefore cited when it @@ -421,16 +431,20 @@ gate's integrity audit reads with two quotes per defect at the same tier over a broader scope. The document is done being reviewed in this loop. Loop closed 2026-09-02 by the developer, on round 3's stop signal and -with every finding of every round disposed. Three architect rounds — -concerns, blocking, concerns — and three propagation gate episodes, one -CLEAN and two producing five hits, every one dismissed with a written -counter-derivation and none requiring a fix. The next reader is the +with every finding of every round disposed. Three architect rounds +ended concerns, blocking, concerns; every propagation gate episode +returned either CLEAN or hits that were dismissed with a written +counter-derivation, and none required a fix. The next reader is the consumption gate's integrity audit, before the plan is written. -A first draft of this paragraph stated six episodes and three fixes, -conflating this loop's gates with the previous wave's. The recount is -the third time in this document that a frozen number was wrong — which -is why the severity section now states none. +No episode or hit count appears here, and the omission is the lesson +rather than an oversight. Two drafts of this paragraph carried counts +and both were wrong: the first conflated this loop's gates with the +previous wave's, and the second froze a total that a later gate episode +invalidated by writing one more line into this very section — two +paragraphs below the sentence saying a growing ledger falsifies any +frozen number. The section reports what happened; the lines are the +count. - hit dismissed 2026-09-02 — that the episode counts above invert the record, since all five `hit dismissed` lines sit under the round-1 heading and so come from one episode; counter: the placement rule writes gate lines under the *last* round's heading at gate time, so the gate before round 1 deferred its line to that stamp and the gate before round 2 wrote four more under the same heading — two episodes, five hits, and the third CLEAN before round 3. The count stands From 87f684036458e23542f7c8384525eb00c5fac3fc Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:12:09 +0200 Subject: [PATCH 050/126] docs: settle the integrity audit's seven implementer questions --- docs/domain/glossary.md | 5 +- ...26-09-02-ledger-as-finding-state-design.md | 50 +++++++++++++++---- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index d50e167..5de0f42 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -223,8 +223,9 @@ _Avoid_: developer override, manual close The developer's authorization of one finding's disposition, written as the `ruling: ` clause on that finding's ledger line — dated fresh, or carrying an earlier ruling's date where the line folds a re-raise -against it. Closes a finding; the round-level counterpart is an -Adjudication. +against it. On a fold against a line written before the clause existed, +the date on that line's own terminal token is the earlier ruling. Closes +a finding; the round-level counterpart is an Adjudication. _Avoid_: developer decision (as the name), developer fix **Fallback**: diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index 3fa46ab..bae63de 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -66,6 +66,13 @@ below: Unfinished-work list anchors. `fixed` and `declined` are terminal and say what became of the document: it changed, or it stands. +The two dates on a terminal line record different events and are both +written even when they coincide. The leading date is when the line +reached its terminal state; `ruling:` is when the decision it cites was +taken. On an ordinary developer-authorized line the two are the same +day and say so; on a fold they differ, and that divergence is the point +of carrying both. + The severity slot is a reviewer's grade, so it is omitted exactly where there is none: a line whose sole authorizer is `ruling:` and which no reviewer graded — a change the developer directed mid-round — carries @@ -182,6 +189,13 @@ never as a review target.** What that protects is narrow and deliberate: diff-scoping was adopted for, since repair-born defects are the dominant late-round class. +Narrative prose between the lines of a `## Review rounds` section is +lawful and expected. The grammar governs headings, lines and their +indented payload; a paragraph explaining why a wave went the way it did +belongs there too, and every reason this loop found worth keeping was +written as one. A lint over this section reads the anchored lines and +ignores the prose. + The reviewer learns what it may not reopen, never what it may not find. Naming the section rather than copying its lines keeps the brief from growing with the round count, and follows the same @@ -228,7 +242,9 @@ beside six `resolved 2026-09-01` disposition lines under one heading, and two episodes share the date 2026-08-31. **The `hit` token is the discriminator.** A wrong stated reason invites a later session to correct the right practice, so the sentence is replaced rather than -dropped. +dropped — and only its date claim is. The same sentence concludes that +a gate never mints a heading of its own, which stands on the round +heading's grammar being closed, a reason the date never carried. ## What this does not build @@ -294,9 +310,12 @@ lint's first act the condemnation of every committed line. - `plugins/working-process/rules/spec-plan-lifecycle.md` — the four states and their shapes, the clause table, the authorizer rule, the write-ahead sentence, the corrected gate discriminator, the refusals, - the relitigation clause rekeyed to `ruling:`, and the sentence - recording that pre-merge ledger lines stay as written. Two further - sites the grilling found: the Unfinished-work section says a ledger close is + the relitigation clause rekeyed to `ruling:`, the sentence recording + that pre-merge ledger lines stay as written, the retained historical + `resolved` shapes, the lawfulness of narrative prose between ledger + lines, and — from "What a diff-scoped round may read" — its grammar + half: that a pre-design line is settled by its token alone and that a + fold cites the date on it. Two further sites the grilling found: the Unfinished-work section says a ledger close is `open` or `held` becoming `resolved `, which the merge makes `fixed ` or `declined `; and two sentences call the list's own entry a "review-loop ledger entry", a phrase the glossary @@ -304,9 +323,14 @@ lint's first act the condemnation of every committed line. "review-loop entry" instead. - `plugins/working-process/rules/workflow.md` — the oscillation tripwire rekeyed to `license:`, the `blocking` terminator's prohibition - deleted, the cap's contact definition with its cannot-count - escalation, and the re-dispatch brief's scope clause putting the - ledger permanently in a diff-scoped round's context. + deleted, and the cap's contact definition with its cannot-count + escalation. From "What a diff-scoped round may read" it takes the + reviewer's behaviour: the ledger's permanent place in a diff-scoped + round's context, the three protection tiers, and the base against + which evidence counts as new. The split follows the two rules' own + division — workflow says what a round does, the lifecycle rule says + what the record is — so the grammar half of that section goes below + rather than here. - `docs/domain/glossary.md` — already changed by the grilling, not by the implementation: six new terms (**Adjudication** and **Ruling** as a level-distinguishing pair; **Disposition ledger**, **Round @@ -322,11 +346,19 @@ lint's first act the condemnation of every committed line. Historical ledger lines stay as written, with one sentence recording that they predate the merge, as the `scope` token's introduction already -established. The bare `- dismissed 2026-08-31` line above is the one +established. The shipped `resolved ` and `resolved +(declined)` shapes are kept in the rule as described historical forms +rather than deleted: a reader must still parse pre-merge documents, and +a fold against a pre-design settled line cites a date off a token the +live grammar no longer produces. The bare `- dismissed 2026-08-31` line above is the one exception, and for a different reason: it is not a line the merge remaps but a line that never matched any shape, written before the `hit dismissed` shape existed. Normalizing it to a shape its own wave -later defined is not a rewrite under the merge. +later defined is not a rewrite under the merge. That edit records +itself where it happens: a gate line in wave one's own ledger, under +its last round heading. Wave one carries an adjudicated verdict, and +editing a stamped document's body without a trace there is the thing +wave one itself refused to do. Merging a published token narrows a shipped convention, so the release carrying this takes a minor bump. From 98c7079c63121d22f73e5e5c12e79bc1f06363a9 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:13:03 +0200 Subject: [PATCH 051/126] docs: stamp the integrity audit on the wave-two spec --- docs/specs/2026-09-02-ledger-as-finding-state-design.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index bae63de..9d57b0b 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -4,6 +4,7 @@ date: 2026-09-02 status: draft grilled: 2026-09-02 architect: concerns (resolved 2026-09-02) +integrity: 2026-09-02 (sha: bf41005) revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-08-31-review-loop-errata-wave-one.md] branch: feature/audit-errata base: develop From 375e69f0e5c786a95e250d68230b7df3e98d08bc Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:27:57 +0200 Subject: [PATCH 052/126] docs: implementation plan for the ledger-as-finding-state spec --- .../2026-09-02-ledger-as-finding-state.md | 789 ++++++++++++++++++ 1 file changed, 789 insertions(+) create mode 100644 docs/plans/2026-09-02-ledger-as-finding-state.md diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md new file mode 100644 index 0000000..e00eda4 --- /dev/null +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -0,0 +1,789 @@ +--- +ticket: none +date: 2026-09-02 +status: draft +spec: ../specs/2026-09-02-ledger-as-finding-state-design.md +branch: feature/audit-errata +base: develop +--- + +# Ledger as Finding State Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Rewrite the disposition ledger's grammar so the leading token names a state and a clause names the authorizer, replacing five states with four and moving two shipped rules off the token they currently discriminate on. + +**Architecture:** Two rule files change and one spec is normalized. `spec-plan-lifecycle.md` owns the record — states, shapes, clauses, gate lines, the Unfinished-work list. `workflow.md` owns the loop's behaviour — the tripwire, the terminators, the cap, what a round reads. The split follows the two rules' existing division of labour, so no sentence moves between them beyond what each task names. + +**Tech Stack:** Markdown rule files distributed as a Rules payload; `rg` commands published inside the rules are the enforcement mechanism; `claude plugin validate` is the structural check. + +## Global Constraints + +- **No code.** Every deliverable is prose in a Markdown file. The verification for each task is a grep whose result changes, plus `claude plugin validate`. +- **Edit with the Edit tool, never `sed -i` or `printf >>`** — the process-artifacts rule requires it for artifacts under `docs/` and applies equally to rule files here. +- **Line width follows each file's existing habit** — prose wraps at ~72 characters; the indented grammar blocks and `rg` command lines run long and stay on one line. +- **Public-repo hygiene:** English only, no machine-specific paths, no company or client names. +- **`claude plugin validate .` and `claude plugin validate plugins/working-process` must both pass** after every task. +- **Historical ledger lines are never rewritten** to the new grammar. One task normalizes exactly one line, for a reason that task states. +- **No version bump.** `plugins/working-process/.claude-plugin/plugin.json` already carries `0.14.0-dev.audit-errata`; the release PR mints the real number. This branch dogfoods through `--plugin-dir` and project-level rules, neither of which is cache-keyed, so the discriminator needs no re-mint. +- **The spec is the source.** Where this plan and `docs/specs/2026-09-02-ledger-as-finding-state-design.md` disagree, the spec wins and the plan is wrong. + +--- + +### Task 1: The four states, their shapes, and the write-ahead discipline + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the shapes block and bullets under `## The disposition ledger` + +**Interfaces:** +- Produces: the four leading tokens `open`, `held`, `fixed `, `declined `, and the rule that a severity bracket is omitted when both legs hold. Tasks 2, 3, 5 and 7 all name these tokens. + +- [ ] **Step 1: Write the failing check** + +```bash +# The old five-shape block must still be present, and the new tokens absent. +grep -c '^ - resolved — \[\]' plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^ - declined ' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +- [ ] **Step 2: Run it to confirm the starting state** + +Expected: first command prints `1`, second prints `0`. + +- [ ] **Step 3: Replace the shapes block** + +Replace these five lines: + +``` + - fixed — [] ; license: ; + - held — [] ; question: [; counter: ] + - open — [] + - resolved — [] ; landed in
+ - resolved (declined) — [] ; +``` + +with these four, plus the bracketless variant and the paragraphs that follow: + +``` + - open — [] + - held — [] ; question: ; options: + - fixed — [] ; ; + - declined — [] ; ; + +The severity bracket is omitted on a line whose sole authorizer is +`ruling:` **and** which no reviewer graded — both legs, never one: + + - fixed ; ruling: ; + +`open` and `held` are the non-terminal states, and the only two the +Unfinished-work list anchors. `fixed` and `declined` are terminal and +say what became of the document: it changed, or it stands. + +The two dates on a terminal line record different events and are both +written even when they coincide. The leading date is when the line +reached its terminal state; `ruling:` is when the decision it cites was +taken. On an ordinary developer-authorized line the two are the same day +and say so; on a fold they differ, and that divergence is the point of +carrying both. + +The severity slot is a reviewer's grade, so it is omitted exactly where +there is none: a change the developer directed mid-round is not a +finding, and inventing a grade for it would be the same manufacture the +authorizer rule forbids. This adds no fourth severity value; the +glossary's three stand. + +`fixed` and `resolved` merge because they were never two states. Both +mean the document changed on account of this finding, and they differed +only in who authorized it, which is now a clause. Merging also frees a +word the rules used for two objects — `concerns (resolved )` +annotates a verdict, while `resolved ` annotated a finding. +``` + +- [ ] **Step 4: Replace the four state bullets below the block** + +Replace the `open` / `fixed` / `held` / `resolved ` bullets with: + +``` +- `open` — written at stamp time, before the findings are triaged. An + `open` line surviving a session means the remediation never ran, and + the document's next touch re-offers it. +- `held` — the finding needs the developer. The line carries the + concrete question and the options with the session's recommendation; + where the finding is disputed or contested, `counter:` carries the + evidence the developer needs in order to answer, and the oscillation + tripwire's named flip is that evidence. +- `fixed ` — the document changed on account of this finding. Its + authorizer says who decided: `license:` where the session cited a + written decision, `ruling:` where the developer did. +- `declined ` — the document stands. It always carries `ruling:`, + because declining is a decision and triage gives a session no license + to decide. +``` + +- [ ] **Step 5: Add the write-ahead paragraph** + +Immediately after those bullets, add: + +``` +Each disposition line is written before the edit it describes, or with +it — never batched at the end of a wave. The dangerous failure is not a +session dying mid-round but a fix wave half-applied with no lines +written: the body has changed, nothing says which change belongs to +which finding, and the next round's brief reads a diff source that is +silently wrong. Writing contemporaneously makes a partial wave +self-evident, since `open` and `fixed` lines mixed under one heading say +exactly where the session stopped. +``` + +- [ ] **Step 6: Run the check again** + +Expected: first command prints `0`, second prints `1`. + +- [ ] **Step 7: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both print `✔ Validation passed`. + +- [ ] **Step 8: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): four ledger states, authorizer as a clause" +``` + +--- + +### Task 2: The clause table + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — after the state bullets from Task 1 + +**Interfaces:** +- Consumes: the four tokens from Task 1. +- Produces: the clause names `license:`, `ruling:`, `question:`, `options:`, `counter:`, `deviation:`. Tasks 5, 8 and 10 name `license:` and `ruling:`. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c '^| `ruling: ` |' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +- [ ] **Step 2: Run it** + +Expected: `0`. + +- [ ] **Step 3: Add the table and its two rules** + +After Task 1's write-ahead paragraph, add: + +``` +The leading token is a queryable state. Clauses are payload. + +| clause | carries | on | +|---|---|---| +| `license: ` | the written decision the session acted on | `fixed` | +| `ruling: ` | the developer authorized it; on a fold, the prior ruling's date followed by `folding
` naming what it folds against | `fixed`, `declined` | +| `question:` | the question, phrased so one short answer resolves it | `held` | +| `options:` | the options and the session's recommendation | `held` | +| `counter:` | the session's evidence where the finding is disputed or contested | `held` | +| `deviation:
` | where the rationale for departing from a reviewer's suggestion lives | `fixed` | + +`question:` and `options:` are both required on a `held` line: the batch +that relays them is a transcript, and a session that dies between the +relay and the answer leaves the next session to re-derive the options, +possibly differently, so the developer answers a question that silently +changed. `counter:` and `deviation:` are conditional, written whenever +their condition holds. + +Every terminal line carries exactly one authorizer. + +Payload costs nothing structurally. Four of the five Unfinished-work +commands anchor a frontmatter field and are held to the frontmatter +block by the list's default scope guard, so no body line reaches them at +all; the fifth is this ledger's own, anchored on `^- `, which an indented +continuation does not match. Payload under a line is therefore invisible +to every published command, and where it runs long it belongs in +indented sub-bullets rather than in a longer line. +``` + +- [ ] **Step 4: Run the check again** + +Expected: `1`. + +- [ ] **Step 5: Verify the anchor claim against the file itself** + +```bash +grep -c "rg -[a-z]* --no-ignore --crlf '\^" plugins/working-process/rules/spec-plan-lifecycle.md +grep -c "rg -n --no-ignore --crlf '\^- " plugins/working-process/rules/spec-plan-lifecycle.md +``` + +Expected: `6` and `1` — six published commands in the file, of which one anchors `^- `. Five of the six are Unfinished-work entries; the sixth is the `revises:` lookup, which is not one. If the first number is not 6, the claim "four of the five" is wrong and must be recounted before committing. + +- [ ] **Step 6: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): the ledger's clause table" +``` + +--- + +### Task 3: Historical shapes, the pre-merge sentence, and lawful prose + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — after the clause table + +**Interfaces:** +- Consumes: the merge from Task 1. +- Produces: the statement that `resolved ` and `resolved (declined)` remain parseable historical forms. Task 5's fold and Task 11's normalization both rely on it. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c 'described historical forms' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +- [ ] **Step 2: Run it** + +Expected: `0`. + +- [ ] **Step 3: Add the paragraph** + +``` +Ledger lines written before this merge stay as written, as the `scope` +token's introduction already established. The shapes they use — +`resolved ` and `resolved (declined)` — are kept here as +described historical forms rather than deleted: a reader must still +parse pre-merge documents, and a fold against a pre-design settled line +cites a date off a token the live grammar no longer produces. + +Narrative prose between the lines of a `## Review rounds` section is +lawful and expected. This grammar governs headings, lines, and their +indented payload; a paragraph explaining why a wave went the way it did +belongs there too. A lint over the section reads the anchored lines and +ignores the prose. +``` + +- [ ] **Step 4: Run the check again** + +Expected: `1`. + +- [ ] **Step 5: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): retain historical ledger shapes, permit prose" +``` + +--- + +### Task 4: The gate discriminator + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md:~185-195` — the paragraph under `### Gate lines` beginning "Both are written at gate time" + +**Interfaces:** +- Consumes: nothing from earlier tasks. +- Produces: no new names. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c 'The date each line carries tells a gate episode apart' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +- [ ] **Step 2: Run it** + +Expected: `1`. + +- [ ] **Step 3: Replace the false reason, keeping the conclusion** + +Replace: + +``` +Both are written at gate time, under the last round's heading. The date +each line carries tells a gate episode apart from that round's own +findings, so a gate never mints a heading of its own — the round +heading's grammar is closed, and a gate is not a round. +``` + +with: + +``` +Both are written at gate time, under the last round's heading. The `hit` +token tells a gate line apart from that round's own findings; the date +does not, since a gate episode and the round it precedes commonly share +one. A gate still never mints a heading of its own, on the separate +ground that the round heading's grammar is closed and a gate is not a +round. +``` + +- [ ] **Step 4: Run the check again** + +Expected: `0`. + +- [ ] **Step 5: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "fix(working-process): the hit token discriminates a gate line, not the date" +``` + +--- + +### Task 5: The relitigation clause, rekeyed + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the paragraph beginning "A resolved held line is a recorded decision" + +**Interfaces:** +- Consumes: `ruling:` and `license:` from Task 2; the historical-forms statement from Task 3. +- Produces: the three-way branch that Task 10's reviewer-scope text refers to. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c 'A resolved held line is a recorded decision' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +- [ ] **Step 2: Run it** + +Expected: `1`. + +- [ ] **Step 3: Replace the paragraph** + +Replace: + +``` +A resolved held line is a recorded decision. When a later round re-raises +the problem it settled, the new finding is folded and cited against that +line, never asked again — state prevents relitigation, not the +reviewer's memory. +``` + +with: + +``` +A line carrying `ruling:` is a recorded developer decision, and what a +later round may do with it depends on what that round brings: + +- re-raised without new evidence — folded and cited, never asked again; + the fold produces `declined ` carrying `ruling:` with the prior + ruling's date and a `folding` citation of the line it folds against, + so the authorizer is cited rather than manufactured; +- re-raised with new evidence — `held`, its `counter:` citing the prior + ruling, because a session that folded this alone would arbitrate + between a reviewer and a recorded developer decision. + +Evidence is new relative to what the folded line records — its claim and +the reasoning its clauses carry — not relative to the reviewer's +wording. A session that cannot tell holds rather than folds. + +A pre-design settled line carries no authorizer clause and is settled by +its token alone; a fold against one cites the date on that token, which +is when the developer decided. + +State prevents relitigation, not the reviewer's memory. +``` + +- [ ] **Step 4: Run the check again** + +Expected: `0`, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). + +- [ ] **Step 5: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): relitigation branches on the authorizer clause" +``` + +--- + +### Task 6: The Unfinished-work section's two corrections + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the closing paragraph of `## Unfinished-work list`, and the two sentences at the section's head and tail that read "review-loop ledger entry" + +**Interfaces:** +- Consumes: the four tokens from Task 1. +- Produces: nothing new. + +- [ ] **Step 1: Write the failing check** + +```bash +rg -U -n 'review-loop\s+ledger entry' plugins/working-process/rules/spec-plan-lifecycle.md +grep -c 'becomes `resolved `' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +- [ ] **Step 2: Run it** + +Expected: the first prints three lines covering two occurrences — one whole at line 228, one wrapped across lines 271–272 — and the second prints `1`. + +**`rg -U` is not optional here.** The second occurrence breaks across a line ending, so a single-line `grep` finds only the first and reports the work half done. Any check for this phrase in this file is multi-line. + +- [ ] **Step 3: Reword both "review-loop ledger entry" occurrences** + +Change each to `review-loop entry`. The glossary's **Disposition line** entry bans `ledger entry` as a name for a disposition line, and both sentences mean the Unfinished-work list's own entry — the reword removes the collision without changing the referent. + +- [ ] **Step 4: Correct the close description** + +Replace: + +``` +ledger entry anchors a leading disposition token instead, so there the +close is a rewrite — `open` or `held` becomes `resolved `, and the +anchor stops matching. +``` + +with: + +``` +review-loop entry anchors a leading disposition token instead, so there +the close is a rewrite — `open` or `held` becomes `fixed ` or +`declined `, and the anchor stops matching. +``` + +- [ ] **Step 5: Run the check again** + +Expected: `rg -U -n 'review-loop\s+ledger entry'` prints nothing, and the second command prints `0`. + +- [ ] **Step 6: Run the published command against the repo** + +```bash +rg -n --no-ignore --crlf '^- (open|held) —' docs/ +``` + +Expected: no output. A hit here means a real unfinished line, not a defect in this task; investigate before continuing. + +- [ ] **Step 7: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "fix(working-process): ledger close names the merged tokens" +``` + +--- + +### Task 7: The oscillation tripwire and the blocking terminator + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — the `### Terminators` list + +**Interfaces:** +- Consumes: `license:` from Task 2. +- Produces: nothing new. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c 'a finding re-raised against a `fixed` line' plugins/working-process/rules/workflow.md +grep -c 'A blocking' plugins/working-process/rules/workflow.md +``` + +- [ ] **Step 2: Run it** + +Expected: `1` and `1`. + +- [ ] **Step 3: Rekey the tripwire** + +Replace: + +``` +- Oscillation tripwire: a finding re-raised against a `fixed` line is + never re-fixed autonomously. Two readings of one license are a + contested reading, so it escalates as held, the flip named. +``` + +with: + +``` +- Oscillation tripwire: a finding re-raised against a line carrying + `license:` is never re-fixed autonomously. Two readings of one license + are a contested reading, so it escalates as held, the flip named. A + re-raise against a line carrying `ruling:` is the relitigation case + instead, and the spec-plan-lifecycle rule owns it. +``` + +- [ ] **Step 4: Delete the self-fix prohibition** + +Replace: + +``` +- `blocking` suspends autonomy entirely: relay, stamp, stop. A blocking + round licenses no self-fixes, because reshaping a design the reviewer + judged broken as a whole is design work and re-enters through the + design conversation. `concerns` is the autonomy zone. +``` + +with: + +``` +- `blocking` suspends autonomy entirely: relay, stamp, stop — no further + round without the developer. It licenses no separate fix prohibition, + because triage already holds what the prohibition was reaching for: a + design reshape has no citable license by construction, so it is held + whatever the verdict's grade. +``` + +- [ ] **Step 5: Run the check again** + +Expected: first command prints `0`. + +- [ ] **Step 6: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): tripwire keys on license, blocking drops its fix ban" +``` + +--- + +### Task 8: The cap's contact definition + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — the `Round cap` bullet in `### Terminators` + +**Interfaces:** +- Consumes: nothing. +- Produces: nothing new. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c 'any developer contact resets the count' plugins/working-process/rules/workflow.md +grep -c 'a message from the developer' plugins/working-process/rules/workflow.md +``` + +- [ ] **Step 2: Run it** + +Expected: `1` and `0`. + +- [ ] **Step 3: Replace the bullet** + +Replace: + +``` +- Round cap: three autonomous rounds per document per field without + developer contact. Hitting the cap escalates in one batch — what was + fixed, what remains, why — rather than halting silently, and any + developer contact resets the count. +``` + +with: + +``` +- Round cap: three autonomous rounds per document per field without + developer contact, counting only rounds that returned a verdict. + Hitting the cap escalates in one batch — what was fixed, what remains, + why — rather than halting silently. Developer contact is a message + from the developer: not a relay they read, not an escalation the + session sent, not an unanswered batch. The count is derived from the + round headings and the reset event is recorded nowhere, so the cap is + best-effort by construction; a session that cannot count its own + rounds escalates rather than assuming, since resetting to zero would + let a long session grant itself three fresh rounds after every + compaction. +``` + +- [ ] **Step 4: Run the check again** + +Expected: second command prints `1`. + +- [ ] **Step 5: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): define developer contact, state the cap is best-effort" +``` + +--- + +### Task 9: What a diff-scoped round may read + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — `### Re-dispatch briefs`, after the ledger-supplies-what-changed paragraph + +**Interfaces:** +- Consumes: `license:` and `ruling:` from Task 2; the relitigation branch from Task 5. +- Produces: nothing new. + +- [ ] **Step 1: Write the failing check** + +```bash +grep -c 'always in scope for a diff-scoped round' plugins/working-process/rules/workflow.md +``` + +- [ ] **Step 2: Run it** + +Expected: `0`. + +- [ ] **Step 3: Add the paragraph** + +``` +Diff-scoping forbids re-reviewing the document beyond the diff, and the +ledger is part of the document — so without a clause the reviewer is cut +off from the one section recording what the developer already decided. +The ledger is therefore always in scope for a diff-scoped round as +context, never as a review target, and what that protects is narrow: + +- lines carrying `ruling:` may be re-raised only with new evidence, + which routes to `held` rather than to a fold; +- `held` lines carry questions already put, so a round does not + duplicate one; +- `fixed` lines carrying `license:` get no protection at all — the + previous round's are the diff and are named as the first thing to + attack, and older ones are simply unprotected, since a reviewer told + not to re-raise a fix would lose the property diff-scoping was + adopted for. + +The reviewer learns what it may not reopen, never what it may not find. +Naming the section rather than copying its lines keeps the brief from +growing with the round count. +``` + +- [ ] **Step 4: Run the check again** + +Expected: `1`. + +- [ ] **Step 5: Validate and commit** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): the ledger is standing context for a diff-scoped round" +``` + +--- + +### Task 10: Normalize wave one's bare gate line + +**Files:** +- Modify: `docs/specs/2026-08-31-review-loop-errata-wave-one.md:157` and its `## Review rounds` section + +**Interfaces:** +- Consumes: the `hit dismissed` shape, which wave one itself shipped. +- Produces: nothing. + +- [ ] **Step 1: Write the failing check** + +```bash +rg -n --no-ignore --crlf '^- dismissed ' docs/ +``` + +- [ ] **Step 2: Run it** + +Expected: one hit, `docs/specs/2026-08-31-review-loop-errata-wave-one.md:157`. + +- [ ] **Step 3: Add the `hit` token** + +Change `- dismissed 2026-08-31 — eight sites in the shipped spec…` to `- hit dismissed 2026-08-31 — eight sites in the shipped spec…`, leaving the rest of the line untouched. + +- [ ] **Step 4: Record the edit in wave one's own ledger** + +Under wave one's last round heading, add: + +``` +- hit fixed — this document's own bare `- dismissed 2026-08-31` line predated the `hit dismissed` shape its wave went on to define; the token is added, and nothing else on the line changes +``` + +Wave one carries an adjudicated verdict, and editing a stamped document's body without a trace there is the thing wave one itself refused to do. + +- [ ] **Step 5: Run the check again** + +Expected: no output. + +- [ ] **Step 6: Commit** + +```bash +git add docs/specs/2026-08-31-review-loop-errata-wave-one.md +git commit -m "docs: normalize wave one's bare gate line to the shape it defined" +``` + +--- + +### Task 11: Whole-payload verification + +**Files:** +- Modify: none unless a check fails + +**Interfaces:** +- Consumes: every earlier task. + +- [ ] **Step 1: Run every published Unfinished-work command** + +```bash +rg -l --no-ignore --crlf '^\s*grilled: grilling' docs/ +rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/ +rg -n --no-ignore --crlf '^- (open|held) —' docs/ +rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/ +rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback|integrity):' docs/ +``` + +Expected: the first returns `docs/plans/2026-07-13-rules-distribution.md`, which is a body quotation of the convention and not a frontmatter hit — confirm with `grep -n 'grilled: grilling'` on that file and check the line sits below the closing `---`. The other four return nothing. + +- [ ] **Step 2: Confirm no banned term returned** + +```bash +grep -rn --include='*.md' 'ledger entry' plugins/ docs/domain/ +``` + +Expected: no output. + +- [ ] **Step 3: Confirm the old grammar is gone from the rules** + +```bash +grep -n 'resolved — \[' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +Expected: no output outside the historical-forms paragraph from Task 3. If the paragraph quotes the shape, that single hit is correct. + +- [ ] **Step 4: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 5: Dispatch the propagation gate** + +Run the `propagation-auditor` agent on the cheapest available family over the whole change set, with a positive scope: report only internal contradictions, consumers left behind, and recomputed counters that are wrong. Fix or dismiss each hit with a written derivation, recording dismissals as gate lines in this plan's ledger. + +- [ ] **Step 6: Commit any fixes** + +```bash +git add -A plugins/ docs/ +git commit -m "fix(working-process): close the propagation gate on the ledger rewrite" +``` + +--- + +## Self-review + +**Spec coverage.** Every section of the spec maps to a task: the states and severity omission and write-ahead to Task 1; the clauses and the authorizer rule to Task 2; historical shapes and lawful prose to Task 3; the gate discriminator to Task 4; the fold and the relitigation branch to Task 5; the Unfinished-work corrections to Task 6; the tripwire and blocking terminator to Task 7; the cap to Task 8; the diff-scoped reading scope to Task 9; wave one's line to Task 10. The glossary needs no task — the grilling already changed it. The four refusals need no task: they are decisions not to build, and Task 1's severity paragraph carries the only one with prose consequences. + +**Placeholders.** None. Every step carries the literal text to write or the literal command to run. + +**Name consistency.** `license:`, `ruling:`, `question:`, `options:`, `counter:`, `deviation:`, `folding`, `fixed `, `declined `, `open`, `held`, `hit fixed`, `hit dismissed` are spelled identically in Tasks 1, 2, 5, 6, 7, 9 and 10. + +**One defect the self-review caught.** Task 6's check first asserted two +single-line matches for `review-loop ledger entry`. Only one occurrence +sits on a single line; the other wraps across a line ending, so `grep` +finds one, and an executor would have read that as the work half done. +The check is now `rg -U`, with the reason stated on the step. Every +other phrase check in this plan was re-run against the working tree +before the plan was saved: the five-shape block, the close description, +the tripwire wording, the bare `dismissed` line, and the command counts +all match what their steps expect. + +**Known seam.** Task 2's Step 5 verifies the "four of the five" anchor claim by counting published commands. That count includes the `revises:` lookup, which is not an Unfinished-work entry — the step says so, but a future command added to either group will make the assertion wrong before the prose is. It is a check with a short shelf life, deliberately kept because the alternative is trusting the claim. From bbb81971c87cd3062fe075d326585e6b2380814a Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:32:45 +0200 Subject: [PATCH 053/126] fix: plan phrase checks are multi-line, per the gate's two hits --- .../2026-09-02-ledger-as-finding-state.md | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index e00eda4..cc199cf 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -27,6 +27,7 @@ base: develop - **Historical ledger lines are never rewritten** to the new grammar. One task normalizes exactly one line, for a reason that task states. - **No version bump.** `plugins/working-process/.claude-plugin/plugin.json` already carries `0.14.0-dev.audit-errata`; the release PR mints the real number. This branch dogfoods through `--plugin-dir` and project-level rules, neither of which is cache-keyed, so the discriminator needs no re-mint. - **The spec is the source.** Where this plan and `docs/specs/2026-09-02-ledger-as-finding-state-design.md` disagree, the spec wins and the plan is wrong. +- **Every phrase check against a rule file uses `rg -U`, never `grep`.** These files wrap prose at about 72 characters, so any searched phrase longer than a few words may straddle a line ending — and a single-line `grep` then returns 0 where the phrase is plainly present. Three checks in the first draft of this plan had exactly that fault. Write the pattern with `\s+` where the prose has a space: `rg -U -c 'the phrase\s+continues' `. --- @@ -294,12 +295,12 @@ git commit -m "feat(working-process): retain historical ledger shapes, permit pr - [ ] **Step 1: Write the failing check** ```bash -grep -c 'The date each line carries tells a gate episode apart' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -c 'The date\s+each line carries tells a gate episode apart' plugins/working-process/rules/spec-plan-lifecycle.md ``` - [ ] **Step 2: Run it** -Expected: `1`. +Expected: `1`. The phrase wraps after "The date", so `grep` returns 0 here and `rg -U` is required. - [ ] **Step 3: Replace the false reason, keeping the conclusion** @@ -559,13 +560,13 @@ git commit -m "feat(working-process): tripwire keys on license, blocking drops i - [ ] **Step 1: Write the failing check** ```bash -grep -c 'any developer contact resets the count' plugins/working-process/rules/workflow.md -grep -c 'a message from the developer' plugins/working-process/rules/workflow.md +rg -U -c 'any\s+developer contact resets the count' plugins/working-process/rules/workflow.md +rg -U -c 'a message from the developer' plugins/working-process/rules/workflow.md ``` - [ ] **Step 2: Run it** -Expected: `1` and `0`. +Expected: `1` and `0`. The first phrase wraps after "any", so `grep` returns 0 here and `rg -U` is required. - [ ] **Step 3: Replace the bullet** @@ -776,14 +777,23 @@ git commit -m "fix(working-process): close the propagation gate on the ledger re **Name consistency.** `license:`, `ruling:`, `question:`, `options:`, `counter:`, `deviation:`, `folding`, `fixed `, `declined `, `open`, `held`, `hit fixed`, `hit dismissed` are spelled identically in Tasks 1, 2, 5, 6, 7, 9 and 10. -**One defect the self-review caught.** Task 6's check first asserted two -single-line matches for `review-loop ledger entry`. Only one occurrence -sits on a single line; the other wraps across a line ending, so `grep` -finds one, and an executor would have read that as the work half done. -The check is now `rg -U`, with the reason stated on the step. Every -other phrase check in this plan was re-run against the working tree -before the plan was saved: the five-shape block, the close description, -the tripwire wording, the bare `dismissed` line, and the command counts -all match what their steps expect. +**One defect class, three instances, and the lesson about finding it.** +Task 6's check first asserted two single-line matches for +`review-loop ledger entry`; only one occurrence sits on a single line, +so `grep` found one and an executor would have read that as the work +half done. The self-review caught that instance **and treated it as +isolated** — which it was not. A propagation gate over the committed +plan found two more of exactly the same shape, in Tasks 4 and 8, where a +phrase wraps after "The date" and after "any". A sweep of every phrase +check in the plan then confirmed those three and no fourth. + +The fix is the Global Constraint above rather than three patches: in +files that wrap prose, a phrase check is multi-line or it is unsound. +Finding one instance of a mechanical fault is weak evidence that it is +the only one, and the cheap move is to sweep the class immediately. + +Every other check was re-run against the working tree: the five-shape +block, the close description, the tripwire wording, the bare `dismissed` +line, and the command counts all match what their steps expect. **Known seam.** Task 2's Step 5 verifies the "four of the five" anchor claim by counting published commands. That count includes the `revises:` lookup, which is not an Unfinished-work entry — the step says so, but a future command added to either group will make the assertion wrong before the prose is. It is a check with a short shelf life, deliberately kept because the alternative is trusting the claim. From 00b3eac7300635557906fba30709e960f198d7c3 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:33:57 +0200 Subject: [PATCH 054/126] fix: prose checks go multi-line, the blocking check can actually fail --- docs/plans/2026-09-02-ledger-as-finding-state.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index cc199cf..cb5db5d 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -27,7 +27,7 @@ base: develop - **Historical ledger lines are never rewritten** to the new grammar. One task normalizes exactly one line, for a reason that task states. - **No version bump.** `plugins/working-process/.claude-plugin/plugin.json` already carries `0.14.0-dev.audit-errata`; the release PR mints the real number. This branch dogfoods through `--plugin-dir` and project-level rules, neither of which is cache-keyed, so the discriminator needs no re-mint. - **The spec is the source.** Where this plan and `docs/specs/2026-09-02-ledger-as-finding-state-design.md` disagree, the spec wins and the plan is wrong. -- **Every phrase check against a rule file uses `rg -U`, never `grep`.** These files wrap prose at about 72 characters, so any searched phrase longer than a few words may straddle a line ending — and a single-line `grep` then returns 0 where the phrase is plainly present. Three checks in the first draft of this plan had exactly that fault. Write the pattern with `\s+` where the prose has a space: `rg -U -c 'the phrase\s+continues' `. +- **A check that searches for prose uses `rg -U` with `\s+` between words; a check that searches for an anchored structural pattern uses `grep`.** These files wrap prose at about 72 characters, so a searched phrase may straddle a line ending and a single-line `grep` then returns 0 where the phrase is plainly present — three checks in this plan's first draft had exactly that fault. An anchored pattern like `^ - fixed ` or `^| \`ruling:` cannot straddle by construction, so single-line matching is correct there and multi-line matching would be misleading. --- @@ -245,7 +245,7 @@ git commit -m "feat(working-process): the ledger's clause table" - [ ] **Step 1: Write the failing check** ```bash -grep -c 'described historical forms' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -c 'described\s+historical\s+forms' plugins/working-process/rules/spec-plan-lifecycle.md ``` - [ ] **Step 2: Run it** @@ -350,7 +350,7 @@ git commit -m "fix(working-process): the hit token discriminates a gate line, no - [ ] **Step 1: Write the failing check** ```bash -grep -c 'A resolved held line is a recorded decision' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -c 'A\s+resolved\s+held\s+line\s+is\s+a\s+recorded\s+decision' plugins/working-process/rules/spec-plan-lifecycle.md ``` - [ ] **Step 2: Run it** @@ -420,7 +420,7 @@ git commit -m "feat(working-process): relitigation branches on the authorizer cl ```bash rg -U -n 'review-loop\s+ledger entry' plugins/working-process/rules/spec-plan-lifecycle.md -grep -c 'becomes `resolved `' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -c 'becomes\s+`resolved `' plugins/working-process/rules/spec-plan-lifecycle.md ``` - [ ] **Step 2: Run it** @@ -485,13 +485,13 @@ git commit -m "fix(working-process): ledger close names the merged tokens" - [ ] **Step 1: Write the failing check** ```bash -grep -c 'a finding re-raised against a `fixed` line' plugins/working-process/rules/workflow.md -grep -c 'A blocking' plugins/working-process/rules/workflow.md +rg -U -c 'a\s+finding\s+re-raised\s+against\s+a\s+`fixed`\s+line' plugins/working-process/rules/workflow.md +rg -U -c 'licenses\s+no\s+self-fixes' plugins/working-process/rules/workflow.md ``` - [ ] **Step 2: Run it** -Expected: `1` and `1`. +Expected: `1` and `1`. The second pattern names the clause this task deletes, so it fails if the deletion is skipped; a looser pattern such as `A blocking` would pass either way. - [ ] **Step 3: Rekey the tripwire** @@ -621,7 +621,7 @@ git commit -m "feat(working-process): define developer contact, state the cap is - [ ] **Step 1: Write the failing check** ```bash -grep -c 'always in scope for a diff-scoped round' plugins/working-process/rules/workflow.md +rg -U -c 'always\s+in\s+scope\s+for\s+a\s+diff-scoped\s+round' plugins/working-process/rules/workflow.md ``` - [ ] **Step 2: Run it** From 107dec08447ae04fa5b18320c5d05be021042e12 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 15:56:41 +0200 Subject: [PATCH 055/126] docs: plan round one fix wave - check mechanics, retired-token consumer, anchor tolerance --- .../2026-09-02-ledger-as-finding-state.md | 217 +++++++++++++----- 1 file changed, 162 insertions(+), 55 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index cb5db5d..1438e13 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -2,6 +2,7 @@ ticket: none date: 2026-09-02 status: draft +adversary: blocking spec: ../specs/2026-09-02-ledger-as-finding-state-design.md branch: feature/audit-errata base: develop @@ -27,7 +28,9 @@ base: develop - **Historical ledger lines are never rewritten** to the new grammar. One task normalizes exactly one line, for a reason that task states. - **No version bump.** `plugins/working-process/.claude-plugin/plugin.json` already carries `0.14.0-dev.audit-errata`; the release PR mints the real number. This branch dogfoods through `--plugin-dir` and project-level rules, neither of which is cache-keyed, so the discriminator needs no re-mint. - **The spec is the source.** Where this plan and `docs/specs/2026-09-02-ledger-as-finding-state-design.md` disagree, the spec wins and the plan is wrong. -- **A check that searches for prose uses `rg -U` with `\s+` between words; a check that searches for an anchored structural pattern uses `grep`.** These files wrap prose at about 72 characters, so a searched phrase may straddle a line ending and a single-line `grep` then returns 0 where the phrase is plainly present — three checks in this plan's first draft had exactly that fault. An anchored pattern like `^ - fixed ` or `^| \`ruling:` cannot straddle by construction, so single-line matching is correct there and multi-line matching would be misleading. +- **A check that searches for prose uses `rg -U` and puts `\s+` between *every* pair of words in the pattern; a check that searches for an anchored structural pattern uses `grep`.** These files wrap prose at about 72 characters, so a searched phrase may straddle a line ending and a single-line `grep` then returns 0 where the phrase is plainly present. Four checks in this plan's earlier drafts had exactly that fault, found across three sweeps that each declared the class closed — which is why the constraint is now unconditional rather than applied where a wrap looks likely. Where the wrap falls is not something a reader reliably predicts, and a pattern that is uniformly `\s+` is correct whether or not it wraps, so no judgement is exercised and no instance can be missed. An anchored pattern like `^ - fixed ` or `^| \`ruling:` cannot straddle by construction, so single-line matching is correct there and multi-line matching would be misleading. +- **`rg -c` prints nothing and exits 1 when its pattern does not match** — it never prints `0`. A step asserting absence with `rg` therefore expects *no output*; only `grep -c`, which does print `0`, is given a numeric zero expectation. +- **Leading-anchor tolerance follows the direction of the assertion.** A check asserting that text is *gone* uses a tolerant anchor (`^\s*`), because a leftover the pattern fails to match reads as success — the same false-clean failure the wrapped-phrase class produces. A check asserting that prescribed text is *present* uses the exact anchor (`^ ` for an indented grammar block, `^| ` for a table row), because the indentation is part of what the step prescribes and a tolerant match would accept a malformed block as correct. This is the lifecycle rule's own reasoning applied here: its Unfinished-work anchors are tolerant so a relocated field is still found, and its Misplaced-stamp anchor is exact precisely because there the indentation *is* the defect. One published command is copied verbatim rather than reasoned about — the ledger anchor `^- `, which is strict by design so indented payload cannot match it; a check mirroring a published command reproduces it exactly. --- @@ -43,10 +46,12 @@ base: develop ```bash # The old five-shape block must still be present, and the new tokens absent. -grep -c '^ - resolved — \[\]' plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^\s*- resolved — \[\]' plugins/working-process/rules/spec-plan-lifecycle.md grep -c '^ - declined ' plugins/working-process/rules/spec-plan-lifecycle.md ``` +The two anchors differ deliberately, per the tolerance constraint above. The first ends this task asserting the old shape is *gone*, so it is tolerant — a leftover line at any indent must still be caught. The second ends it asserting the new shape is *present* at the grammar block's own indent, so it is exact — a block written at the wrong indent is not a code block and must fail. + - [ ] **Step 2: Run it to confirm the starting state** Expected: first command prints `1`, second prints `0`. @@ -240,7 +245,9 @@ git commit -m "feat(working-process): the ledger's clause table" **Interfaces:** - Consumes: the merge from Task 1. -- Produces: the statement that `resolved ` and `resolved (declined)` remain parseable historical forms. Task 5's fold and Task 11's normalization both rely on it. +- Produces: the two historical shape lines, quoted verbatim, and the statement that they remain parseable. Task 5's fold and Task 11's Step 3 both rely on them being present in the file. + +**This task reinstates shape lines Task 1 deleted.** Task 1 removes all five old shapes from the live block; this task writes two of them back, in a block explicitly labelled historical. Task 1's own post-edit check is therefore true only at Task 1's completion, and Task 11 accounts for the reinstated pair rather than expecting the file to be free of them. - [ ] **Step 1: Write the failing check** @@ -250,17 +257,22 @@ rg -U -c 'described\s+historical\s+forms' plugins/working-process/rules/spec-pla - [ ] **Step 2: Run it** -Expected: `0`. +Expected: no output. - [ ] **Step 3: Add the paragraph** ``` Ledger lines written before this merge stay as written, as the `scope` -token's introduction already established. The shapes they use — -`resolved ` and `resolved (declined)` — are kept here as -described historical forms rather than deleted: a reader must still -parse pre-merge documents, and a fold against a pre-design settled line -cites a date off a token the live grammar no longer produces. +token's introduction already established. The shapes they use are kept +here as described historical forms rather than deleted: + + - resolved — [] ; landed in
+ - resolved (declined) — [] ; + +A reader must still parse pre-merge documents, and a fold against a +pre-design settled line cites a date off a token the live grammar no +longer produces. These two shapes are described, never minted: no +session writes a new line in either form. Narrative prose between the lines of a `## Review rounds` section is lawful and expected. This grammar governs headings, lines, and their @@ -271,7 +283,13 @@ ignores the prose. - [ ] **Step 4: Run the check again** -Expected: `1`. +Expected: `1`. Also confirm the reinstated shapes are present, which Task 11's Step 3 will re-assert: + +```bash +grep -c '^ - resolved ' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +Expected: `2`. - [ ] **Step 5: Validate and commit** @@ -295,7 +313,7 @@ git commit -m "feat(working-process): retain historical ledger shapes, permit pr - [ ] **Step 1: Write the failing check** ```bash -rg -U -c 'The date\s+each line carries tells a gate episode apart' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -c 'The\s+date\s+each\s+line\s+carries\s+tells\s+a\s+gate\s+episode\s+apart' plugins/working-process/rules/spec-plan-lifecycle.md ``` - [ ] **Step 2: Run it** @@ -326,7 +344,7 @@ round. - [ ] **Step 4: Run the check again** -Expected: `0`. +Expected: no output. - [ ] **Step 5: Validate and commit** @@ -395,7 +413,7 @@ State prevents relitigation, not the reviewer's memory. - [ ] **Step 4: Run the check again** -Expected: `0`, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). +Expected: no output, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). - [ ] **Step 5: Validate and commit** @@ -419,21 +437,27 @@ git commit -m "feat(working-process): relitigation branches on the authorizer cl - [ ] **Step 1: Write the failing check** ```bash -rg -U -n 'review-loop\s+ledger entry' plugins/working-process/rules/spec-plan-lifecycle.md -rg -U -c 'becomes\s+`resolved `' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -n 'review-loop\s+ledger\s+entry' plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -c 'becomes\s+`resolved\s+`' plugins/working-process/rules/spec-plan-lifecycle.md ``` - [ ] **Step 2: Run it** -Expected: the first prints three lines covering two occurrences — one whole at line 228, one wrapped across lines 271–272 — and the second prints `1`. +Expected: the first reports two occurrences of `review-loop ledger entry` — one falling on a single line, in the paragraph about a re-scoped match scope, and one wrapping across a line ending, in the closing paragraph about the anchors. The second prints `1`. + +Line numbers are deliberately not stated: Tasks 1–5 insert text above both occurrences, so any number quoted here would be wrong by the time this task runs. Match on the surrounding sentence instead. **`rg -U` is not optional here.** The second occurrence breaks across a line ending, so a single-line `grep` finds only the first and reports the work half done. Any check for this phrase in this file is multi-line. -- [ ] **Step 3: Reword both "review-loop ledger entry" occurrences** +- [ ] **Step 3: Reword the first occurrence** -Change each to `review-loop entry`. The glossary's **Disposition line** entry bans `ledger entry` as a name for a disposition line, and both sentences mean the Unfinished-work list's own entry — the reword removes the collision without changing the referent. +In the paragraph about the re-scoped match scope, change `the review-loop ledger entry below is the one that does` to `the review-loop entry below is the one that does`. -- [ ] **Step 4: Correct the close description** +The glossary's **Disposition line** entry bans `ledger entry` as a name for a disposition line, and the sentence means the Unfinished-work list's own entry — the reword removes the collision without changing the referent. + +**The second occurrence is not touched here.** It sits inside the block Step 4 replaces wholesale, and Step 4's replacement text already carries the reword. Rewording it now would leave Step 4 quoting text that no longer exists. + +- [ ] **Step 4: Correct the close description, rewording the second occurrence as part of it** Replace: @@ -446,14 +470,16 @@ anchor stops matching. with: ``` -review-loop entry anchors a leading disposition token instead, so there -the close is a rewrite — `open` or `held` becomes `fixed ` or +entry anchors a leading disposition token instead, so there the +close is a rewrite — `open` or `held` becomes `fixed ` or `declined `, and the anchor stops matching. ``` +The word `review-loop` sits on the preceding line and is not part of either block, so dropping `ledger` from the start of the replacement is what completes the reword — the sentence then reads "the review-loop entry anchors a leading disposition token instead". Re-wrap the paragraph to the file's ~72-character habit after the edit. + - [ ] **Step 5: Run the check again** -Expected: `rg -U -n 'review-loop\s+ledger entry'` prints nothing, and the second command prints `0`. +Expected: both commands print nothing. - [ ] **Step 6: Run the published command against the repo** @@ -473,27 +499,50 @@ git commit -m "fix(working-process): ledger close names the merged tokens" --- -### Task 7: The oscillation tripwire and the blocking terminator +### Task 7: `workflow.md`'s three consumers of the retired token **Files:** -- Modify: `plugins/working-process/rules/workflow.md` — the `### Terminators` list +- Modify: `plugins/working-process/rules/workflow.md` — the triage paragraph under `### The review loop`, and the `### Terminators` list **Interfaces:** -- Consumes: `license:` from Task 2. +- Consumes: `license:` and `ruling:` from Task 2; the merge from Task 1. - Produces: nothing new. +The merge in Task 1 retires `resolved` as a disposition token, and `workflow.md` reads it in three places: the triage paragraph's list of license sources, the oscillation tripwire, and the blocking terminator. All three are fixed here, in one file, so no consumer of the retired token is left behind. + - [ ] **Step 1: Write the failing check** ```bash +rg -U -c 'a\s+previously\s+resolved\s+`held`\s+line' plugins/working-process/rules/workflow.md rg -U -c 'a\s+finding\s+re-raised\s+against\s+a\s+`fixed`\s+line' plugins/working-process/rules/workflow.md rg -U -c 'licenses\s+no\s+self-fixes' plugins/working-process/rules/workflow.md ``` - [ ] **Step 2: Run it** -Expected: `1` and `1`. The second pattern names the clause this task deletes, so it fails if the deletion is skipped; a looser pattern such as `A blocking` would pass either way. +Expected: `1`, `1` and `1`. Each pattern names text this task removes, so each fails if its step is skipped; a looser pattern such as `A blocking` would pass either way and verifies nothing. + +- [ ] **Step 3: Rekey the triage paragraph's license sources** -- [ ] **Step 3: Rekey the tripwire** +The triage paragraph lists what a session may cite to license a self-fix, and one item names a state the live grammar stops producing. Replace: + +``` +licenses the fix — a statement in the document itself, a glossary term +or `_Avoid_` ban, a recorded ADR, or a previously resolved `held` +line — and the citation goes on the finding's line in the disposition +``` + +with: + +``` +licenses the fix — a statement in the document itself, a glossary term +or `_Avoid_` ban, a recorded ADR, or a line carrying `ruling:` — and +the citation goes on the finding's line in the disposition +``` + +A held line the developer answered now terminates as `fixed ` or `declined ` carrying `ruling:`, so the authorizer clause is what identifies a recorded developer decision, whatever token the line ends on. The reword also picks up pre-design settled lines, which the old wording missed. + +- [ ] **Step 4: Rekey the tripwire** Replace: @@ -513,7 +562,7 @@ with: instead, and the spec-plan-lifecycle rule owns it. ``` -- [ ] **Step 4: Delete the self-fix prohibition** +- [ ] **Step 5: Delete the self-fix prohibition** Replace: @@ -534,16 +583,16 @@ with: whatever the verdict's grade. ``` -- [ ] **Step 5: Run the check again** +- [ ] **Step 6: Run the check again** -Expected: first command prints `0`. +Expected: all three commands print nothing. Each corresponds to one of Steps 3, 4 and 5, so a skipped step is the one that still prints `1`. -- [ ] **Step 6: Validate and commit** +- [ ] **Step 7: Validate and commit** ```bash claude plugin validate . && claude plugin validate plugins/working-process git add plugins/working-process/rules/workflow.md -git commit -m "feat(working-process): tripwire keys on license, blocking drops its fix ban" +git commit -m "feat(working-process): move workflow.md off the retired resolved token" ``` --- @@ -560,13 +609,13 @@ git commit -m "feat(working-process): tripwire keys on license, blocking drops i - [ ] **Step 1: Write the failing check** ```bash -rg -U -c 'any\s+developer contact resets the count' plugins/working-process/rules/workflow.md -rg -U -c 'a message from the developer' plugins/working-process/rules/workflow.md +rg -U -c 'any\s+developer\s+contact\s+resets\s+the\s+count' plugins/working-process/rules/workflow.md +rg -U -c 'a\s+message\s+from\s+the\s+developer' plugins/working-process/rules/workflow.md ``` - [ ] **Step 2: Run it** -Expected: `1` and `0`. The first phrase wraps after "any", so `grep` returns 0 here and `rg -U` is required. +Expected: `1`, then no output. The first phrase wraps after "any" and the second wraps after "a message" once written, so both are uniformly `\s+` — the second is the instance that made the constraint unconditional. - [ ] **Step 3: Replace the bullet** @@ -626,7 +675,7 @@ rg -U -c 'always\s+in\s+scope\s+for\s+a\s+diff-scoped\s+round' plugins/working-p - [ ] **Step 2: Run it** -Expected: `0`. +Expected: no output. - [ ] **Step 3: Add the paragraph** @@ -637,8 +686,12 @@ off from the one section recording what the developer already decided. The ledger is therefore always in scope for a diff-scoped round as context, never as a review target, and what that protects is narrow: -- lines carrying `ruling:` may be re-raised only with new evidence, - which routes to `held` rather than to a fold; +- settled lines may be re-raised only with new evidence, which routes + to `held` rather than to a fold. A line carrying `ruling:` is settled + by that clause; a historical line written before this design, + `resolved (declined)` included, carries no authorizer clause + and is settled by its token alone. Both are the developer's + decisions, and both are protected on the same footing; - `held` lines carry questions already put, so a round does not duplicate one; - `fixed` lines carrying `license:` get no protection at all — the @@ -732,21 +785,26 @@ rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|ad Expected: the first returns `docs/plans/2026-07-13-rules-distribution.md`, which is a body quotation of the convention and not a frontmatter hit — confirm with `grep -n 'grilled: grilling'` on that file and check the line sits below the closing `---`. The other four return nothing. +These expectations describe the repo as this plan was written, and the process's own artifacts can falsify them at execution time: a spec grilled or a round stamped between now and then is a real unfinished-work hit, not a defect in this plan. Investigate any extra hit against the document it names before continuing, exactly as Task 6's Step 6 directs — a hit here is a question about that document, never a reason to edit this one. + - [ ] **Step 2: Confirm no banned term returned** ```bash -grep -rn --include='*.md' 'ledger entry' plugins/ docs/domain/ +grep -rn --include='*.md' 'ledger entry' plugins/ docs/domain/ | grep -v '_Avoid_' ``` Expected: no output. -- [ ] **Step 3: Confirm the old grammar is gone from the rules** +The `grep -v` is not slack. The glossary's **Disposition line** entry defines the ban by writing the banned phrase — `_Avoid_: finding line, ledger entry` — so an unfiltered sweep necessarily hits the one line that must keep saying it, and the check could never pass in the correct end state. Filtering the definition site is what makes the sweep assert what it means: no *use* of the banned term survives. + +- [ ] **Step 3: Confirm the live grammar is gone and the historical block remains** ```bash -grep -n 'resolved — \[' plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^\s*- resolved — \[' plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^\s*- resolved (declined) — \[' plugins/working-process/rules/spec-plan-lifecycle.md ``` -Expected: no output outside the historical-forms paragraph from Task 3. If the paragraph quotes the shape, that single hit is correct. +Expected: `1` and `1` — the two lines Task 3 writes into its historical-forms block, and nothing else. Task 1 deleted both shapes from the live block; Task 3 reinstated them as described history. Two hits on the first command would mean a live-block line survived. - [ ] **Step 4: Validate** @@ -771,29 +829,78 @@ git commit -m "fix(working-process): close the propagation gate on the ledger re ## Self-review -**Spec coverage.** Every section of the spec maps to a task: the states and severity omission and write-ahead to Task 1; the clauses and the authorizer rule to Task 2; historical shapes and lawful prose to Task 3; the gate discriminator to Task 4; the fold and the relitigation branch to Task 5; the Unfinished-work corrections to Task 6; the tripwire and blocking terminator to Task 7; the cap to Task 8; the diff-scoped reading scope to Task 9; wave one's line to Task 10. The glossary needs no task — the grilling already changed it. The four refusals need no task: they are decisions not to build, and Task 1's severity paragraph carries the only one with prose consequences. +**Spec coverage.** Every section of the spec maps to a task: the states and severity omission and write-ahead to Task 1; the clauses and the authorizer rule to Task 2; historical shapes and lawful prose to Task 3; the gate discriminator to Task 4; the fold and the relitigation branch to Task 5; the Unfinished-work corrections to Task 6; the triage license sources, the tripwire and the blocking terminator — `workflow.md`'s three consumers of the retired token — to Task 7; the cap to Task 8; the diff-scoped reading scope to Task 9; wave one's line to Task 10. The glossary needs no task — the grilling already changed it. The four refusals need no task: they are decisions not to build, and Task 1's severity paragraph carries the only one with prose consequences. **Placeholders.** None. Every step carries the literal text to write or the literal command to run. **Name consistency.** `license:`, `ruling:`, `question:`, `options:`, `counter:`, `deviation:`, `folding`, `fixed `, `declined `, `open`, `held`, `hit fixed`, `hit dismissed` are spelled identically in Tasks 1, 2, 5, 6, 7, 9 and 10. -**One defect class, three instances, and the lesson about finding it.** +**One defect class, four instances, and the lesson about how to close it.** Task 6's check first asserted two single-line matches for `review-loop ledger entry`; only one occurrence sits on a single line, so `grep` found one and an executor would have read that as the work half done. The self-review caught that instance **and treated it as -isolated** — which it was not. A propagation gate over the committed -plan found two more of exactly the same shape, in Tasks 4 and 8, where a -phrase wraps after "The date" and after "any". A sweep of every phrase -check in the plan then confirmed those three and no fourth. - -The fix is the Global Constraint above rather than three patches: in -files that wrap prose, a phrase check is multi-line or it is unsound. -Finding one instance of a mechanical fault is weak evidence that it is -the only one, and the cheap move is to sweep the class immediately. +isolated** — which it was not. A propagation gate found two more of +exactly the same shape, in Tasks 4 and 8. A sweep then declared those +three complete, and the plan-adversary found a fourth: Task 8's own +post-edit pattern, written during the repair of the third. + +Three sweeps, each declaring the class closed, each wrong. What finally +closed it was not a fourth sweep but a change of method. The constraint +above no longer says "use `rg -U` where a phrase might wrap" — a +judgement, re-exercised per pattern, wrong roughly a third of the time +here. It says every prose pattern is uniformly `\s+` between every pair +of words, which is correct whether or not the phrase wraps and so cannot +be misapplied. The lesson is not "sweep harder": a rule that requires a +prediction at each site will keep producing instances at the rate the +prediction fails, and the repair is to remove the prediction. + +The same reasoning produced two further constraints during this wave — +one on `rg -c`'s zero behaviour, one on leading-anchor tolerance, the +latter raised by the developer. Each replaces a per-site judgement with +a mechanical rule. Every other check was re-run against the working tree: the five-shape -block, the close description, the tripwire wording, the bare `dismissed` -line, and the command counts all match what their steps expect. +block, the close description, the tripwire wording, the triage +paragraph, the bare `dismissed` line, and the command counts all match +what their steps expect. **Known seam.** Task 2's Step 5 verifies the "four of the five" anchor claim by counting published commands. That count includes the `revises:` lookup, which is not an Unfinished-work entry — the step says so, but a future command added to either group will make the assertion wrong before the prose is. It is a check with a short shelf life, deliberately kept because the alternative is trusting the claim. + +## Review rounds + +### 2026-09-02 — plan-adversary, fable 5, blocking (round 1, full-document) + +- fixed — [Important] Task 8's post-edit pattern uses literal spaces while the replacement it verifies wraps as "a message / from the developer", so the check false-fails against a correct edit — a fourth instance of the wrapped-phrase class, in the plan whose self-review had just declared that class swept; license: this plan's own Global Constraint on prose checks; the pattern is now uniformly `\s+`, and the constraint itself was rewritten from a per-site judgement into an unconditional rule so the class cannot recur +- fixed — [Important] Task 11's banned-term sweep expects no output from a command that necessarily hits the glossary's own `_Avoid_` line, so the check cannot pass in the correct end state; license: the glossary's **Disposition line** entry, whose ban is stated by writing the banned phrase; the sweep now filters the definition site with `grep -v '_Avoid_'` and the step says why that is not slack +- fixed — [Important] Task 6's Steps 3 and 4 prescribe overlapping edits: Step 3 rewords both occurrences, and the second opens Step 4's replace-this block, so Step 4 then targets text that no longer exists; license: Step 4's own replacement text, which already carried the reword; Step 3 is narrowed to the first occurrence and Step 4 completes the second as part of its block, each step saying so +- fixed — [Important] a consumer of the retired token is left behind — `workflow.md` licenses a self-fix off "a previously resolved `held` line", a state the live grammar stops producing, and no task touches it; license: the spec's merge of `fixed` and `resolved` plus its authorizer rule; Task 7 is rescoped from two consumers to all three in that file, retitled accordingly, and the triage paragraph now cites "a line carrying `ruling:`", which also picks up pre-design settled lines the old wording missed +- fixed — [Important] Task 3 claims the historical `resolved` shapes are "kept" while Task 1 deletes the shape lines and only the token names survive; Task 11's conditional expectation shows the plan has not decided its own end state; license: the spec's statement that the shapes are kept as described historical forms; Task 3 now writes both shape lines verbatim into its block, states that they are described and never minted, and warns that it reinstates lines Task 1 deleted; Task 11's expectation is now unconditional +- fixed — [Important] Task 6's Step 2 states absolute line numbers that Tasks 1–5 invalidate by inserting above them, so a literal executor reads a correct state as a failed check; license: this plan's own task ordering; the numbers are gone, replaced by the surrounding sentence as the locator, with a note saying why no number is quoted +- fixed — [Important] Task 7's Step 5 states only one of its two post-edit expectations, so the deletion the second pattern exists to verify passes unchecked if skipped; license: that step's own stated rationale that each pattern must fail if its step is skipped; the task now carries three checks for three steps and asserts all three +- fixed — [Minor] five "Expected: 0" lines sit on `rg -c` commands, which print nothing and exit 1 rather than printing 0; license: the measured behaviour of `rg -c`, verified in-session; a Global Constraint states it once and six steps — one more than the round found — now expect "no output" +- fixed — [Minor] Task 9's workflow text protects only lines carrying `ruling:`, narrower than the spec's Settled-lines tier, which includes historical token-settled lines; license: the spec's **Settled lines** bullet; the rule text now names both, protected on the same footing +- fixed — [Minor] Task 11's Step 1 asserts a repo state the process's own artifacts can falsify at execution time, without the investigate-versus-defect caveat Task 6's Step 6 carries; license: Task 6's Step 6, which carries exactly that caveat; the step now says an extra hit is a question about the document it names, never a reason to edit this plan + +The developer authorized this fix wave despite the `blocking` verdict, which otherwise suspends autonomy. Every finding above carried a citable written license, and none was a design decision — the verdict's grade and the findings' licenses pointed in different directions, which is the case the loop's triage rule was written for. + +One further defect was raised by the developer during the wave, outside +the round: + +- fixed — [Important] the anchored `grep` checks used an exact four-space leading anchor where the Unfinished-work list's own commands are deliberately tolerant, so a leftover line at a different indent would read as absent — the same false-clean failure as the wrapped-phrase class; license: the lifecycle rule's stated reasoning that leading anchors are tolerant on purpose and its Misplaced-stamp anchor exact because there the indentation is the defect; a third Global Constraint now ties anchor tolerance to the direction of the assertion, and Task 1's two anchors differ accordingly with the step saying why + +Answering the round's focusing question — what is still broken if every +stated check passes — the reviewer named three: the retired token still +licenses a self-fix in `workflow.md`, the rule claims to keep shapes it +deleted, and Task 7's deletion may silently not have happened. Two +checks fail against the *correct* state, which it called the more +dangerous direction, since an executor may "fix" the document to satisfy +a broken check. + +Its stop signal: a re-round after the fix wave earns its cost, but +diff-scoped — the findings sit in check mechanics and two scope gaps, +not in the prescribed rule prose, which matched the spec everywhere it +was diffed. And a standing instruction for that round: **the +wrapped-phrase class has now produced four instances across two sweeps +that each declared completeness, so it is re-verified mechanically +rather than by reading.** From 4041e4f332a7d04f2414750dd5a8ecf1311eaad8 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 16:03:49 +0200 Subject: [PATCH 056/126] docs: paired anchors on every check, close the vacuous verification step --- .../2026-09-02-ledger-as-finding-state.md | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index 1438e13..bb8b2ff 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -30,7 +30,12 @@ base: develop - **The spec is the source.** Where this plan and `docs/specs/2026-09-02-ledger-as-finding-state-design.md` disagree, the spec wins and the plan is wrong. - **A check that searches for prose uses `rg -U` and puts `\s+` between *every* pair of words in the pattern; a check that searches for an anchored structural pattern uses `grep`.** These files wrap prose at about 72 characters, so a searched phrase may straddle a line ending and a single-line `grep` then returns 0 where the phrase is plainly present. Four checks in this plan's earlier drafts had exactly that fault, found across three sweeps that each declared the class closed — which is why the constraint is now unconditional rather than applied where a wrap looks likely. Where the wrap falls is not something a reader reliably predicts, and a pattern that is uniformly `\s+` is correct whether or not it wraps, so no judgement is exercised and no instance can be missed. An anchored pattern like `^ - fixed ` or `^| \`ruling:` cannot straddle by construction, so single-line matching is correct there and multi-line matching would be misleading. - **`rg -c` prints nothing and exits 1 when its pattern does not match** — it never prints `0`. A step asserting absence with `rg` therefore expects *no output*; only `grep -c`, which does print `0`, is given a numeric zero expectation. -- **Leading-anchor tolerance follows the direction of the assertion.** A check asserting that text is *gone* uses a tolerant anchor (`^\s*`), because a leftover the pattern fails to match reads as success — the same false-clean failure the wrapped-phrase class produces. A check asserting that prescribed text is *present* uses the exact anchor (`^ ` for an indented grammar block, `^| ` for a table row), because the indentation is part of what the step prescribes and a tolerant match would accept a malformed block as correct. This is the lifecycle rule's own reasoning applied here: its Unfinished-work anchors are tolerant so a relocated field is still found, and its Misplaced-stamp anchor is exact precisely because there the indentation *is* the defect. One published command is copied verbatim rather than reasoned about — the ledger anchor `^- `, which is strict by design so indented payload cannot match it; a check mirroring a published command reproduces it exactly. +- **An anchored check on an indented block publishes *both* anchors — exact and tolerant — and asserts their equality.** Never one alone, and never a per-site decision about which. The exact anchor (`^ ` for a grammar block, `^| ` for a table row) proves the prescribed text is well-formed at the indent the step prescribes; the tolerant anchor (`^\s*`) proves no variant survives anywhere else. Each alone has a blind spot that reads as success: the exact one passes while a leftover sits at another indent, the tolerant one passes while the prescribed block is mis-indented. Equality of the two counts is the assertion, and a divergence localizes which half failed. + + An earlier draft of this constraint made tolerance depend on the direction of the assertion — tolerant for "is it gone", exact for "is it present". That reasoning is sound and it is *why* the pair works, but it is a judgement exercised at every site, and the wrapped-phrase constraint above is the standing evidence for what that costs. Applying it, this plan got Task 11's Step 3 wrong: that step asserts both directions at once and the rule had no answer for it. Publishing both anchors always is mechanical, subsumes both directions, and cannot be misapplied. The lifecycle rule's own asymmetry — tolerant Unfinished-work anchors so a relocated field is still found, an exact `^\s+` on Misplaced stamp because there the indentation *is* the defect — is the reasoning this pair captures without asking any later reader to re-derive it. + + One case is copied rather than reasoned about: a check mirroring a command the rules publish reproduces it verbatim, the ledger anchor `^- ` included, which is strict by design so indented payload cannot match it. +- **Every check must return a different value before and after its step, and both values are stated.** A check whose before-value equals its after-value verifies nothing, however correct both numbers look — and it survives review precisely because nothing about it appears wrong. Task 11's Step 3 was exactly this: it counted a shape one task deletes and a later one restores, scoring `2` both before and after the entire plan. Where a count cannot distinguish the two states, assert something that can — a line ordering against text that does not exist until the work is done. --- @@ -46,15 +51,18 @@ base: develop ```bash # The old five-shape block must still be present, and the new tokens absent. -grep -c '^\s*- resolved — \[\]' plugins/working-process/rules/spec-plan-lifecycle.md -grep -c '^ - declined ' plugins/working-process/rules/spec-plan-lifecycle.md +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^ - resolved — \[\]' "$f" # old shape, exact indent +grep -c '^\s*- resolved — \[\]' "$f" # old shape, any indent +grep -c '^ - declined ' "$f" # new shape, exact indent +grep -c '^\s*- declined ' "$f" # new shape, any indent ``` -The two anchors differ deliberately, per the tolerance constraint above. The first ends this task asserting the old shape is *gone*, so it is tolerant — a leftover line at any indent must still be caught. The second ends it asserting the new shape is *present* at the grammar block's own indent, so it is exact — a block written at the wrong indent is not a code block and must fail. +Each shape is counted twice, exact and tolerant, per the paired-anchor constraint above. The two counts for a shape must always match: a divergence means a line sits at an indent the grammar block does not use, which the single-anchor form of this check could not see in either direction. - [ ] **Step 2: Run it to confirm the starting state** -Expected: first command prints `1`, second prints `0`. +Expected: `1`, `1`, `0`, `0` — the old shape present at the block's indent and nowhere else, the new shape absent everywhere. - [ ] **Step 3: Replace the shapes block** @@ -143,7 +151,7 @@ exactly where the session stopped. - [ ] **Step 6: Run the check again** -Expected: first command prints `0`, second prints `1`. +Expected: `0`, `0`, `1`, `1` — the old shape gone at every indent, the new shape present at the block's indent and nowhere else. Each pair must match. - [ ] **Step 7: Validate** @@ -174,12 +182,16 @@ git commit -m "feat(working-process): four ledger states, authorizer as a clause - [ ] **Step 1: Write the failing check** ```bash -grep -c '^| `ruling: ` |' plugins/working-process/rules/spec-plan-lifecycle.md +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^| `ruling: ` |' "$f" # exact: a table row starts at column 0 +grep -c '^\s*| `ruling: ` |' "$f" # any indent ``` - [ ] **Step 2: Run it** -Expected: `0`. +Expected: `0` and `0`. + +The pair matters here for a reason particular to Markdown: a table row indented by four spaces stops being a table and renders as a code block, silently, with no parse error. The exact anchor alone would report the row missing without saying why; the tolerant one alone would report it present while the table was broken. A divergence between the two is the diagnosis. - [ ] **Step 3: Add the table and its two rules** @@ -217,7 +229,7 @@ indented sub-bullets rather than in a longer line. - [ ] **Step 4: Run the check again** -Expected: `1`. +Expected: `1` and `1`, matching. - [ ] **Step 5: Verify the anchor claim against the file itself** @@ -286,10 +298,12 @@ ignores the prose. Expected: `1`. Also confirm the reinstated shapes are present, which Task 11's Step 3 will re-assert: ```bash -grep -c '^ - resolved ' plugins/working-process/rules/spec-plan-lifecycle.md +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^ - resolved ' "$f" # exact indent +grep -c '^\s*- resolved ' "$f" # any indent ``` -Expected: `2`. +Expected: `2` and `2`, matching. Task 1 left this at `0` and `0`, so the pair also proves this task ran rather than merely that the shapes exist somewhere. - [ ] **Step 5: Validate and commit** @@ -646,7 +660,7 @@ with: - [ ] **Step 4: Run the check again** -Expected: second command prints `1`. +Expected: the first command prints nothing, the second prints `1`. Both are stated because the replacement deletes the first phrase and introduces the second, so each command changes value and a step that asserted only one would let half the edit pass unverified. - [ ] **Step 5: Validate and commit** @@ -800,11 +814,17 @@ The `grep -v` is not slack. The glossary's **Disposition line** entry defines th - [ ] **Step 3: Confirm the live grammar is gone and the historical block remains** ```bash -grep -c '^\s*- resolved — \[' plugins/working-process/rules/spec-plan-lifecycle.md -grep -c '^\s*- resolved (declined) — \[' plugins/working-process/rules/spec-plan-lifecycle.md +f=plugins/working-process/rules/spec-plan-lifecycle.md +rg -U -n 'described\s+historical\s+forms' "$f" | cut -d: -f1 # the paragraph Task 3 adds +grep -n '^ - resolved ' "$f" # exact: the block, well-formed +grep -c '^\s*- resolved ' "$f" # tolerant: nothing else, any indent ``` -Expected: `1` and `1` — the two lines Task 3 writes into its historical-forms block, and nothing else. Task 1 deleted both shapes from the live block; Task 3 reinstated them as described history. Two hits on the first command would mean a live-block line survived. +Expected: the paragraph's line number prints; exactly two `resolved ` lines print, **both numbered greater than it**; and the tolerant count is `2`, equal to the number of exact-anchored hits. + +**A bare count here would be vacuous, and was.** This step's first draft compared counts alone, and the file scores `2` and `2` *before* any task runs — the two shapes sit in the live block today, and Task 1 deleting them while Task 3 writes them back leaves the total unchanged. A check that passes identically in the starting and finishing states verifies nothing, and it would have gone unnoticed because both numbers are right. The line-ordering comparison is what makes the step discriminate: before implementation the introducing paragraph does not exist, and the shape lines sit above where it will be, so the assertion fails exactly when the work has not happened. + +The two anchors then split the remaining work in opposite directions. The exact one says Task 3's block is well-formed at the grammar block's own indent — fewer than two hits means missing or mis-indented. The tolerant one says nothing matching the retired shape survives anywhere else at any indent — a count above the number of exact hits means a leftover the exact anchor cannot see, which is the live-block line Task 1 was supposed to delete. Neither anchor alone carries both claims. - [ ] **Step 4: Validate** @@ -884,10 +904,37 @@ what their steps expect. The developer authorized this fix wave despite the `blocking` verdict, which otherwise suspends autonomy. Every finding above carried a citable written license, and none was a design decision — the verdict's grade and the findings' licenses pointed in different directions, which is the case the loop's triage rule was written for. -One further defect was raised by the developer during the wave, outside -the round: +Four further defects were raised by the developer during the wave, +outside the round. All four came from one observation — that the +anchored `grep` checks had no whitespace treatment — pursued +mechanically rather than site by site, the developer returning three +times because each answer still left a judgement in place: - fixed — [Important] the anchored `grep` checks used an exact four-space leading anchor where the Unfinished-work list's own commands are deliberately tolerant, so a leftover line at a different indent would read as absent — the same false-clean failure as the wrapped-phrase class; license: the lifecycle rule's stated reasoning that leading anchors are tolerant on purpose and its Misplaced-stamp anchor exact because there the indentation is the defect; a third Global Constraint now ties anchor tolerance to the direction of the assertion, and Task 1's two anchors differ accordingly with the step saying why +- fixed — [Critical] Task 11's Step 3 was vacuous: it compared counts of the retired shape, and the file scores `2` and `2` *before* any task runs, since Task 1 deleting the two shapes while Task 3 writes them back leaves the total unchanged — the step passed identically in the starting and finishing states, and both numbers being right is why nobody noticed; license: the plan's own requirement that a check be capable of failing if its step were skipped; the step now compares the shape lines' line numbers against the introducing paragraph's, which does not exist before implementation, and the step records the vacuity so the next reader sees why the ordering comparison is there +- fixed — [Important] Task 8's Step 4 stated only one of its two post-edit expectations, leaving the deletion half of the edit unverified — the same defect the round found in Task 7, in the task next to it, and missed there; license: that round's finding on Task 7, which is a written decision about this exact shape; both expectations are now stated + +- fixed — [Important] the repair above still made anchor tolerance depend on a per-site judgement — tolerant for "is it gone", exact for "is it present" — which is the same shape as the wrapped-phrase rule that produced four instances, and the developer said so after Tasks 1 and 3 kept their single exact anchors; license: this plan's own wrapped-phrase constraint, whose stated reason for going unconditional is that a rule requiring a prediction at each site keeps failing at the rate the prediction does; the constraint now requires *both* anchors on every anchored check with their equality as the assertion, and all five checks are paired + +The vacuity above is the wave's most serious finding and none of the +three reviews caught it — not the self-review, not the propagation gate, +not the `blocking` round. It surfaced because the developer's anchor +question forced a mechanical audit of every anchored pattern, and the +audit asked a question reading never asks: does this check return a +different value before and after its task? That question is now worth +asking of every check in every plan, and Task 8's defect fell out of the +same sweep moments later. + +The sequence is the lesson, more than any of the four repairs. The first +answer fixed the sites the developer pointed at. The second generalized +to a rule — but a rule with a judgement in it, and the judgement was +promptly got wrong on the one step that asserts both directions at once. +The third removed the judgement. Twice in one plan the same correction +was needed on the same class, and both times the intermediate stop +looked like a principled rule rather than an unfinished one. A +constraint that still asks the reader to classify the site is not +finished; the test is whether it can be applied without deciding +anything. Answering the round's focusing question — what is still broken if every stated check passes — the reviewer named three: the retired token still From 825fb17b39f76287592ae15237653b417deb0f1e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 16:09:45 +0200 Subject: [PATCH 057/126] docs: record the propagation gate episode and its self-report gap --- .../2026-09-02-ledger-as-finding-state.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index bb8b2ff..a1752be 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -944,6 +944,26 @@ checks fail against the *correct* state, which it called the more dangerous direction, since an executor may "fix" the document to satisfy a broken check. +The propagation gate before round 2 ran twice and returned CLEAN both +times: once over the fix wave at `107dec0`, and again over `4041e4f` +after the developer-raised repairs, the second time with a sixth scope +class added for before/after equivalence. It produced no hits, so it +writes no gate lines. + +Neither run opened with the model self-report the workflow rule requires, +the second omitting it despite an emphatic instruction. That is a +measured property of this agent rather than a one-off, and it is recorded +here because the rule makes an unverified self-report a reason to +withhold reliance. Reliance is taken anyway, on a narrow derivation: the +guard exists to catch a silent substitution of the model actually run for +the one dispatched, and a propagation audit's prescribed rung is the +cheapest available family, which is what was named at dispatch. A +substitution could therefore only have run the audit *above* its +prescribed tier, which does not invalidate a structural CLEAN. Several of +the second run's specific claims — the quoted blocks at their stated +lines, and the `1, 1, 0, 0` starting state — were independently verified +in-session before it was dispatched. + Its stop signal: a re-round after the fix wave earns its cost, but diff-scoped — the findings sit in check mechanics and two scope gaps, not in the prescribed rule prose, which matched the spec everywhere it From c5339e64c26393bcfd16ba0396930fdd29aee568 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 16:24:17 +0200 Subject: [PATCH 058/126] docs: round two fix wave - prose sweep pattern, scoped before/after rule, term consumer --- .../2026-09-02-ledger-as-finding-state.md | 83 ++++++++++++++++--- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index a1752be..46e0354 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -2,7 +2,7 @@ ticket: none date: 2026-09-02 status: draft -adversary: blocking +adversary: concerns spec: ../specs/2026-09-02-ledger-as-finding-state-design.md branch: feature/audit-errata base: develop @@ -35,7 +35,9 @@ base: develop An earlier draft of this constraint made tolerance depend on the direction of the assertion — tolerant for "is it gone", exact for "is it present". That reasoning is sound and it is *why* the pair works, but it is a judgement exercised at every site, and the wrapped-phrase constraint above is the standing evidence for what that costs. Applying it, this plan got Task 11's Step 3 wrong: that step asserts both directions at once and the rule had no answer for it. Publishing both anchors always is mechanical, subsumes both directions, and cannot be misapplied. The lifecycle rule's own asymmetry — tolerant Unfinished-work anchors so a relocated field is still found, an exact `^\s+` on Misplaced stamp because there the indentation *is* the defect — is the reasoning this pair captures without asking any later reader to re-derive it. One case is copied rather than reasoned about: a check mirroring a command the rules publish reproduces it verbatim, the ledger anchor `^- ` included, which is strict by design so indented payload cannot match it. -- **Every check must return a different value before and after its step, and both values are stated.** A check whose before-value equals its after-value verifies nothing, however correct both numbers look — and it survives review precisely because nothing about it appears wrong. Task 11's Step 3 was exactly this: it counted a shape one task deletes and a later one restores, scoring `2` both before and after the entire plan. Where a count cannot distinguish the two states, assert something that can — a line ordering against text that does not exist until the work is done. +- **Every check that verifies an edit must return a different value before and after its step, and both values are stated.** A check whose before-value equals its after-value verifies nothing, however correct both numbers look — and it survives review precisely because nothing about it appears wrong. Task 11's Step 3 was exactly this: it counted a shape one task deletes and a later one restores, scoring `2` both before and after the entire plan. Where a count cannot distinguish the two states, assert something that can — a line ordering against text that does not exist until the work is done. + + Two kinds of check verify no edit and are therefore outside this rule: a **claim-verification** check, which tests a standing assertion in the prose rather than a change (Task 2's Step 5, which counts published commands to confirm a "four of the five" claim), and an **end-state assertion** in a task that modifies nothing (all of Task 11, whose `Files:` line reads "none unless a check fails"). To keep the exemption from becoming the per-site judgement this plan spent three passes removing elsewhere, it is claimed rather than inferred: a check is exempt only where its own step says in words that it verifies no edit, and both exempt sites do. --- @@ -318,7 +320,9 @@ git commit -m "feat(working-process): retain historical ledger shapes, permit pr ### Task 4: The gate discriminator **Files:** -- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md:~185-195` — the paragraph under `### Gate lines` beginning "Both are written at gate time" +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the paragraph under `### Gate lines` beginning "Both are written at gate time" + +No line number is given, and none should be: Tasks 1–3 insert well over fifty lines above this paragraph, so any number written here is wrong by the time the task runs. The prose locator is exact on its own. This is the class round 1 reported against Task 6, applied to the one other place that carried a stale number. **Interfaces:** - Consumes: nothing from earlier tasks. @@ -427,7 +431,7 @@ State prevents relitigation, not the reviewer's memory. - [ ] **Step 4: Run the check again** -Expected: no output, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). +Expected: no output, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). Its before-value is `0` — the word does not appear in the file until Task 2 writes it — so the pair discriminates. - [ ] **Step 5: Validate and commit** @@ -623,13 +627,17 @@ git commit -m "feat(working-process): move workflow.md off the retired resolved - [ ] **Step 1: Write the failing check** ```bash -rg -U -c 'any\s+developer\s+contact\s+resets\s+the\s+count' plugins/working-process/rules/workflow.md -rg -U -c 'a\s+message\s+from\s+the\s+developer' plugins/working-process/rules/workflow.md +w=plugins/working-process/rules/workflow.md +rg -U -c 'any\s+developer\s+contact\s+resets\s+the\s+count' "$w" +rg -U -c 'a\s+message\s+from\s+the\s+developer' "$w" +rg -U -c 'refusal\s+mid-loop\s+is\s+already\s+developer\s+contact' "$w" ``` - [ ] **Step 2: Run it** -Expected: `1`, then no output. The first phrase wraps after "any" and the second wraps after "a message" once written, so both are uniformly `\s+` — the second is the instance that made the constraint unconditional. +Expected: `1`, no output, `1`. The first phrase wraps after "any" and the second wraps after "a message" once written, so both are uniformly `\s+` — the second is the instance that made the constraint unconditional. The third finds the consumer Step 4 reconciles. + +**Enumerate the consumers of the term, not just the bullet.** This task redefines "developer contact" and the term is used elsewhere in the same file. Task 7 enumerates consumers of a retired *token*; this step does the same for a redefined *term*, which is the class round 2 found missing here. - [ ] **Step 3: Replace the bullet** @@ -658,11 +666,29 @@ with: compaction. ``` -- [ ] **Step 4: Run the check again** +- [ ] **Step 4: Reconcile the cap-refusal sentence with the new definition** -Expected: the first command prints nothing, the second prints `1`. Both are stated because the replacement deletes the first phrase and introduces the second, so each command changes value and a step that asserted only one would let half the edit pass unverified. +The file's closing paragraph says a model-cap refusal *is* developer contact. Step 3's definition says developer contact is a message from the developer, and a platform refusal is not one — so the two would ship contradicting each other. Replace: -- [ ] **Step 5: Validate and commit** +``` +refusal mid-loop is already developer contact: the drop-or-wait +question above is never answered autonomously. +``` + +with: + +``` +refusal mid-loop forces developer contact: the drop-or-wait +question above is never answered autonomously. +``` + +The behaviour is unchanged and was never in doubt — the loop cannot proceed until the developer answers the drop-or-wait question, which is a message. Only the claim changes, from the refusal *being* contact to *forcing* it, which is what the sentence always meant and what the new definition now requires it to say. + +- [ ] **Step 5: Run the check again** + +Expected: the first command prints nothing, the second prints `1`, the third prints nothing. All three are stated because each corresponds to one edit — Step 3 deletes the first phrase and introduces the second, Step 4 removes the third — and a step asserting fewer would let an edit pass unverified. + +- [ ] **Step 6: Validate and commit** ```bash claude plugin validate . && claude plugin validate plugins/working-process @@ -804,11 +830,13 @@ These expectations describe the repo as this plan was written, and the process's - [ ] **Step 2: Confirm no banned term returned** ```bash -grep -rn --include='*.md' 'ledger entry' plugins/ docs/domain/ | grep -v '_Avoid_' +rg -U -n 'ledger\s+entry' plugins/ docs/domain/ | grep -v '_Avoid_' ``` Expected: no output. +`ledger entry` is a two-word prose phrase, so this sweep obeys the prose constraint like any other: `rg -U` with `\s+`, never a single-line `grep`. The point is exact: a surviving banned use that happened to wrap as `ledger` / `entry` across a line ending is invisible to a literal-space pattern, and this command's whole job is to prove no use survives. An earlier draft ran `grep -rn 'ledger entry'` here — written, and then *edited*, during the very wave whose new constraint forbids it. + The `grep -v` is not slack. The glossary's **Disposition line** entry defines the ban by writing the banned phrase — `_Avoid_: finding line, ledger entry` — so an unfiltered sweep necessarily hits the one line that must keep saying it, and the check could never pass in the correct end state. Filtering the definition site is what makes the sweep assert what it means: no *use* of the banned term survives. - [ ] **Step 3: Confirm the live grammar is gone and the historical block remains** @@ -889,6 +917,39 @@ what their steps expect. ## Review rounds +### 2026-09-02 — plan-adversary, fable 5, concerns (round 2, diff-scoped) + +- fixed — [Important] Task 11's Step 2 banned-term sweep is itself in the wrapped-phrase class: `grep -rn 'ledger entry'` searches a two-word prose phrase with a literal space, so a surviving banned use wrapping as `ledger` / `entry` reads as clean — and the wave *edited this exact command* to add the `_Avoid_` filter without noticing its pattern; license: this plan's own prose-check constraint; the command is now `rg -U -n 'ledger\s+entry'` and the step records that the fifth instance of the class was written during the repair of the fourth +- fixed — [Minor] the wave-born before/after constraint is falsified by the plan's own checks — Task 2's Step 5 scores `6` and `1` on both sides because it verifies a prose claim rather than an edit, Task 11 edits nothing at all, and Task 5's Step 4 stated only an after-value — so the rule as written re-introduced the per-site judgement the wave had just spent three passes removing; license: the wave's own stated test, that a rule still asking the reader to classify the site is unfinished; the constraint is scoped to checks that verify an edit, the two exempt classes are named, and the exemption is claimed in each step's own words rather than inferred; Task 5's Step 4 now states its before-value, which is `0` rather than the `1` the round estimated +- fixed — [Minor] Task 4's `Files:` locator `spec-plan-lifecycle.md:~185-195` is stale by construction — the paragraph sits at line 178 today and lands near 255 once Tasks 1–3 insert above it — the same class round 1 reported against Task 6, repaired there and left standing here; license: round 1's finding, which defines the class; the number is gone and the step says why the prose locator is sufficient alone +- fixed — [Minor] Task 8 redefines "developer contact" but enumerates no consumers of the redefined term, leaving `workflow.md:322` asserting that a model-cap refusal *is* developer contact, which the new definition denies; license: Task 7's own precedent of enumerating a retired token's consumers, applied to a redefined term; Task 8 gains a check for the consumer and a step reconciling it to "forces developer contact", which is what the sentence always meant and leaves the behaviour unchanged + +Answering the round's focusing question — where the fix wave repaired the +instance and missed the class — the reviewer found it **inside a single +command**: Task 11's Step 2 received round 1's `_Avoid_` filter while its +pattern stayed a single-line literal-space prose search, violating the +unconditional constraint the same wave had just written, in the one step +the wave was actively editing. Its secondary instance is Task 7 against +Task 8: the wave enumerated consumers of the retired *token* and never +asked the same question of the *term* Task 8 redefines. + +The round verified the diff mechanically rather than by reading, as its +brief required — every Replace block matched verbatim and uniquely, every +starting-state expectation was reproduced against the tree, and the whole +plan was applied to scratch copies with every after-check re-run. That +simulation is what confirmed the vacuity repair in Task 11's Step 3 is +sound, and it is the reason the round's own stop signal rules out a third +diff-scoped pass. + +Its stop signal: another diff-scoped round would not repay its cost — the +diff has been simulated to exhaustion and the leftovers were four +one-edit fixes, each licensed by the plan's own written constraints. What +the loop still owes is structural rather than marginal: on a plan only a +full-document round's LGTM terminates, so the confirming full-document +round is the right next dispatch, and it is also the only scope that can +reach the class behind the fourth finding — consumers of a redefined term +living outside the diff. + ### 2026-09-02 — plan-adversary, fable 5, blocking (round 1, full-document) - fixed — [Important] Task 8's post-edit pattern uses literal spaces while the replacement it verifies wraps as "a message / from the developer", so the check false-fails against a correct edit — a fourth instance of the wrapped-phrase class, in the plan whose self-review had just declared that class swept; license: this plan's own Global Constraint on prose checks; the pattern is now uniformly `\s+`, and the constraint itself was rewritten from a per-site judgement into an unconditional rule so the class cannot recur From 776ee75cea1fa9ce21a48fa58939fc0ce438c248 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 16:29:37 +0200 Subject: [PATCH 059/126] docs: record the third gate run and the auditor's self-report gap --- .../2026-09-02-ledger-as-finding-state.md | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index 46e0354..5689e03 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -1005,17 +1005,23 @@ checks fail against the *correct* state, which it called the more dangerous direction, since an executor may "fix" the document to satisfy a broken check. -The propagation gate before round 2 ran twice and returned CLEAN both -times: once over the fix wave at `107dec0`, and again over `4041e4f` -after the developer-raised repairs, the second time with a sixth scope -class added for before/after equivalence. It produced no hits, so it -writes no gate lines. - -Neither run opened with the model self-report the workflow rule requires, -the second omitting it despite an emphatic instruction. That is a -measured property of this agent rather than a one-off, and it is recorded -here because the rule makes an unverified self-report a reason to -withhold reliance. Reliance is taken anyway, on a narrow derivation: the +The propagation gate ran three times across this document's loop and +returned CLEAN every time: over the round-1 fix wave at `107dec0`, over +`4041e4f` after the developer-raised repairs, and over `c5339e6` before +the confirming round, each dispatch widening its positive scope as the +loop taught it what to look for. None produced a hit, so none writes a +gate line. + +No run opened with the model self-report the workflow rule requires. The +second omitted it despite an emphatic instruction naming the first +omission, and the third returned the single word `CLEAN` and nothing +else. Three for three is a property of the agent rather than a one-off, +and the likely mechanism is that a self-report is neither a hunt target +nor a premise for classifying — the two kinds of instruction this agent +demonstrably acts on. Fixing it belongs in the agent's own card, where +the self-report becomes a duty instead of a request a brief can lose. +It is recorded here because the rule makes an unverified self-report a +reason to withhold reliance. Reliance is taken anyway, on a narrow derivation: the guard exists to catch a silent substitution of the model actually run for the one dispatched, and a propagation audit's prescribed rung is the cheapest available family, which is what was named at dispatch. A From 2698ccf67c001b0a404fd7d6301c8f081814d724 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 16:45:17 +0200 Subject: [PATCH 060/126] docs: round three fix wave - evidence-newness base, un-specced deletions, refusal mapping --- .../2026-09-02-ledger-as-finding-state.md | 118 ++++++++++++++---- 1 file changed, 93 insertions(+), 25 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index 5689e03..83e38f4 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -598,9 +598,11 @@ with: round without the developer. It licenses no separate fix prohibition, because triage already holds what the prohibition was reaching for: a design reshape has no citable license by construction, so it is held - whatever the verdict's grade. + whatever the verdict's grade. `concerns` is the autonomy zone. ``` +The closing sentence is retained deliberately. The spec directs only the self-fix clause removed, and the sentence stays true under the new design: `blocking` still suspends rounds, `LGTM` still ends the loop, and `concerns` remains the one verdict the loop continues under autonomously. Deleting it would be an un-specced change riding along with a specced one. + - [ ] **Step 6: Run the check again** Expected: all three commands print nothing. Each corresponds to one of Steps 3, 4 and 5, so a skipped step is the one that still prints `1`. @@ -628,14 +630,18 @@ git commit -m "feat(working-process): move workflow.md off the retired resolved ```bash w=plugins/working-process/rules/workflow.md -rg -U -c 'any\s+developer\s+contact\s+resets\s+the\s+count' "$w" +rg -U -c 'counting\s+only\s+rounds\s+that\s+returned\s+a\s+verdict' "$w" rg -U -c 'a\s+message\s+from\s+the\s+developer' "$w" rg -U -c 'refusal\s+mid-loop\s+is\s+already\s+developer\s+contact' "$w" ``` - [ ] **Step 2: Run it** -Expected: `1`, no output, `1`. The first phrase wraps after "any" and the second wraps after "a message" once written, so both are uniformly `\s+` — the second is the instance that made the constraint unconditional. The third finds the consumer Step 4 reconciles. +Expected: no output, no output, `1`. + +**The first pattern is not the obvious one, deliberately.** An earlier draft checked `any developer contact resets the count`, which reads like the natural anchor for this bullet — but the replacement *retains* that sentence, so the pattern scores `1` on both sides and verifies nothing. The qualifier `counting only rounds that returned a verdict` is text the replacement introduces and the original lacks, so it discriminates. This is the plan's own before/after constraint catching a check that a repair to a different finding had just made vacuous. + +The second phrase wraps after "a message" once written, so it is uniformly `\s+` like every prose pattern here. The third finds the consumer Step 4 reconciles. **Enumerate the consumers of the term, not just the bullet.** This task redefines "developer contact" and the term is used elsewhere in the same file. Task 7 enumerates consumers of a retired *token*; this step does the same for a redefined *term*, which is the class round 2 found missing here. @@ -656,16 +662,21 @@ with: - Round cap: three autonomous rounds per document per field without developer contact, counting only rounds that returned a verdict. Hitting the cap escalates in one batch — what was fixed, what remains, - why — rather than halting silently. Developer contact is a message - from the developer: not a relay they read, not an escalation the - session sent, not an unanswered batch. The count is derived from the - round headings and the reset event is recorded nowhere, so the cap is - best-effort by construction; a session that cannot count its own - rounds escalates rather than assuming, since resetting to zero would - let a long session grant itself three fresh rounds after every - compaction. + why — rather than halting silently, and any developer contact resets + the count. Developer contact is a message from the developer: not a + relay they read, not an escalation the session sent, not an unanswered + batch. The count is derived from the round headings and the reset + event is recorded nowhere, so the cap is best-effort by construction; + a session that cannot count its own rounds escalates rather than + assuming, since resetting to zero would let a long session grant + itself three fresh rounds after every compaction. ``` +Two details of this replacement are not in the spec, and both are recorded here rather than left to be re-derived: + +- **The reset sentence is retained**, not dropped. An earlier draft let "without developer contact" imply the reset. The spec directs no deletion, and the definition this bullet adds makes the reset *more* worth stating explicitly, not less — the sentence now says precisely what event resets the count. +- **"counting only rounds that returned a verdict" is added**, and it is derivable rather than invented: the bullet's own next sentence says the count comes from the round headings, and a round that died without a verdict mints no heading. Stating it prevents a session from counting a crashed dispatch against its own budget. + - [ ] **Step 4: Reconcile the cap-refusal sentence with the new definition** The file's closing paragraph says a model-cap refusal *is* developer contact. Step 3's definition says developer contact is a message from the developer, and a platform refusal is not one — so the two would ship contradicting each other. Replace: @@ -686,7 +697,7 @@ The behaviour is unchanged and was never in doubt — the loop cannot proceed un - [ ] **Step 5: Run the check again** -Expected: the first command prints nothing, the second prints `1`, the third prints nothing. All three are stated because each corresponds to one edit — Step 3 deletes the first phrase and introduces the second, Step 4 removes the third — and a step asserting fewer would let an edit pass unverified. +Expected: `1`, `1`, then nothing. All three are stated because each corresponds to one edit — Step 3 introduces the first two phrases, Step 4 removes the third — and a step asserting fewer would let an edit pass unverified. - [ ] **Step 6: Validate and commit** @@ -704,18 +715,22 @@ git commit -m "feat(working-process): define developer contact, state the cap is - Modify: `plugins/working-process/rules/workflow.md` — `### Re-dispatch briefs`, after the ledger-supplies-what-changed paragraph **Interfaces:** -- Consumes: `license:` and `ruling:` from Task 2; the relitigation branch from Task 5. +- Consumes: `license:` and `ruling:` from Task 2; the relitigation branch and the evidence-newness base from Task 5. - Produces: nothing new. +**The evidence-newness base is carried as a pointer, not a copy.** The spec's Changes-by-file assigns `workflow.md` "the base against which evidence counts as new", and this task delivers it by naming where the definition lives rather than restating it — Task 5 writes the full definition into `spec-plan-lifecycle.md`, which is where the spec puts the record's grammar. A duplicated definition in two rule files is the drift the spec's own file split exists to prevent, and both files already cross-reference each other this way rather than restating. A reviewer who thinks the pointer is too thin should say so: the deviation from the reviewer's suggested full sentence is recorded here deliberately, and the rationale is the thing to attack. + - [ ] **Step 1: Write the failing check** ```bash -rg -U -c 'always\s+in\s+scope\s+for\s+a\s+diff-scoped\s+round' plugins/working-process/rules/workflow.md +w=plugins/working-process/rules/workflow.md +rg -U -c 'always\s+in\s+scope\s+for\s+a\s+diff-scoped\s+round' "$w" +rg -U -c 'the\s+base\s+the\s+spec-plan-lifecycle\s+rule\s+defines' "$w" ``` - [ ] **Step 2: Run it** -Expected: no output. +Expected: no output from either. The second is what proves the evidence-newness base reached this file, which is the one thing the spec assigns here that a reader would otherwise look for in the lifecycle rule alone. - [ ] **Step 3: Add the paragraph** @@ -726,12 +741,14 @@ off from the one section recording what the developer already decided. The ledger is therefore always in scope for a diff-scoped round as context, never as a review target, and what that protects is narrow: -- settled lines may be re-raised only with new evidence, which routes - to `held` rather than to a fold. A line carrying `ruling:` is settled - by that clause; a historical line written before this design, - `resolved (declined)` included, carries no authorizer clause - and is settled by its token alone. Both are the developer's - decisions, and both are protected on the same footing; +- settled lines may be re-raised only with new evidence — new against + what the folded line records, the base the spec-plan-lifecycle rule + defines — which routes to `held` rather than to a fold. A line + carrying `ruling:` is settled by that clause; a historical line + written before this design, `resolved (declined)` included, + carries no authorizer clause and is settled by its token alone. Both + are the developer's decisions, and both are protected on the same + footing; - `held` lines carry questions already put, so a round does not duplicate one; - `fixed` lines carrying `license:` get no protection at all — the @@ -747,7 +764,7 @@ growing with the round count. - [ ] **Step 4: Run the check again** -Expected: `1`. +Expected: `1` and `1`. Both are stated because the paragraph delivers two things the spec assigns to this file — the ledger's standing place in a diff-scoped round, and the evidence-newness base — and a step asserting only the first would let the second go missing exactly as it did in this plan's first three drafts. - [ ] **Step 5: Validate and commit** @@ -823,9 +840,15 @@ rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degr rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|adversary-fallback|integrity):' docs/ ``` -Expected: the first returns `docs/plans/2026-07-13-rules-distribution.md`, which is a body quotation of the convention and not a frontmatter hit — confirm with `grep -n 'grilled: grilling'` on that file and check the line sits below the closing `---`. The other four return nothing. +Expected, with two known hits: + +- the **first** returns `docs/plans/2026-07-13-rules-distribution.md`, a body quotation of the convention rather than a frontmatter hit — confirm with `grep -n 'grilled: grilling'` on that file and check the line sits below the closing `---`; +- the **second** returns **this plan**, whose own `adversary:` field carries a live verdict throughout the review loop. That is a true unfinished-work hit, not a false positive, and it clears when the confirming full-document round's `LGTM` is stamped — which happens before implementation, so by the time an executor reaches this step the command should return nothing. If it still returns this plan, the loop has not closed and implementation has started early; +- the remaining three return nothing. -These expectations describe the repo as this plan was written, and the process's own artifacts can falsify them at execution time: a spec grilled or a round stamped between now and then is a real unfinished-work hit, not a defect in this plan. Investigate any extra hit against the document it names before continuing, exactly as Task 6's Step 6 directs — a hit here is a question about that document, never a reason to edit this one. +An earlier draft of this step claimed all four of the last commands were clean "as this plan was written", which its own frontmatter falsified on the day the step was written — the plan was carrying `adversary: blocking` at the time. + +Beyond those, the process's own artifacts can falsify these expectations at execution time: a spec grilled or a round stamped between now and then is a real unfinished-work hit, not a defect in this plan. Investigate any extra hit against the document it names before continuing, exactly as Task 6's Step 6 directs — a hit here is a question about that document, never a reason to edit this one. - [ ] **Step 2: Confirm no banned term returned** @@ -877,7 +900,9 @@ git commit -m "fix(working-process): close the propagation gate on the ledger re ## Self-review -**Spec coverage.** Every section of the spec maps to a task: the states and severity omission and write-ahead to Task 1; the clauses and the authorizer rule to Task 2; historical shapes and lawful prose to Task 3; the gate discriminator to Task 4; the fold and the relitigation branch to Task 5; the Unfinished-work corrections to Task 6; the triage license sources, the tripwire and the blocking terminator — `workflow.md`'s three consumers of the retired token — to Task 7; the cap to Task 8; the diff-scoped reading scope to Task 9; wave one's line to Task 10. The glossary needs no task — the grilling already changed it. The four refusals need no task: they are decisions not to build, and Task 1's severity paragraph carries the only one with prose consequences. +**Spec coverage.** Every section of the spec maps to a task: the states and severity omission and write-ahead to Task 1; the clauses and the authorizer rule to Task 2; historical shapes and lawful prose to Task 3; the gate discriminator to Task 4; the fold and the relitigation branch to Task 5; the Unfinished-work corrections to Task 6; the triage license sources, the tripwire and the blocking terminator — `workflow.md`'s three consumers of the retired token — to Task 7; the cap to Task 8; the diff-scoped reading scope to Task 9; wave one's line to Task 10. The glossary needs no task — the grilling already changed it. + +**The refusals**, which the spec's Changes-by-file lists among the `spec-plan-lifecycle.md` changes, are mapped rather than waived. Three are decisions not to build and leave no prose behind. The two with a rule-side trace are already accounted for: the no-fourth-severity refusal rides Task 1, whose severity paragraph ends "This adds no fourth severity value; the glossary's three stand"; and the hit-outstanding refusal is already shipped prose, the stated-gap paragraph under `### Gate lines` beginning "Neither shape covers a hit left outstanding", which this wave leaves untouched because wave one wrote it and nothing in this design changes it. No task is therefore missing — but the mapping is stated here rather than assumed, since "needs no task" and "is already in the file" are different claims and only the second is true of these two. **Placeholders.** None. Every step carries the literal text to write or the literal command to run. @@ -917,6 +942,49 @@ what their steps expect. ## Review rounds +### 2026-09-02 — plan-adversary, fable 5, concerns (round 3, full-document) + +- fixed — [Important] Task 9 omits the base against which evidence counts as new, which the spec's Changes-by-file assigns to `workflow.md`; the plan ships it only into `spec-plan-lifecycle.md` via Task 5, so an executor produces a `workflow.md` whose new-evidence judgment has no stated base in the file governing the round's behaviour; license: the spec, which the plan's own Global Constraint makes the winner on disagreement; the paragraph now carries the base as a pointer to the lifecycle rule's definition, a second check proves it reached the file, and the deviation from the reviewer's suggested full sentence is recorded in the task with its rationale — a duplicated definition across two rule files is the drift the spec's file split exists to prevent +- fixed — [Minor] Task 8's replacement silently dropped the shipped sentence "any developer contact resets the count" and added the un-specced qualifier "counting only rounds that returned a verdict"; license: the spec, which directs no deletion here; the reset sentence is retained — the new definition makes stating the reset event more valuable, not less — and the qualifier is kept with its derivation recorded, since the bullet's own next sentence says the count comes from the round headings and a round that died without a verdict mints none +- fixed — [Minor] Task 7's Step 5 deleted "`concerns` is the autonomy zone", which the spec did not direct removed and which stays true under the new design; license: the spec, which directs only the self-fix clause deleted; the sentence is retained in the replacement text and the task says why an un-specced deletion must not ride along with a specced one +- fixed — [Minor] Task 11's Step 1 claimed four commands return nothing "as this plan was written", which the plan's own `adversary:` frontmatter falsified on the day the step was written; license: the mechanical fact, verified in-session; the step now names this plan as the second known hit, says it is a true unfinished-work hit rather than a false positive, and states when it clears — at the confirming round's LGTM, before implementation +- fixed — [Minor] the self-review waived "the refusals", which the spec's Changes-by-file lists among the lifecycle rule's changes, without citing anything licensing the omission; license: the spec's own text plus the shipped rule; the two refusals with a rule-side trace are now mapped explicitly — no-fourth-severity rides Task 1's severity paragraph, hit-outstanding is already-shipped prose from wave one — and the self-review distinguishes "needs no task" from "is already in the file" + +One defect was found by the session while applying the above, and it is +the wave's own most instructive moment. Retaining the reset sentence for +the second finding made Task 8's first check score `1` on both sides of +its edit — a check the repair itself rendered vacuous, in the plan whose +constraint against exactly that was written two rounds earlier. The +mechanical before/after comparison caught it immediately; reading would +not have, because the pattern still looked like the natural anchor for +the bullet. The check now keys on the qualifier the replacement +introduces: + +- fixed — [Important] repairing the reset-sentence finding made Task 8's first check vacuous, since the phrase it searches is now present both before and after the edit; license: this plan's own before/after constraint; the check keys on `counting only rounds that returned a verdict` instead, which the original bullet lacks, and the step records why the obvious anchor is the wrong one + +Answering the round's focusing question — whether a literal execution +leaves the two rule files saying exactly what the spec designed — the +reviewer's answer was "almost". It diffed every prescribed block against +the spec's sections and simulated the full task sequence: the states, +clauses, fold, historical forms, gate discriminator, Unfinished-work +corrections and all three retired-token consumers land as designed, and +no stranded consumer of `resolved`, `fixed`, `held` or "developer +contact" survives in either file. The single substantive gap was the +evidence-newness base above; the rest were un-specced additions, +deletions and false expectations. + +The round confirmed both historically recurring classes are closed, +mechanically rather than by reading: every prose pattern is uniformly +`\s+`-separated and reproduced its stated before-value against the tree, +every anchored check is paired with both anchors agreeing in simulation, +and Task 11's Step 3 ordering assertion discriminates as intended. + +Its stop signal: after these fixes land, another round buys little — the +prescribed prose has now been read hard against the spec and the whole +plan executed in simulation twice, so the remaining risk is concentrated +in the fix wave itself, and the economical shape is a short pass over +those edits rather than a fresh full read. + ### 2026-09-02 — plan-adversary, fable 5, concerns (round 2, diff-scoped) - fixed — [Important] Task 11's Step 2 banned-term sweep is itself in the wrapped-phrase class: `grep -rn 'ledger entry'` searches a two-word prose phrase with a literal space, so a surviving banned use wrapping as `ledger` / `entry` reads as clean — and the wave *edited this exact command* to add the `_Avoid_` filter without noticing its pattern; license: this plan's own prose-check constraint; the command is now `rg -U -n 'ledger\s+entry'` and the step records that the fifth instance of the class was written during the repair of the fourth From e91da5707f133bd680a0dffacc4f6c4fe19b6b2e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:07:17 +0200 Subject: [PATCH 061/126] docs: round four fix - move task 3 insertion point to preserve the antecedent --- .../2026-09-02-ledger-as-finding-state.md | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index 83e38f4..607b5be 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -255,7 +255,9 @@ git commit -m "feat(working-process): the ledger's clause table" ### Task 3: Historical shapes, the pre-merge sentence, and lawful prose **Files:** -- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — after the clause table +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — after the paragraph beginning "One annotation extends those shapes", immediately before the `### Gate lines` heading + +**The insertion point is chosen, not incidental.** The obvious place is straight after Task 2's clause table, and that is wrong: the shipped sentence "One annotation extends those shapes, and nothing else does" refers to the live shapes block, and Tasks 1–3 push roughly a hundred lines between the two. Inserting this task's historical block just above that sentence hands it a nearer and false antecedent — a reader would bind "those shapes" to the two forms this very task declares nobody may mint. Placing the block *after* that paragraph leaves the live shapes as the sentence's nearest shapes block, which is what it means, and costs no new prose in a rule the spec did not ask to reword. **Interfaces:** - Consumes: the merge from Task 1. @@ -275,6 +277,8 @@ Expected: no output. - [ ] **Step 3: Add the paragraph** +Insert immediately after the paragraph ending "defeats the re-review offer" and immediately before the `### Gate lines` heading: + ``` Ledger lines written before this merge stay as written, as the `scope` token's introduction already established. The shapes they use are kept @@ -942,6 +946,49 @@ what their steps expect. ## Review rounds +### 2026-09-02 — plan-adversary, fable 5, concerns (round 4, full-document) + +- fixed — [Minor] Tasks 1–3 insert roughly a hundred lines between the shipped sentence "One annotation extends those shapes, and nothing else does" and the shapes it refers to, and Task 3's block landed directly above that sentence — handing it a nearer and false antecedent, the two historical forms this plan declares nobody may mint; license: the plan's own statement that the historical shapes are described and never minted, which the drifted antecedent contradicts; Task 3's insertion point moves to after the chain-accepted paragraph and immediately before `### Gate lines`, restoring the live shapes block as the sentence's nearest antecedent with no new prose and no reworded rule text, and the task now records that the placement is chosen rather than incidental + +This round would otherwise have carried the terminating verdict. The +reviewer said so outright: absent the antecedent seam, its verdict would +have been `LGTM`. + +Its verification was the most complete of the four rounds, and it +confirmed both historically recurring classes are extinct rather than +merely quiet. Every stated before-value in the plan was executed against +the tree and reproduced, including the two known Task 11 hits. The whole +plan was applied to scratch copies: sixteen of sixteen Replace blocks +matched verbatim and uniquely, every after-check reproduced its stated +value, and Task 1's Step 6 was additionally checked at its own sequence +point rather than only at the end. Every edit-verifying check was +re-derived for vacuity, including the one this session had just rekeyed, +and no other check was found to have been made vacuous by the round-3 +wave. No fifth wrapped-phrase instance exists, and every anchored check +is either paired or a verbatim copy of a published command. + +It also cleared the round-3 deviation it was asked to attack rather than +protect: Task 9's pointer carries the base's substance inline — "new +against what the folded line records" — and defers to the lifecycle rule +only for the refinement, so a reader of `workflow.md` alone can apply the +rule. The reviewer declined to re-raise it. Task 8's un-specced qualifier +survived the same treatment: a heading is minted at stamp time and +carries the verdict, so a heading-derived count necessarily counts only +verdict-returning rounds, and the qualifier states a consequence rather +than adding a rule. + +The spec mapping was verified in both directions — every Changes-by-file +item lands in a named task, and no task ships prose the spec does not +design or license. + +Its stop signal: a fifth round does not earn its cost. The leftover was a +single insertion-point change whose correctness is verifiable by eye, and +the plan has now been fully simulated twice by two separate rounds with +zero recurrence in any historical class. The reviewer's recommendation to +the dispatcher was to apply the one fix, verify the single edit directly, +and treat a further full round as the developer's call rather than a +process necessity. + ### 2026-09-02 — plan-adversary, fable 5, concerns (round 3, full-document) - fixed — [Important] Task 9 omits the base against which evidence counts as new, which the spec's Changes-by-file assigns to `workflow.md`; the plan ships it only into `spec-plan-lifecycle.md` via Task 5, so an executor produces a `workflow.md` whose new-evidence judgment has no stated base in the file governing the round's behaviour; license: the spec, which the plan's own Global Constraint makes the winner on disagreement; the paragraph now carries the base as a pointer to the lifecycle rule's definition, a second check proves it reached the file, and the deviation from the reviewer's suggested full sentence is recorded in the task with its rationale — a duplicated definition across two rule files is the drift the spec's file split exists to prevent From 3d5bbb16ddff4b3ae4aaae4006dca7b6aaa30374 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:16:58 +0200 Subject: [PATCH 062/126] docs: close the plan review loop with the resolution annotation --- .../2026-09-02-ledger-as-finding-state.md | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index 607b5be..614236a 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -2,7 +2,7 @@ ticket: none date: 2026-09-02 status: draft -adversary: concerns +adversary: concerns (resolved 2026-09-02) spec: ../specs/2026-09-02-ledger-as-finding-state-design.md branch: feature/audit-errata base: develop @@ -946,6 +946,27 @@ what their steps expect. ## Review rounds +**Loop closed 2026-09-02 by the developer**, with `adversary: concerns +(resolved 2026-09-02)` rather than a fifth round. What resolved it: round +4's single Minor was fixed in `e91da57`, and round 4 was a full-document +round whose reviewer stated that absent that one seam its verdict would +have been the terminating `LGTM`. The fix was one insertion-point change, +verified directly — the anchor text exists verbatim in the target, no +step still refers to the old location, and no check's value moves, +since Task 3's phrase check and Task 11's ordering assertion are both +position-independent within the section. + +The loop ran four rounds and four propagation-gate episodes, every gate +returning CLEAN. Rounds 1 and 2 concentrated on check mechanics, round 3 +read the prescribed rule prose against the spec, and round 4 simulated +the whole plan and re-tested every historically recurring class with no +recurrence. The developer was in contact at every round boundary, so the +round cap was never the binding constraint; the closure is a cost +judgment, taken with the reviewer's own stop signal in hand. + +The plan is implementation-ready. The next gate is the developer's +`status` flip to `approved`. + ### 2026-09-02 — plan-adversary, fable 5, concerns (round 4, full-document) - fixed — [Minor] Tasks 1–3 insert roughly a hundred lines between the shipped sentence "One annotation extends those shapes, and nothing else does" and the shapes it refers to, and Task 3's block landed directly above that sentence — handing it a nearer and false antecedent, the two historical forms this plan declares nobody may mint; license: the plan's own statement that the historical shapes are described and never minted, which the drifted antecedent contradicts; Task 3's insertion point moves to after the chain-accepted paragraph and immediately before `### Gate lines`, restoring the live shapes block as the sentence's nearest antecedent with no new prose and no reworded rule text, and the task now records that the placement is chosen rather than incidental From ae07b3d467dd97497e798a6bfe882479717c45dd Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:19:17 +0200 Subject: [PATCH 063/126] docs: approve the ledger-as-finding-state plan --- docs/plans/2026-09-02-ledger-as-finding-state.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index 614236a..ad97d83 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-09-02 -status: draft +status: approved adversary: concerns (resolved 2026-09-02) spec: ../specs/2026-09-02-ledger-as-finding-state-design.md branch: feature/audit-errata @@ -847,7 +847,7 @@ rg -l --no-ignore --crlf '^\s+(grilled|architect|adversary|architect-fallback|ad Expected, with two known hits: - the **first** returns `docs/plans/2026-07-13-rules-distribution.md`, a body quotation of the convention rather than a frontmatter hit — confirm with `grep -n 'grilled: grilling'` on that file and check the line sits below the closing `---`; -- the **second** returns **this plan**, whose own `adversary:` field carries a live verdict throughout the review loop. That is a true unfinished-work hit, not a false positive, and it clears when the confirming full-document round's `LGTM` is stamped — which happens before implementation, so by the time an executor reaches this step the command should return nothing. If it still returns this plan, the loop has not closed and implementation has started early; +- the **second** returned **this plan** throughout the review loop, whose own `adversary:` field carried a live verdict. That was a true unfinished-work hit, not a false positive. It cleared when the loop closed on 2026-09-02 with `adversary: concerns (resolved 2026-09-02)`, the annotation defeating the command's tail anchor exactly as an `LGTM` replacement would have. By the time an executor reaches this step the command returns nothing; if it returns this plan again, a later round reopened the loop and implementation has started early; - the remaining three return nothing. An earlier draft of this step claimed all four of the last commands were clean "as this plan was written", which its own frontmatter falsified on the day the step was written — the plan was carrying `adversary: blocking` at the time. From 34f5cebe423b770cd75387c22b8c9ba0d3a88c29 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:20:22 +0200 Subject: [PATCH 064/126] feat(working-process): four ledger states, authorizer as a clause --- .../rules/spec-plan-lifecycle.md | 71 +++++++++++++------ 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 0ae975c..9d6f309 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -129,31 +129,62 @@ always says so. Under the heading each finding takes one line, its disposition the leading token: - - fixed — [] ; license: ; - - held — [] ; question: [; counter: ] - - open — [] - - resolved — [] ; landed in
- - resolved (declined) — [] ; + - open — [] + - held — [] ; question: ; options: + - fixed — [] ; ; + - declined — [] ; ; + +The severity bracket is omitted on a line whose sole authorizer is +`ruling:` **and** which no reviewer graded — both legs, never one: + + - fixed ; ruling: ; + +`open` and `held` are the non-terminal states, and the only two the +Unfinished-work list anchors. `fixed` and `declined` are terminal and +say what became of the document: it changed, or it stands. + +The two dates on a terminal line record different events and are both +written even when they coincide. The leading date is when the line +reached its terminal state; `ruling:` is when the decision it cites was +taken. On an ordinary developer-authorized line the two are the same day +and say so; on a fold they differ, and that divergence is the point of +carrying both. + +The severity slot is a reviewer's grade, so it is omitted exactly where +there is none: a change the developer directed mid-round is not a +finding, and inventing a grade for it would be the same manufacture the +authorizer rule forbids. This adds no fourth severity value; the +glossary's three stand. + +`fixed` and `resolved` merge because they were never two states. Both +mean the document changed on account of this finding, and they differed +only in who authorized it, which is now a clause. Merging also frees a +word the rules used for two objects — `concerns (resolved )` +annotates a verdict, while `resolved ` annotated a finding. - `open` — written at stamp time, before the findings are triaged. An `open` line surviving a session means the remediation never ran, and the document's next touch re-offers it. -- `fixed` — the session fixed the finding alone, licensed by a decision - it can cite: a statement in the document itself, a glossary term or - `_Avoid_` ban, a recorded ADR, or a previously resolved held line. The - citation goes on the line. No citable license means the finding is - held, and a finding that could go either way is a decision. - `held` — the finding needs the developer. The line carries the - concrete question, phrased so one short answer resolves it. Where the - finding is disputed or contested, the `counter:` clause carries the - evidence the developer needs in order to answer, so the dispute and - the question travel on one line. The oscillation tripwire's named - flip is that evidence. -- `resolved ` — closes a held line once the answer lands. The - answer's substance goes into the document's design text; the ledger - line points at it and never duplicates it. - `resolved (declined)` records the developer keeping the - document as it was. + concrete question and the options with the session's recommendation; + where the finding is disputed or contested, `counter:` carries the + evidence the developer needs in order to answer, and the oscillation + tripwire's named flip is that evidence. +- `fixed ` — the document changed on account of this finding. Its + authorizer says who decided: `license:` where the session cited a + written decision, `ruling:` where the developer did. +- `declined ` — the document stands. It always carries `ruling:`, + because declining is a decision and triage gives a session no license + to decide. + +Each disposition line is written before the edit it describes, or with +it — never batched at the end of a wave. The dangerous failure is not a +session dying mid-round but a fix wave half-applied with no lines +written: the body has changed, nothing says which change belongs to +which finding, and the next round's brief reads a diff source that is +silently wrong. Writing contemporaneously makes a partial wave +self-evident, since `open` and `fixed` lines mixed under one heading say +exactly where the session stopped. One annotation extends those shapes, and nothing else does. A spec whose developer accepts a From 3b77f4f76e0f51dcb8cef95b738c553351b45bda Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:20:48 +0200 Subject: [PATCH 065/126] feat(working-process): the ledger's clause table --- .../rules/spec-plan-lifecycle.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 9d6f309..9277d31 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -186,6 +186,34 @@ silently wrong. Writing contemporaneously makes a partial wave self-evident, since `open` and `fixed` lines mixed under one heading say exactly where the session stopped. +The leading token is a queryable state. Clauses are payload. + +| clause | carries | on | +|---|---|---| +| `license: ` | the written decision the session acted on | `fixed` | +| `ruling: ` | the developer authorized it; on a fold, the prior ruling's date followed by `folding
` naming what it folds against | `fixed`, `declined` | +| `question:` | the question, phrased so one short answer resolves it | `held` | +| `options:` | the options and the session's recommendation | `held` | +| `counter:` | the session's evidence where the finding is disputed or contested | `held` | +| `deviation:
` | where the rationale for departing from a reviewer's suggestion lives | `fixed` | + +`question:` and `options:` are both required on a `held` line: the batch +that relays them is a transcript, and a session that dies between the +relay and the answer leaves the next session to re-derive the options, +possibly differently, so the developer answers a question that silently +changed. `counter:` and `deviation:` are conditional, written whenever +their condition holds. + +Every terminal line carries exactly one authorizer. + +Payload costs nothing structurally. Four of the five Unfinished-work +commands anchor a frontmatter field and are held to the frontmatter +block by the list's default scope guard, so no body line reaches them at +all; the fifth is this ledger's own, anchored on `^- `, which an indented +continuation does not match. Payload under a line is therefore invisible +to every published command, and where it runs long it belongs in +indented sub-bullets rather than in a longer line. + One annotation extends those shapes, and nothing else does. A spec whose developer accepts a diff-scoped chain at the consumption gate gains `, chain accepted ` From ae3439da55b9d8bf2bde805e941b66f4e6234fff Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:21:13 +0200 Subject: [PATCH 066/126] feat(working-process): retain historical ledger shapes, permit prose --- .../rules/spec-plan-lifecycle.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 9277d31..6f88fea 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -221,6 +221,24 @@ on that round's LGTM heading: the dispatcher appends it there on the decline, and its presence defeats the gate's re-ask, as `, waived ` defeats the re-review offer. +Ledger lines written before this merge stay as written, as the `scope` +token's introduction already established. The shapes they use are kept +here as described historical forms rather than deleted: + + - resolved — [] ; landed in
+ - resolved (declined) — [] ; + +A reader must still parse pre-merge documents, and a fold against a +pre-design settled line cites a date off a token the live grammar no +longer produces. These two shapes are described, never minted: no +session writes a new line in either form. + +Narrative prose between the lines of a `## Review rounds` section is +lawful and expected. This grammar governs headings, lines, and their +indented payload; a paragraph explaining why a wave went the way it did +belongs there too. A lint over the section reads the anchored lines and +ignores the prose. + ### Gate lines The propagation gate, when that agent is available, writes two shapes of From 5048eb4538c35024e9dd1e0bdd1566cc46f564ff Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:21:28 +0200 Subject: [PATCH 067/126] fix(working-process): the hit token discriminates a gate line, not the date --- plugins/working-process/rules/spec-plan-lifecycle.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 6f88fea..31aa565 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -252,10 +252,12 @@ a graded finding: Neither carries a license either, because a hit's fix is licensed by its own derivation. -Both are written at gate time, under the last round's heading. The date -each line carries tells a gate episode apart from that round's own -findings, so a gate never mints a heading of its own — the round -heading's grammar is closed, and a gate is not a round. Writing at gate +Both are written at gate time, under the last round's heading. The `hit` +token tells a gate line apart from that round's own findings; the date +does not, since a gate episode and the round it precedes commonly share +one. A gate still never mints a heading of its own, on the separate +ground that the round heading's grammar is closed and a gate is not a +round. Writing at gate time is what the lines are for: a dismissal must exist while the episode is still re-dispatching, or the gate cannot terminate, and the next diff-scoped brief is composed before its own round is stamped. A gate From 04e17fbbaeff81bb265759bc5c0e76fc76cd0787 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:21:56 +0200 Subject: [PATCH 068/126] feat(working-process): relitigation branches on the authorizer clause --- .../rules/spec-plan-lifecycle.md | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 31aa565..7adab98 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -282,10 +282,26 @@ that would dismiss the same hit differently argues against written words rather than silence. Neither joins the unfinished-work anchors: both are closed when written and owe nobody a next move. -A resolved held line is a recorded decision. When a later round re-raises -the problem it settled, the new finding is folded and cited against that -line, never asked again — state prevents relitigation, not the -reviewer's memory. +A line carrying `ruling:` is a recorded developer decision, and what a +later round may do with it depends on what that round brings: + +- re-raised without new evidence — folded and cited, never asked again; + the fold produces `declined ` carrying `ruling:` with the prior + ruling's date and a `folding` citation of the line it folds against, + so the authorizer is cited rather than manufactured; +- re-raised with new evidence — `held`, its `counter:` citing the prior + ruling, because a session that folded this alone would arbitrate + between a reviewer and a recorded developer decision. + +Evidence is new relative to what the folded line records — its claim and +the reasoning its clauses carry — not relative to the reviewer's +wording. A session that cannot tell holds rather than folds. + +A pre-design settled line carries no authorizer clause and is settled by +its token alone; a fold against one cites the date on that token, which +is when the developer decided. + +State prevents relitigation, not the reviewer's memory. ## Unfinished-work list From a10d1ff9b92627096cfea9f6691359e863363bc4 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:22:26 +0200 Subject: [PATCH 069/126] fix(working-process): ledger close names the merged tokens --- plugins/working-process/rules/spec-plan-lifecycle.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 7adab98..0761ed2 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -320,7 +320,7 @@ matching line sits inside the document's frontmatter block — between the later pair — because a document quoting this convention in its body describes it rather than instantiating it. That guard is the default. An entry re-scopes it only by publishing its own match scope as a fourth -leg, and the review-loop ledger entry below is the one that does. +leg, and the review-loop entry below is the one that does. - **Grilling pending** — a session's outcomes are recorded and not yet applied. @@ -364,9 +364,9 @@ anchors are tolerant on purpose, so a relocated field is still found. The Misplaced stamp command anchors `^\s+` instead, because there the indentation is the defect it looks for rather than an accident to tolerate. Those anchors all sit on a frontmatter field; the review-loop -ledger entry anchors a leading disposition token instead, so there the -close is a rewrite — `open` or `held` becomes `resolved `, and the -anchor stops matching. +entry anchors a leading disposition token instead, so there the close is +a rewrite — `open` or `held` becomes `fixed ` or +`declined `, and the anchor stops matching. ## Lifecycle offers From 77910eb827b55c9393a9632a02b68b8067351b1e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:22:53 +0200 Subject: [PATCH 070/126] feat(working-process): move workflow.md off the retired resolved token --- plugins/working-process/rules/workflow.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index fb9c415..7ab77ba 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -189,8 +189,8 @@ the developer. Triage decides each finding by its license, never by its grade. A finding is self-fixable when the session can cite the decision that licenses the fix — a statement in the document itself, a glossary term -or `_Avoid_` ban, a recorded ADR, or a previously resolved `held` -line — and the citation goes on the finding's line in the disposition +or `_Avoid_` ban, a recorded ADR, or a line carrying `ruling:` — and +the citation goes on the finding's line in the disposition ledger the spec-plan-lifecycle rule defines. Everything else is held for the developer, and a finding that could go either way is a decision. Consequences the loop states outright: @@ -297,10 +297,11 @@ evidence to attack, never a defence to protect. - `LGTM` ends the loop — on a plan, only a full-document round's LGTM does. -- `blocking` suspends autonomy entirely: relay, stamp, stop. A blocking - round licenses no self-fixes, because reshaping a design the reviewer - judged broken as a whole is design work and re-enters through the - design conversation. `concerns` is the autonomy zone. +- `blocking` suspends autonomy entirely: relay, stamp, stop — no further + round without the developer. It licenses no separate fix prohibition, + because triage already holds what the prohibition was reaching for: a + design reshape has no citable license by construction, so it is held + whatever the verdict's grade. `concerns` is the autonomy zone. - Round cap: three autonomous rounds per document per field without developer contact. Hitting the cap escalates in one batch — what was fixed, what remains, why — rather than halting silently, and any @@ -312,9 +313,11 @@ evidence to attack, never a defence to protect. until the developer answers it: the resolution annotation the spec-plan-lifecycle rule defines records their close, and no session writes it without their answer. -- Oscillation tripwire: a finding re-raised against a `fixed` line is - never re-fixed autonomously. Two readings of one license are a - contested reading, so it escalates as held, the flip named. +- Oscillation tripwire: a finding re-raised against a line carrying + `license:` is never re-fixed autonomously. Two readings of one license + are a contested reading, so it escalates as held, the flip named. A + re-raise against a line carrying `ruling:` is the relitigation case + instead, and the spec-plan-lifecycle rule owns it. The cap guards spend and the signal guards sense; both escalate, and neither is a wall. Relay stays the developer's standing veto — every From 2af78971d1c3d2b214b690701cccb19398fc1aaa Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:23:22 +0200 Subject: [PATCH 071/126] feat(working-process): define developer contact, state the cap is best-effort --- plugins/working-process/rules/workflow.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 7ab77ba..f61d2e7 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -303,9 +303,16 @@ evidence to attack, never a defence to protect. design reshape has no citable license by construction, so it is held whatever the verdict's grade. `concerns` is the autonomy zone. - Round cap: three autonomous rounds per document per field without - developer contact. Hitting the cap escalates in one batch — what was - fixed, what remains, why — rather than halting silently, and any - developer contact resets the count. + developer contact, counting only rounds that returned a verdict. + Hitting the cap escalates in one batch — what was fixed, what remains, + why — rather than halting silently, and any developer contact resets + the count. Developer contact is a message from the developer: not a + relay they read, not an escalation the session sent, not an unanswered + batch. The count is derived from the round headings and the reset + event is recorded nowhere, so the cap is best-effort by construction; + a session that cannot count its own rounds escalates rather than + assuming, since resetting to zero would let a long session grant + itself three fresh rounds after every compaction. - All-Minor signal: two consecutive rounds whose findings are all Minor end the unattended run. Triage the round as always — by license, never by grade — and escalate with an offer of a fresh round instead of @@ -322,7 +329,7 @@ evidence to attack, never a defence to protect. The cap guards spend and the signal guards sense; both escalate, and neither is a wall. Relay stays the developer's standing veto — every report reaches them before the session acts on it — and a model-cap -refusal mid-loop is already developer contact: the drop-or-wait +refusal mid-loop forces developer contact: the drop-or-wait question above is never answered autonomously. ### What a diff-scoped LGTM certifies From fb1f601352d98dc2b355e25115957062e4b7fa95 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:23:55 +0200 Subject: [PATCH 072/126] feat(working-process): the ledger is standing context for a diff-scoped round --- plugins/working-process/rules/workflow.md | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index f61d2e7..0ffc032 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -281,6 +281,32 @@ needs no snapshot, commit, or hash — these documents stay uncommitted through the rounds, and the ledger is the only durable account of the diff. +Diff-scoping forbids re-reviewing the document beyond the diff, and the +ledger is part of the document — so without a clause the reviewer is cut +off from the one section recording what the developer already decided. +The ledger is therefore always in scope for a diff-scoped round as +context, never as a review target, and what that protects is narrow: + +- settled lines may be re-raised only with new evidence — new against + what the folded line records, the base the spec-plan-lifecycle rule + defines — which routes to `held` rather than to a fold. A line + carrying `ruling:` is settled by that clause; a historical line + written before this design, `resolved (declined)` included, + carries no authorizer clause and is settled by its token alone. Both + are the developer's decisions, and both are protected on the same + footing; +- `held` lines carry questions already put, so a round does not + duplicate one; +- `fixed` lines carrying `license:` get no protection at all — the + previous round's are the diff and are named as the first thing to + attack, and older ones are simply unprotected, since a reviewer told + not to re-raise a fix would lose the property diff-scoping was + adopted for. + +The reviewer learns what it may not reopen, never what it may not find. +Naming the section rather than copying its lines keeps the brief from +growing with the round count. + Every brief states the loop's terminators outright — the cap and the all-Minor signal below — rather than improvising them late, and asks the reviewer for its own stop signal: judge whether another round earns From 330528ec94979ead29a9507cc1e828b91488f602 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:24:37 +0200 Subject: [PATCH 073/126] docs: normalize wave one's bare gate line to the shape it defined --- docs/specs/2026-08-31-review-loop-errata-wave-one.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/specs/2026-08-31-review-loop-errata-wave-one.md b/docs/specs/2026-08-31-review-loop-errata-wave-one.md index df3ec76..2c125e7 100644 --- a/docs/specs/2026-08-31-review-loop-errata-wave-one.md +++ b/docs/specs/2026-08-31-review-loop-errata-wave-one.md @@ -154,7 +154,7 @@ release carrying this wave takes a minor bump rather than a patch. - fixed — [Minor] "the round's relay" had no referent before an integrity audit, which is not a round; license: the gate's own list of three firing points; now "the next report the session relays to the developer" - fixed — [Minor] the `counter:` clause admitted only a finding the session disputes, while the tripwire case is one where it takes no side; license: the tripwire's own definition as a contested reading; widened to "disputed or contested" - fixed — [Minor] "no session writes it on their behalf" forbade the session from writing the annotation at all, against the writing model everywhere else; license: the lifecycle rule's definition of the annotation as a dispatcher-written artifact; now "without their answer" -- dismissed 2026-08-31 — eight sites in the shipped spec and plan still describe the pre-errata design; counter: both carry `status: implemented` and record what shipped in 0.14.0, and the spec's architect verdict certifies a body an `integrity:` hash covers, so a body edit would un-certify text a reviewer did read; `revises:` carries the pointer instead +- hit dismissed 2026-08-31 — eight sites in the shipped spec and plan still describe the pre-errata design; counter: both carry `status: implemented` and record what shipped in 0.14.0, and the spec's architect verdict certifies a body an `integrity:` hash covers, so a body edit would un-certify text a reviewer did read; `revises:` carries the pointer instead ### 2026-09-01 — architect, opus 5, blocking (round 2, diff-scoped) @@ -200,6 +200,7 @@ a better argument for it, recorded as a seam below. - resolved 2026-09-01 — [Minor] `hit fixed` dropped the `license:` clause its sibling shape declares mandatory without the definition site saying why; landed in "Gate lines" (one clause: neither shape carries a license, because a hit's fix is licensed by its own derivation) - resolved 2026-09-01 — [Minor] the published `revises:` example used a plan-relative path, wrong for the field's commonest case; landed in the frontmatter block (`./.md`, leaving `../specs/` to `spec:`, which is genuinely plans-only) - resolved 2026-09-01 (declined) — [Important] the two-re-dispatch bound produces an outstanding-hit state no shape carries and no anchor surfaces; the document stands with the gap stated rather than closed: "Gate lines" now says outright that neither shape covers it, that it owes the developer a decision, and that the workflow rule's report is its only record until a shape exists. Designing that shape is the wave-two question of whether gate episodes are first-class ledger units, and answering it here would decide wave two by accident +- hit fixed 2026-09-02 — this document's own bare `- dismissed 2026-08-31` line predated the `hit dismissed` shape its wave went on to define; the token is added, and nothing else on the line changes - resolved 2026-09-01 (declined) — [Important] the glossary has no owner on the fix-wave path — the grilling-session fires at spec authoring, so an errata wave editing shipped rules bypasses it, and two of this wave's three instances were semantic where no mechanical pass could reach; the document stands because the fix is a process change to triage or to the gate's standing targets, not a wording change to this wave, and it is carried to wave two's list Round 3's stop signal: no fourth round, and its reasons do not expire — From bb1bdd62b7a0712687864aee3e5e92c79a3f9110 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:25:48 +0200 Subject: [PATCH 074/126] docs: record the implementation run and correct task 5's before-value --- .../2026-09-02-ledger-as-finding-state.md | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index ad97d83..e39b25b 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -435,7 +435,7 @@ State prevents relitigation, not the reviewer's memory. - [ ] **Step 4: Run the check again** -Expected: no output, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). Its before-value is `0` — the word does not appear in the file until Task 2 writes it — so the pair discriminates. +Expected: no output, and `grep -c 'folding' plugins/working-process/rules/spec-plan-lifecycle.md` prints at least `2` (the clause table row from Task 2 and this paragraph). Its before-value **at this task's own sequence point is `1`**, not `0`: the word is absent from the pristine file, but Task 2 has already written the clause-table row by the time Task 5 runs. The pair still discriminates, `1` to `2`. Measured during implementation, where a stated `0` was the first thing this step got wrong. - [ ] **Step 5: Validate and commit** @@ -946,6 +946,34 @@ what their steps expect. ## Review rounds +### 2026-09-02 — implementation + +All eleven tasks executed on `feature/audit-errata`, one commit each, +every check run and every stated value reproduced except one: + +- fixed 2026-09-02 — [Minor] Task 5's Step 4 stated a before-value of `0` for its `folding` count, true of the pristine file but not of the file Task 5 actually meets — Task 2 writes the clause-table row first, so the real before-value at that sequence point is `1`; license: the measurement, taken during implementation; the step now states `1` and names the sequence point, and the check discriminates either way + +The defect is the before/after constraint's own blind spot, and worth +naming: the constraint asks for a value *before the step*, and a plan +author naturally computes it against the document as it stands rather +than as the task will find it. Four rounds of review, two full +simulations and four propagation gates all reproduced the `0` without +challenging it, because every one of them measured the same thing the +author did. Only running the tasks in order exposed it. A stated +before-value in a multi-task plan is a claim about a *simulated +intermediate state*, and nothing but execution or an explicitly +sequenced simulation can check it. + +Everything else landed clean: Task 1 `0,0,1,1`; Task 2's paired table +row and the `6,1` anchor claim; Task 3's block placed after the +chain-accepted paragraph, with round 4's antecedent fix confirmed in the +file (the live shapes at line 132 remain the nearest block above the +"One annotation extends those shapes" sentence at 217, and the +historical block sits below it at 228–229); Tasks 4–9 each returning +exactly their stated after-values, with both sentences round 3 restored +verified present; Task 10's two gate lines; and Task 11's five published +commands returning only the known body-quotation hit. + **Loop closed 2026-09-02 by the developer**, with `adversary: concerns (resolved 2026-09-02)` rather than a fifth round. What resolved it: round 4's single Minor was fixed in `e91da57`, and round 4 was a full-document From 870e0a16a3c60f0a3c44f93850f67ed5477803a3 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Wed, 2 Sep 2026 17:31:16 +0200 Subject: [PATCH 075/126] docs: mark wave two spec and plan implemented --- docs/plans/2026-09-02-ledger-as-finding-state.md | 9 ++++++++- docs/specs/2026-09-02-ledger-as-finding-state-design.md | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/plans/2026-09-02-ledger-as-finding-state.md b/docs/plans/2026-09-02-ledger-as-finding-state.md index e39b25b..f6af69b 100644 --- a/docs/plans/2026-09-02-ledger-as-finding-state.md +++ b/docs/plans/2026-09-02-ledger-as-finding-state.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-09-02 -status: approved +status: implemented adversary: concerns (resolved 2026-09-02) spec: ../specs/2026-09-02-ledger-as-finding-state-design.md branch: feature/audit-errata @@ -964,6 +964,13 @@ before-value in a multi-task plan is a claim about a *simulated intermediate state*, and nothing but execution or an explicitly sequenced simulation can check it. +Task 11's Step 5 propagation gate ran over the whole implemented change +set and returned CLEAN — no internal contradiction, no consumer left +behind, no counter wrong. It produced no hits, so it writes no gate +lines. Like the four before it, it omitted the model self-report the +workflow rule requires; five dispatches, five omissions, and the +reliance derivation is the one recorded under round 1's heading. + Everything else landed clean: Task 1 `0,0,1,1`; Task 2's paired table row and the `6,1` anchor claim; Task 3's block placed after the chain-accepted paragraph, with round 4's antecedent fix confirmed in the diff --git a/docs/specs/2026-09-02-ledger-as-finding-state-design.md b/docs/specs/2026-09-02-ledger-as-finding-state-design.md index 9d57b0b..741d2f3 100644 --- a/docs/specs/2026-09-02-ledger-as-finding-state-design.md +++ b/docs/specs/2026-09-02-ledger-as-finding-state-design.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-09-02 -status: draft +status: implemented grilled: 2026-09-02 architect: concerns (resolved 2026-09-02) integrity: 2026-09-02 (sha: bf41005) From faf2dd0ccc6944a5687db3aafadb43b72ab070e8 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 08:45:51 +0200 Subject: [PATCH 076/126] fix(working-process): the self-report survives both auditors' early-exit paths --- plugins/working-process/README.md | 5 ++-- .../agents/integrity-auditor.md | 24 ++++++++++++------- .../agents/propagation-auditor.md | 19 +++++++++++---- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index 9a58708..6566ac9 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -154,9 +154,10 @@ dispatch, and reviews never dispatch on the cheapest available family. A dispatch refused on the dispatched model's cap offers a one-family drop (once) or waiting for the reset; a verdict produced below the prescribed tier gets a fallback record and a re-review offer — grammar -and lifecycle in the spec-plan-lifecycle rule. Agents self-report the +and lifecycle in the spec-plan-lifecycle rule. Verdict agents self-report the model they ran on (family plus version) so the dispatcher can verify -before stamping. +before stamping; the two audit agents report the family alone, which is +the rung their comparison reads. An audit is not a review, and that floor governs reviews alone: the `propagation-auditor` dispatches on the cheapest available family, diff --git a/plugins/working-process/agents/integrity-auditor.md b/plugins/working-process/agents/integrity-auditor.md index 681fd38..e114f55 100644 --- a/plugins/working-process/agents/integrity-auditor.md +++ b/plugins/working-process/agents/integrity-auditor.md @@ -34,11 +34,17 @@ The judgment below is the share of the work no cheaper rung does — the mechanical share belongs to the propagation audit, and the split is the point. -Your report therefore opens with a one-line model self-report, family -plus version, which the dispatcher compares against the dispatched and -the prescribed tier before stamping. A run below the prescribed tier -earns no stamp and is re-dispatched. Report the model you actually ran -on, never the model the dispatch asked for. +Your report therefore opens with a one-line model self-report — the +family you ran on, which is the tier — and the dispatcher compares it +against the dispatched tier before stamping. A run below the prescribed +tier earns no stamp and is re-dispatched. Report the model you actually +ran on, never the model the dispatch asked for. + +Report the family alone. A self-reported version proved unreliable where +it was measured, on the sibling propagation audit: two runs dispatched +under one identical model string reported different versions, one of them +a different model entirely. The tier comparison reads the family, so the +version added a number the dispatcher had to ignore. ## Fresh context, and the preconditions it rests on @@ -61,9 +67,9 @@ confirm both: written counter-derivation does not hold the gate shut. If the brief leaves a precondition unmet — pending edits, a confirmed -hit still outstanding — say so in one line and stop. A run against a -stale file wastes the tier and returns defects the developer has already -fixed. +hit still outstanding — open with the self-report, name the unmet +precondition in one line, and stop. A run against a stale file wastes the +tier and returns defects the developer has already fixed. ## Target and moment @@ -109,7 +115,7 @@ the finding you would have manufactured. Open with the self-report, one line: - model: + model: Then the defects, one entry each: diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 9128ffb..7193e0b 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -35,9 +35,14 @@ the split: every duty below is procedural (parse, enumerate, count, diff), which a capable model does casually badly and a cheap model does well when told to derive by counting. -Your report therefore opens with a one-line model self-report, family -plus version, which the dispatcher compares against the dispatched and -the prescribed rung. Your exposure runs upward: below the cheapest family +Your report therefore opens with a one-line model self-report — the +family you ran on, which is the rung — and the dispatcher compares it +against the dispatched rung. + +Report the family alone. Two runs dispatched under one identical model +string once reported different versions, one of them a different model +entirely, so a reported version supplies a number the dispatcher must +ignore. The dispatched string is the record of what ran. Your exposure runs upward: below the cheapest family there is no rung, but an omitted model inherits the session's model, and an over-tier run does this work casually badly — a false clean line would then feed the integrity gate unnoticed. A mismatched run earns no @@ -116,12 +121,16 @@ text that defeats the anchor its own command relies on. Open with the self-report, one line: - model: + model: -A clean audit then reports one line and nothing else — the literal token: +A clean audit runs to exactly two lines: the self-report above, then the +literal token. CLEAN +Add nothing after the token. The self-report opens every report, and a +clean run is the case where that is easiest to forget. + Otherwise, one entry per hit: — derivation: From 8ea01a3f54e6a8209c41d30d39e830de1dd45ed1 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 08:45:51 +0200 Subject: [PATCH 077/126] docs: record the auditor self-report errata and its falsifiable prediction --- .../2026-09-07-auditor-self-report-errata.md | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 docs/specs/2026-09-07-auditor-self-report-errata.md diff --git a/docs/specs/2026-09-07-auditor-self-report-errata.md b/docs/specs/2026-09-07-auditor-self-report-errata.md new file mode 100644 index 0000000..9517941 --- /dev/null +++ b/docs/specs/2026-09-07-auditor-self-report-errata.md @@ -0,0 +1,104 @@ +--- +ticket: none +date: 2026-09-07 +status: implemented +revises: ./2026-08-27-audit-agents-design.md +branch: feature/audit-errata +base: develop +--- + +# Auditor self-report errata — the CLEAN contract and the rung narrowing + +Wave three, package A. Two corrections to the audit agents, both licensed +by measurements the audit-agents design already recorded, and one of them +by a decision that design explicitly left to the developer. + +## The measurement that prompted it + +Five `propagation-auditor` dispatches across the wave-two review loop +(2026-09-02), every one on `claude-haiku-4-5-20251001`, every one asked +for the model self-report its card mandates. **All five omitted it.** +Emphasis escalated and changed nothing: the second brief called the +requirement mandatory and named the first omission as its reason; the +third asked plainly and got back the single word `CLEAN`. + +The first diagnosis — move the duty into the agent card — was wrong, and +reading the card is what disproved it. The duty was already there twice: +a section explaining the reasoning, and an output template opening the +`## Output` section. An instruction present in the card *and* in every +brief was dropped anyway, which rules out placement and repetition as +the lever. + +## Defect 1: an early-exit path that swallows the self-report + +`propagation-auditor.md` told the agent to open with the self-report and +then said a clean audit "reports one line and nothing else". The second +sentence reads as governing the whole report. **All five omissions were +clean runs**, and the third returned literally one line — exactly what +the absolute reading prescribes. + +The defect originates in the design, not the card: the audit-agents spec +says "A clean audit reports one line — the literal token `CLEAN`" and +then, in the next sentence, "The report opens with the model +self-report". The card implemented the spec faithfully. + +**Fixed** by counting the self-report into the clean report: a clean +audit runs to exactly two lines, and the instruction to add nothing is +scoped to what follows the token. + +`integrity-auditor.md` carries a second, unmeasured instance of the same +class — "say so in one line and stop" on the unmet-precondition path. +Fixed the same way. Repairing one instance of a mechanical fault and +leaving its sibling is the failure this branch measured five times over +in a different class, so the class is closed rather than the instance. + +## Defect 2: a self-report finer than its consumer, and unreliable + +Both auditor cards asked for "family plus version". The workflow rule +compares "against the dispatched and the prescribed rung" — the family. +The version was therefore precision the consumer never read, and the +audit-agents design had already measured it as untrustworthy: two runs +under one identical dispatched string reported "haiku 4" and +"claude-3-5-haiku-20241022", the second a different model entirely. + +That design recorded the measurement and stopped there, in its own words: +"The prescription above stands unchanged — narrowing it to the rung is +the developer's call, and this paragraph records the measurement rather +than pre-empting it." **The developer made that call on 2026-09-07.** + +**Fixed** in both cards, prose and output template: report the family +alone, with the reason stated where the instruction lives. + +## Deliberately out of scope + +Verdict agents keep "family plus version". Four sites still carry it — +the lifecycle rule, `architect.md`, `plan-adversary.md`, and the README — +and the measurement covers propagation runs only. Narrowing a verdict +agent's self-report is a separate question with separate evidence, and +folding it in here would be the un-specced change riding along with a +specced one that this branch's own review rounds flagged twice. + +The README's generic "Agents self-report" became false the moment the +auditors narrowed, so it now names both cases: verdict agents report +family plus version, the audit agents report the family. + +## The prediction this package is worth judging by + +Package A ships a falsifiable claim, which is why it went first: **a +clean propagation run should now return two lines rather than one.** + +The confound is stated rather than hidden. This branch produced no +non-CLEAN propagation run, so "clean" and "omitted" never varied +independently — the correlation is perfect and unisolated. A single +hit-returning dispatch separates them. `integrity-auditor` has no clean +path and is not implicated by the data at all; it was dispatched once, +outside the measuring session, and its self-report behaviour remains +unmeasured. + +## Process + +No review round ran. The verdict and audit agents were unavailable in the +session that made these edits, so the propagation gate that normally +precedes a dispatch could not run either — including over this errata. +The changes are three files, and each carries its rationale beside the +text it governs; a round remains worth offering when the agents return. From 3cc00d6f6903688f415eba5644ea697bd1957134 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 09:27:55 +0200 Subject: [PATCH 078/126] docs: record the confirmed self-report prediction and the closed gate debt --- .../2026-09-07-auditor-self-report-errata.md | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/docs/specs/2026-09-07-auditor-self-report-errata.md b/docs/specs/2026-09-07-auditor-self-report-errata.md index 9517941..e26c7f2 100644 --- a/docs/specs/2026-09-07-auditor-self-report-errata.md +++ b/docs/specs/2026-09-07-auditor-self-report-errata.md @@ -82,23 +82,48 @@ The README's generic "Agents self-report" became false the moment the auditors narrowed, so it now names both cases: verdict agents report family plus version, the audit agents report the family. -## The prediction this package is worth judging by +## The prediction, and its confirmation -Package A ships a falsifiable claim, which is why it went first: **a +Package A shipped a falsifiable claim, which is why it went first: **a clean propagation run should now return two lines rather than one.** -The confound is stated rather than hidden. This branch produced no +**Confirmed 2026-09-07.** The first gate dispatched after the fix — a +propagation audit over this errata's own change set, which the Process +section below records as previously ungated — returned: + + model: haiku + + CLEAN + +Two lines. The brief deliberately **did not ask for the self-report**, so +the line came from the card alone; and it names the family without a +version, which is the narrowing this errata also made. One observation +confirms both halves. + +The contrast is the evidence: five dispatches before the fix, every one +clean, every one omitting the self-report, several of them asking for it +in the brief emphatically. One dispatch after the fix, clean, self-report +present, brief silent. Emphasis never moved it; the card did. + +One confound remains stated rather than hidden. This branch still has no non-CLEAN propagation run, so "clean" and "omitted" never varied -independently — the correlation is perfect and unisolated. A single -hit-returning dispatch separates them. `integrity-auditor` has no clean -path and is not implicated by the data at all; it was dispatched once, -outside the measuring session, and its self-report behaviour remains +independently before the fix — the pre-fix correlation was perfect and +unisolated, and the post-fix run is a single observation. The mechanism +is now the best-supported explanation rather than a proven one. +`integrity-auditor` has no clean path and was never implicated; its +unmet-precondition path, fixed here as the same class, remains unmeasured. ## Process -No review round ran. The verdict and audit agents were unavailable in the -session that made these edits, so the propagation gate that normally +No verdict round ran. The verdict and audit agents were unavailable in +the session that made these edits, so the propagation gate that normally precedes a dispatch could not run either — including over this errata. The changes are three files, and each carries its rationale beside the -text it governs; a round remains worth offering when the agents return. +text it governs; an architect round remains worth offering. + +**The gate ran on 2026-09-07** once the agents returned, over this +errata's own change set, and returned CLEAN across four classes: +consumers left behind, internal contradictions, claim fidelity in this +document, and recomputed counters. That closes the gate debt above and +supplied the confirmation recorded in the previous section. From c9f7b1e1d2656e0b2ef0e02a9ec8e1ed2e42a9d7 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 10:26:56 +0200 Subject: [PATCH 079/126] docs: spec the diff-scoped chain debt, its anchor and its discharge token --- ...026-09-07-diff-scoped-chain-debt-design.md | 499 ++++++++++++++++++ 1 file changed, 499 insertions(+) create mode 100644 docs/specs/2026-09-07-diff-scoped-chain-debt-design.md diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md new file mode 100644 index 0000000..7147f1a --- /dev/null +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -0,0 +1,499 @@ +--- +ticket: none +date: 2026-09-07 +status: draft +revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-09-02-ledger-as-finding-state-design.md] +branch: feature/audit-errata +base: develop +--- + +# What the loop owes after a diff-scoped LGTM + +Wave three, package B. A review loop's first round reads the whole +document and every later round is diff-scoped, so a diff-scoped `LGTM` +certifies a chain rather than a fresh whole-document read. That chain +leaves a debt, the rules prescribe how to discharge it, and nothing +records whether anyone did. + +## Problem + +A spec's consumption gate offers a pair as one question — an integrity +audit, or a confirming full-document round — and a plan's loop takes one +confirming round before it may terminate. Both mechanisms work. Neither +leaves a mark that says the debt was paid. + +**One document has already passed all the way through unpaid.** +`docs/specs/2026-08-27-audit-agents-design.md` ran `concerns` +(full-document) → `concerns` (diff-scoped) → `LGTM` (round 3, +diff-scoped), carries `architect: LGTM` and `status: implemented`, and +has no `integrity:` stamp. It reached plan-writing and implementation on +a chain nobody audited and nobody accepted. The gate never fired, and no +published command reports it. + +## What measurement established + +Wave two recorded this as a seam: "A plan's owed confirming round has no +Unfinished-work entry … no command matches it, so `process-status` +reports clean while a confirming round is owed." Checking that claim +against the repo overturned it, and the correction reshapes the package. + +**A plan's owed confirming round is already surfaced.** The rules +withhold the frontmatter stamp on a plan's diff-scoped LGTM, so the field +keeps the previous round's verdict, and that verdict is always one the +**Unresolved verdict** command matches. The derivation has two legs, and +the second is the one the ancestor design already worried about: + +- a diff-scoped round always has a predecessor, and that predecessor + never returned `LGTM`, because an `LGTM` from a full-document round + ends the loop; +- an annotated predecessor — `concerns (resolved )` — is + grep-clean, which the ancestor names outright. But annotating *is* the + close, and "scoping never spans a close": the next round on a closed + document is a new loop's first round, which reads the whole document + and is therefore never diff-scoped. So a grep-clean field and a + diff-scoped LGTM heading cannot co-occur under the live grammar. + +The seam's premise fails on plans. It survives only for a document whose +headings predate the `scope` token, which the open seams below record. + +**The unsurfaced state lives on specs.** A spec's diff-scoped LGTM *is* +stamped, so its field reads `LGTM` and no command fires. What such a spec +owes is the gate's pair offer rather than a round, and the gate's own +defeat token records only one of the three ways that offer can be +discharged. + +**The token has never been written.** Every occurrence of +`, chain accepted ` in the repo is a definition or a plan step, +never a use. Renaming or redefining it therefore costs nothing, and that +free hand expires the first time a session writes one. + +## The design + +### The class and its anchor + +`spec-plan-lifecycle.md` gains a sixth Unfinished-work class: + + - **Chain debt** — a diff-scoped `LGTM` heading carrying no + record that what it owed was discharged. + `rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/` + Scope: a hit counts only inside a `## Review rounds` section — the + second entry to re-scope the default guard, for the reason the + first one does. + Owner: for a spec, the consumption gate's pair offer; for a plan, + the confirming full-document round. + +The anchor reads a record the round-heading grammar already produces, so +it works backwards: it reports the live instance with no new write +anywhere. The tail `$` is exact, and the annotation below defeats it — +the idiom the list already uses for `(resolved )`, +`(adjudicated )` and `, waived `. + +### The token + +`, debt discharged ` replaces `, chain accepted `. + +It names an **event** — this heading's debt was discharged on that date — +and never a property of the document. Events keep their meaning; a +property goes stale. The distinction is load-bearing: on the audit path +the discharge is conditional on a body hash, and a token claiming the +chain is *good* would contradict a later edit, while a token recording +what happened on a date never does. + +**One word must be true on all three paths, and that test clears the +field by itself.** `accepted` is true only on the decline. `confirmed` +and `audited` are true only on one performance path each. `satisfied` +looked like continuity — the rules already say a matching stamp +"satisfies the gate" — and is a trap: satisfaction is discharge *by +performance*, so a waived debt is discharged without it, which makes the +word false on precisely the path that leaves no other trace. It fails +twice over, because the hash-match case also satisfies the gate and +writes no annotation, so the word would manufacture a symmetry that does +not hold. `met`, `paid`, `fulfilled` and `redeemed` carry the same +performance-only defect. + +`discharged` is the genus word: English discharges an obligation by +performance *or* by release and declines to say which — the same refusal +this design makes about the reason clause. The document's own prose +reached for it seventeen times before the token did. + +The noun is `debt` rather than `chain` because the objects differ, as +this design's opening sentence already says: the chain leaves a debt. A +chain is an evidence structure and is not the kind of thing anyone +discharges. The house family is otherwise nounless — `(resolved )`, +`(adjudicated )`, `, waived ` all let the annotated record +supply the noun — so a bare `, discharged ` would fit the family +more strictly. It loses on one point that outweighs the five characters: +a round heading names an agent and a model, and a bare `discharged` +beside them invites a reader to think somebody was dismissed. + +The comma is not decoration either. Parenthesised tokens qualify a value +— `concerns (resolved )` changes what the verdict means — while +comma-appended tokens add a later event to a finished record. The +glossary calls a round heading "the immutable record of one dispatch", +and this annotation is written later, by a different actor, about a +different event, so it goes after the closing parenthesis rather than +inside it: + + ### — architect, , LGTM (round 3, diff-scoped), debt discharged + +Three paths discharge the debt, all three write the same token, and the +dispatcher writes it in every case: + +- **the developer declining the gate's pair** — written in the decline + turn, before the work the decline licenses begins. This is the only + path whose trace exists nowhere else, which is what makes the + annotation necessary rather than convenient, and writing it before the + plan is the ledger's write-ahead discipline applied literally. +- **an integrity audit** — written once the audit's dispositions are + applied, and before the `integrity:` stamp, for the reason the next + section gives. +- **any later full-document round, at its stamping turn, whatever its + verdict** — the debt is discharged by the reading, not by the grade. A + confirming round returning `concerns` has paid the debt and left the + loop running; without this clause its heading would sit bare and the + anchor would fire forever. + +A full-document round reads the whole document, so it annotates **every** +unannotated diff-scoped LGTM heading above it, not only the one it +immediately follows. A long plan loop can hold more than one — a +diff-scoped LGTM, a confirming round returning `concerns`, a fix wave, a +second diff-scoped LGTM — and one full-document read settles all of them +at once. Stating it this way removes the question of which heading a +round is "the confirmation for", which has no answer worth defining. + +Where a session discharges the gate and dies before annotating, the +annotation's own derivation licenses a later session to write it: the +later full-document heading or the `integrity:` stamp is on the page, and +a fix a derivation licenses never waits for the developer. Only the +decline path has nothing to derive from, and there the debt correctly +re-surfaces and the developer declines again. + +The token carries a date and nothing else. No clause records which path +discharged the gate, because each path leaves its own trace — an +`integrity:` stamp, a later full-document heading, or neither — and no +named consumer reads the path. The gate's re-ask is defeated by the +annotation whatever discharged it, and the command matches whatever +discharged it. Inferring the path from those traces is a reading +convenience, never a rule: a developer may decline and later commission +an audit anyway, and the inference would then be wrong with nothing +depending on it. + +### The annotation precedes the hash + +On the audit path the order is: apply the audit's dispositions, write the +annotation, recompute the body hash, stamp `integrity:`. + +The `integrity:` hash covers the text below the frontmatter's closing +`---`, which includes the `## Review rounds` section and the heading the +annotation lands on. A stamp written before the annotation is therefore +stale the moment the annotation is appended — dead on arrival, recording +a discharge its own hash disowns. + +### The confirming round's authority + +`workflow.md` states two things it has never stated. + +**The confirming round counts against the round cap.** The count is +derived by folding the round headings, and excluding one kind of heading +would require classifying them — a full-document round *after* a +diff-scoped LGTM is confirming, another full-document round is not. That +is a second fragile derivation in the one place the rules already concede +the cap is best-effort, because the reset event is recorded nowhere. +Counting needs no new state and no new derivation. + +The consequence is stated rather than hidden: a plan whose loop spent its +three rounds escalates once before its confirming round. That round is +the most expensive shape a round takes — a whole document at the +prescribed tier — so a cap that guards spend should guard it above all. +Escalation is one cheap batch, and developer contact resets the count +through machinery that already exists. + +**The confirming round is autonomous under the loop's standing consent.** +The rules make it a consequence of the terminator rather than an offer: +"one full-document confirming round follows". The one-interruption +contract reserves interruptions for a decision genuinely the +developer's, and a mandated round is not one. Without consent nothing +changes, because every dispatch waits anyway. + +### The Unresolved verdict owner leg + +That entry's owner leg reads "a fresh round at the prescribed tier, or +the resolution annotation". On a plan whose latest heading is a +diff-scoped LGTM, writing `concerns (resolved )` closes the verdict +while skipping the confirming round — which `workflow.md` forbids: "For a +plan the loop never terminates on a diff-scoped LGTM." + +A published owner leg therefore licenses a move a sibling rule forbids. +The defect predates this package; the new class only illuminates it, and +shipping a report whose own remedy is forbidden would be a deliberate +self-injury. The leg gains a plan exception: there the confirming round +closes the verdict, not the annotation. + +The entry also names the co-firing outright. On a plan in this state two +classes report — Unresolved verdict on the withheld stamp, Chain debt +on the bare heading — and that is one debt seen from two sides. The +confirming round extinguishes both. Nobody should build suppression +machinery for it, and nobody should "fix" the duplicate. + +### The riders + +Each is its own item, named separately on purpose: wave two's review +rounds twice caught un-specced changes riding along with specced ones. + +**A stop signal gains a durable record.** The rules ask every reviewer to +judge whether another round earns its cost, then give that judgment no +home. It appears in no ledger shape and no clause, so it survives only in +a relay that compaction eats — and practice has already needed it twice, +once to justify overriding a signal and once to close a loop on one. The +signal gets one line under the round heading that gave it, outside every +anchor, because a signal is not a debt. + +Its scope stays qualitative: any later fix wave or new design extinguishes +it, and the judgment belongs to the session that would close on it. Precise +scoping would need a snapshot or a hash of the text the reviewer read, and +this series has refused that machinery for better reasons than this one. The +record is what makes an override auditable, and the override was the real +event. + +**The concurrency limit recovers its reasoning.** The rules say "at most +one live round per document per field within the session" and stop there. +The ancestor design decided the rest and the shipped rule dropped it: a +parallel round from another session is accepted as undetectable and stays +benign, since both rounds record in the body and the field holds the +later stamp. Restoring that is errata rather than design. + +One sentence is genuinely new, because the ancestor ruled before the +round sequence carried weight: a diff-scoped LGTM now certifies a chain, +so an interleave from another session punches a hole no round ever read. +The discharge paths are the mitigation — an audit and a full-document +round both read the whole document — so the gate this package makes +visible is what catches it. Under interleave a heading-derived cap +over-counts, which escalates early: the safe direction. + +### Census sentences rewritten count-free + +Three sentences encode a census of the list and go stale the moment it +grows: + +- "the review-loop entry below is the one that does"; +- "Four of the five Unfinished-work commands anchor a frontmatter field"; +- "Those anchors all sit on a frontmatter field; the review-loop entry + anchors a leading disposition token instead". + +They are rewritten as properties rather than counts — commands under the +default guard never reach a body line; entries publishing their own scope +anchor a leading token or a heading, neither of which an indented +continuation matches. A seventh class then costs no accounting edit. Wave +two's frozen counters are the precedent, and updating the numbers would +repeat that mistake rather than end it. + +### The live instance + +`docs/specs/2026-08-27-audit-agents-design.md` gains +`, debt discharged ` on its round-3 heading, with a ruling recorded in +its own ledger. + +That is a body edit on an `implemented` document, which the lifecycle +rule forbids: "amended only in frontmatter, never in the body". The +package licenses this one class of exception in a sentence — a ledger +annotation is a process record rather than a design amendment — and notes +that it re-arms any `integrity:` stamp, which after `implemented` is +already informational. Wave one set the precedent by normalizing its own +bare `dismissed` line, argued individually and traced in the document's +ledger. + +Without the backfill the class ships with a permanent hit, and hits on +this list carry no durable disposition — there is no `hit dismissed` for +the Unfinished-work list. + +## What the consultations contributed + +Both personas were briefed identically from one canonical file, in fresh +contexts, and neither was told the other's answer. They agreed on the +vehicle, on a bare token, on the cap and autonomy answers, and on +rewriting the census sentences count-free. Two things each found alone +carried the design. + +**The architect supplied the precedent that settles the layering +question.** Asked whether the Unfinished-work list backstopping a gate is +sound or a smell, it answered that **Pending re-review is already that +figure** — a frontmatter state awaiting an offer whose owner is "the +re-review offer at the document's consumption gate". Every class on the +list backstops a process step a session might sleep through. The chain +debt is the only offer-bearing state the index cannot see, so it is the +anomaly rather than the proposal. + +It also weighed a rival this design had not considered: a frontmatter +qualifier (`architect: LGTM (diff-scoped)`), discharged by rewriting the +field. That costs no re-scope, no stale sentences, and would close the +live instance with a legal frontmatter edit. It loses on the point the +class exists for — detection would depend on a *new* write by the same +fleeting session the class protects against, so a document stamped before +the convention would be invisible. "A backstop that inherits the fragility +of what it backstops is a worse backstop." + +**The system designer found both ordering leaks.** The annotation-before-hash +sequence above is its finding, verified here against the rule's own +statement of what the hash covers. So is the owner-leg defect, verified +against both texts. It also enumerated the five states a spec's chain can +occupy and showed that only the decline path lacks any other trace, which +is what makes the annotation necessary rather than convenient — and it +supplied the event-not-property constraint that decides the token's name. + +Both derived the non-LGTM confirming round independently, unprompted, and +reached the same answer: the reading discharges the debt, not the grade. +Two fresh contexts, one conclusion, on the case the briefing had left +open. + +Their only real divergence was in coverage rather than judgment: the +architect counted two stale census sentences and the designer three. The +designer's count is right. + +### A third consultation, on the token alone + +The developer commissioned one more architect consultation once the +design was otherwise settled, with the whole lexical sieve in the brief. +It refuted the token the session had proposed and supplied the test the +session had never articulated: **one word must be true on all three +paths.** The reasoning is folded into "The token" above; three of its +findings deserve recording as findings. + +**It caught the session's strongest argument as a trap.** `satisfied` +looked like continuity because the rules already say a matching stamp +"satisfies the gate". In the vocabulary of obligations this annotation is +reinventing, satisfaction is discharge *by performance*, and a waived +debt is discharged *without* it — so the word is false on exactly the +path the design calls indispensable. The session had proposed it as the +leading candidate. + +**It rejected `closed` on stronger ground than the collision count.** +The annotation is defined to land on a heading whose loop may still be +running, and the same rule file says "an annotation close ends the loop". +The class name carried the collision inverted: a spec's loop *did* close +at the LGTM stamp, and `Unclosed chain` would assert otherwise. Class and +token were renamed together, because a split vocabulary — a grep saying +one word and the fix writing another — is worse than either name alone. + +**It corrected the design's statement of its own meaning.** The sentence +read "discharged, or explicitly waived by the person entitled to waive +it". Waiver is a *mode* of discharge, so the disjunction was redundant — +and the redundancy mattered, because it is precisely the genus reading +that lets one word stay honest on three paths. The sentence now ends at +"discharged". + +## The glossary entry this needs + +`docs/domain/glossary.md` has no entry for either the chain or its debt. +The term is minted here and the grilling session lands it: + +> **Chain debt**: +> The obligation a diff-scoped LGTM leaves — the document was approved +> with no whole-document read at the end, and someone must still take +> responsibility for the part no round re-read, or explicitly decline to. +> Discharged three ways: an integrity audit, any later full-document +> round whatever its verdict, or the developer's recorded decline of the +> gate's pair offer. Recorded as `, debt discharged ` on that +> LGTM's round heading — the record says only that it happened and when, +> never how or how well. Distinct from the chain itself, the +> round-one-plus-reviewed-waves structure the LGTM certifies. +> _Avoid_: chain accepted, chain closed, unclosed chain + +The bare word "chain" folds into this entry rather than minting a second +one. A standalone entry becomes warranted only if rule text starts +predicating things of the chain itself. + +One deliberate near-miss to note: the Unfinished-work list's own glossary +entry bans "debt list" as a name for the list. A single class named Chain +debt does not breach that ban, but nothing has come closer, and a second +debt-flavoured class would. + +## Changes by file + +- `plugins/working-process/rules/spec-plan-lifecycle.md` — the sixth + Unfinished-work class and its scope leg; the annotation paragraph + rewritten from the decline-only `, chain accepted ` to the + three-path `, debt discharged `; the `integrity:` bullet's + annotation-before-hash ordering; the Unresolved verdict owner leg's + plan exception and its note on the deliberate co-firing; the three + census sentences rewritten count-free; and the one-sentence licence for + a ledger annotation on an `implemented` document. +- `plugins/working-process/rules/workflow.md` — the confirming round's + authority (counts against the cap, autonomous under consent) in + `### Terminators` and `### What a diff-scoped LGTM certifies`; the + stop-signal record in `### Re-dispatch briefs`; the restored + concurrency reasoning and its one new consequence. +- `docs/domain/glossary.md` — the **Chain debt** entry above, landed by + the grilling session. +- `docs/specs/2026-08-27-audit-agents-design.md` — the live instance's + backfill: the annotation on its round-3 heading plus the ruling in its + own ledger. +- `plugins/working-process/skills/process-status/SKILL.md` — **no + change.** Verified: the skill already handles a section-scoped entry + generically. + +## Refusals + +- **No reason clause on the token.** Each path leaves its own trace and no + named consumer reads the path. A clause would be a second home for one + fact. +- **No precise scope for the stop signal.** It would need a snapshot or a + hash of what the reviewer read. Position in the ledger gives a coarse + scope for free; precision is not worth its machinery, and this series + has refused snapshots repeatedly. +- **No concurrency detection.** The ancestor's decision — undetectable and + benign — is restored, not replaced. Engineering around it is expensive + and the failure is already mitigated by the discharge paths. +- **No suppression machinery for the plan co-firing.** Two hits on one debt + are documented instead. The Misplaced-stamp suppression works per line, + and these are two different lines. +- **No `status` predicate in the class scope.** `process-status` states that + an entry's scope "narrows where a hit counts, never whether the file + qualifies". A document-level predicate would break that sentence and + force a skill edit with new semantics. +- **No `process-status` edit at all.** Verified: the skill already handles a + section-scoped entry generically — "for a scope naming a section, read the + lines above the match as well" — rather than special-casing the + review-loop entry. + +## What this supersedes, and what it does not + +The autonomous-loop design says a spec's diff-scoped LGTM "owes nothing +standing: it is the loop's normal terminal state, settled at the +consumption gate by the audit, the confirming round, or the recorded +acceptance above." + +Read in full, that sentence is **right about the shape and silent about +the record**. It already names all three discharge paths — this package +invents none of them — and its claim is only that the *loop* owes +nothing further, which stands. What it never says is how a later reader +learns whether the gate settled anything, and the live instance is what +that silence costs: two of the three paths left no mark, the gate never +fired, and the document reached `implemented` with nobody able to tell. + +So the correction is narrower than superseding a decision. The design's +`revises:` pointer records a departure in one respect: a spec's +diff-scoped LGTM does carry a standing obligation *until the gate is +recorded as settled*, where the ancestor treated the gate's existence as +settlement enough. + +Wave two's recorded seam is corrected differently — not wrong that a gap +exists, wrong about which gap. Its premise about plans fails, and the +state it should have named lives on specs. + +## Open seams + +- **Release-mate consumption gates.** Three offers can be live at one spec + gate — a standing `integrity:` stamp, a diff-scoped-chain LGTM, and a + `*-fallback:` field — and no text orders, merges, or batches them, while + the loop's one-interruption contract is scoped to rounds rather than + gates. The developer put this outside the package. +- **Trailing whitespace defeats every exact tail anchor**, including this + one, and fails toward false clean. The list chose that trade knowingly; + headings are hand-written under more prose pressure than frontmatter + fields, so exposure here is higher than at its neighbours. Not worth a + per-class convention. +- **Headings predating the `scope` token.** `LGTM (round 4)` never matches + the new command, which is correct, but the recovery reading "keys on the + absence of `full-document`" and would call the same heading diff-scoped. + The command and the recovery clause diverge on historical documents. +- **The deferred grammar lint** now has one more anchored line to check. From 6944961703c5e35ad8dde65987165502fd5a4ecb Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 10:40:13 +0200 Subject: [PATCH 080/126] docs: grill the chain-debt spec, mint Chain debt and correct five glossary entries --- docs/domain/glossary.md | 48 ++++++++++---- ...026-09-07-diff-scoped-chain-debt-design.md | 63 +++++++++++++++++-- 2 files changed, 94 insertions(+), 17 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 5de0f42..bf2ef7a 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -248,8 +248,11 @@ _Avoid_: sub-tier record **Consumption gate**: The workflow step at which a document's review verdict is about to be relied on as the basis of further work — plan-writing for a spec, -implementation for a plan. Where re-review offers on fallback-recorded -verdicts fire. +implementation for a plan. Four things fire or come due there: the +re-review offer on a fallback-recorded verdict, the integrity audit +offered when a spec's body hash no longer matches its stamp, the pair +question a diff-scoped chain earns, and the chain debt itself. Nothing +orders them against each other yet. _Avoid_: usage point **Unfinished-work list**: @@ -258,8 +261,9 @@ class of unfinished process work — class name, grep command, the owner of the next move, and optionally the entry's own match scope — and the single definition site for which classes exist. A class that accepts the default scope costs one edit in the rule and none in the consumers -that run it; a class that publishes its own scope costs a consumer edit -too, and the ledger class is the first. A command's output is hits to +that run it. Publishing a scope of its own cost a consumer edit once, to +teach the consumers section scopes at all; every class publishing one +since trades on that lesson for free. A command's output is hits to confirm against the entry's scope — the frontmatter block by default — never Findings. _Avoid_: anchor list, debt list @@ -305,9 +309,13 @@ _Avoid_: sweep agent, verifier **Hit**: The unit a mechanical check returns — an Unfinished-work list command's -match or a propagation-auditor detection: located, binary, confirmed or -dismissed by the dispatcher, never graded. Graded problems are Findings -and belong to review rounds. +match or a propagation-auditor detection: located, binary, never graded. +Graded problems are Findings and belong to review rounds. The two kinds +part company over disposition: a propagation-auditor hit is confirmed or +dismissed by the dispatcher and the outcome is written as a gate line, +while an Unfinished-work hit has no dismissal at all — its only +disposition is ceasing to match, when the state the command anchors is +rewritten or annotated closed. _Avoid_: mechanical finding **Disposition ledger**: @@ -316,16 +324,20 @@ The record a review loop keeps inside the reviewed document, under one It carries the loop's durable state, and nothing else does — the session, the reviewer and the developer are all volatile, and these documents stay uncommitted through the rounds. Per-finding and per-hit -state is written into it; loop-level state is derived from the round -headings and stored nowhere. The name comes from the terminal states +state is written into it, and so is one obligation the consumption gate +owns, the chain debt, because no folding derives it; loop-level state is +derived from the round headings and stored nowhere. The name comes from the terminal states that dominate it in practice; a leading token names a state, terminal or not. _Avoid_: review log, findings table, round log **Round heading**: -The immutable record of one dispatch, opening a round's block in the +The record of one dispatch, opening a round's block in the disposition ledger: date, agent, model self-report, verdict, ordinal and -scope. The loop's derived state — round count, the all-Minor signal, the +scope. Those dispatch-time fields are immutable — they say what one +reviewer was given and returned — while a later event about that round +appends after the heading's closing parenthesis, never inside it. The +loop's derived state — round count, the all-Minor signal, the diff-scoped chain — is read by folding these. _Avoid_: round title, round record (for the heading alone) @@ -343,6 +355,20 @@ disposition lines and nothing else — its own leading token, no severity, no license. _Avoid_: hit line, audit line +**Chain debt**: +The obligation a diff-scoped LGTM leaves: the document was approved with +no whole-document read at the end, so somebody must still take +responsibility for the part no round re-read — or explicitly decline to. +The consumption gate owns it, not the loop, which owes nothing further +once it terminates. Discharged three ways: an integrity audit, any later +full-document round whatever its verdict, or the developer's recorded +decline of the gate's pair offer. Recorded as `, debt discharged ` +appended to that LGTM's round heading, and the record says only that it +happened and when, never how or how well. Distinct from the diff-scoped +chain itself, the round-one-plus-reviewed-waves structure the LGTM +certifies. +_Avoid_: chain accepted, chain closed, unclosed chain + **Verdict agent**: An agent whose report ends in a verdict the dispatcher stamps into the reviewed document's frontmatter — `architect` and `plan-adversary`. diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index 7147f1a..dac6f6b 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -2,6 +2,7 @@ ticket: none date: 2026-09-07 status: draft +grilled: 2026-09-07 revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-09-02-ledger-as-finding-state-design.md] branch: feature/audit-errata base: develop @@ -153,6 +154,20 @@ dispatcher writes it in every case: loop running; without this clause its heading would sit bare and the anchor would fire forever. +**The gate's two arms cost differently, and the offer should say so.** An +integrity audit returns material for the dispatcher to dispose of and +leaves the verdict alone. A confirming round on a *spec* does something +larger: a spec's LGTM already ended its loop, and "scoping never spans a +close", so that round is a new loop's first round. It mints its own +verdict and stamps it — and a `concerns` there flips the field back from +`LGTM` while plan-writing is underway. That is the mechanism working +rather than failing, since finding a real problem before anything is +built on the spec is the whole point, but a developer choosing at the +gate is choosing between two very different prices and should be told +which is which. On a plan the question does not arise: there the +confirming round belongs to the same live loop, because a plan's +diff-scoped LGTM never terminated it. + A full-document round reads the whole document, so it annotates **every** unannotated diff-scoped LGTM heading above it, not only the one it immediately follows. A long plan loop can hold more than one — a @@ -381,10 +396,43 @@ and the redundancy mattered, because it is precisely the genus reading that lets one word stay honest on three paths. The sentence now ends at "discharged". -## The glossary entry this needs - -`docs/domain/glossary.md` has no entry for either the chain or its debt. -The term is minted here and the grilling session lands it: +## What the grilling changed in the glossary + +The grilling session found six defects, all in `docs/domain/glossary.md`, +and applied them inline. Four were pre-existing — this design only +brought them into contact with something that tested them. + +**Two canonical sentences forbade what this design does.** The Round +heading was defined as "the immutable record of one dispatch", and this +annotation appends to it; the Disposition ledger declared that it carries +per-finding and per-hit state while "loop-level state is derived from the +round headings and stored nowhere", and this annotation stores something +that is neither. Both are now qualified rather than waived: a heading's +*dispatch-time fields* are immutable and a later event appends after the +closing parenthesis, and the ledger carries one obligation the +consumption gate owns — the chain debt — because no folding derives it. +The shipped `, chain accepted ` broke both sentences already; it +had simply never been written, so nothing tested them. + +**Consumption gate named one of the four things it owns**, the re-review +offer, omitting the integrity audit, the pair question, and now the chain +debt. It enumerates all four, and says outright that nothing orders them +against each other yet. + +**Hit promised a disposition half of its instances lack.** It read +"confirmed or dismissed by the dispatcher" across both kinds, but only a +propagation-auditor hit has shapes to record that in. An Unfinished-work +hit has no dismissal at all — its only disposition is ceasing to match. +The entry now parts the two, which is also the reason the live instance +needs a backfill rather than a recorded dismissal. + +**Unfinished-work list asserted a cost this design disproved.** It said a +class publishing its own scope "costs a consumer edit too". Verified +against `process-status`: the consumer already reads section scopes +generically, so the cost was one-time, spent on the first such class. The +sentence now says that, count-free. + +And the term itself, previously absent for both the chain and its debt: > **Chain debt**: > The obligation a diff-scoped LGTM leaves — the document was approved @@ -422,8 +470,11 @@ debt-flavoured class would. `### Terminators` and `### What a diff-scoped LGTM certifies`; the stop-signal record in `### Re-dispatch briefs`; the restored concurrency reasoning and its one new consequence. -- `docs/domain/glossary.md` — the **Chain debt** entry above, landed by - the grilling session. +- `docs/domain/glossary.md` — **already done**, applied inline by the + grilling session: the new **Chain debt** entry, plus corrections to + **Round heading**, **Disposition ledger**, **Consumption gate**, + **Hit** and **Unfinished-work list**. The section above says what each + changed and why. No implementation task covers these. - `docs/specs/2026-08-27-audit-agents-design.md` — the live instance's backfill: the annotation on its round-3 heading plus the ruling in its own ledger. From 3b68db9c81cdae4d460deea79bd575e50e69d4da Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 10:49:49 +0200 Subject: [PATCH 081/126] docs: drop a frozen count from the token rationale --- docs/specs/2026-09-07-diff-scoped-chain-debt-design.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index dac6f6b..32d1b7c 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -114,8 +114,10 @@ performance-only defect. `discharged` is the genus word: English discharges an obligation by performance *or* by release and declines to say which — the same refusal -this design makes about the reason clause. The document's own prose -reached for it seventeen times before the token did. +this design makes about the reason clause. It is also the verb this +document reaches for unprompted whenever it explains the mechanism, while +every rejected candidate appears only where the token itself is being +argued about. The token should say what the prose already says. The noun is `debt` rather than `chain` because the objects differ, as this design's opening sentence already says: the chain leaves a debt. A From bacc32975d14f07c92a91936b52b0a6fb11c7823 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 10:59:28 +0200 Subject: [PATCH 082/126] docs: architect round one - name the second token site, drop an unsupported extension --- ...026-09-07-diff-scoped-chain-debt-design.md | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index 32d1b7c..bbc4fef 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -3,6 +3,7 @@ ticket: none date: 2026-09-07 status: draft grilled: 2026-09-07 +architect: concerns revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-09-02-ledger-as-finding-state-design.md] branch: feature/audit-errata base: develop @@ -313,11 +314,19 @@ its own ledger. That is a body edit on an `implemented` document, which the lifecycle rule forbids: "amended only in frontmatter, never in the body". The package licenses this one class of exception in a sentence — a ledger -annotation is a process record rather than a design amendment — and notes -that it re-arms any `integrity:` stamp, which after `implemented` is -already informational. Wave one set the precedent by normalizing its own -bare `dismissed` line, argued individually and traced in the document's -ledger. +annotation is a process record rather than a design amendment. Wave one +set the precedent by normalizing its own bare `dismissed` line, argued +individually and traced in the document's ledger. + +An earlier draft added that the annotation re-arms an `integrity:` stamp +"which after `implemented` is already informational". The rule scopes +that word to plans and says nothing about an implemented spec, so the +parenthetical asserted an extension the cited text does not make. It is +gone rather than repaired: the licence stands on the process-record +distinction alone, and the re-arming is harmless for a reason the rule +does state — a spec's stamp is read at exactly one gate, before +plan-writing, which an implemented spec has long passed, and hash +staleness joins no Unfinished-work entry. Without the backfill the class ships with a permanent hit, and hits on this list carry no durable disposition — there is no `hit dismissed` for @@ -469,9 +478,23 @@ debt-flavoured class would. a ledger annotation on an `implemented` document. - `plugins/working-process/rules/workflow.md` — the confirming round's authority (counts against the cap, autonomous under consent) in - `### Terminators` and `### What a diff-scoped LGTM certifies`; the + `### Terminators` and `### What a diff-scoped LGTM certifies`; **the + decline-path paragraph in that same subsection rewritten off the + retired token** — `, chain accepted ` becomes + `, debt discharged `, and "the developer accepting the chain … + the acceptance is recorded" becomes the three-path framing, since that + wording is the property-not-event reading this design rejects; the stop-signal record in `### Re-dispatch briefs`; the restored concurrency reasoning and its one new consequence. + + The retired token lives in **two** files, and this is the second. The + lifecycle rule's occurrence is the definition site and the obvious one; + this one narrates the same mechanism independently, sits in a + subsection this design already edits for a different reason, and would + survive a literal reading of an earlier draft of this list. Leaving it + would ship the exact defect this design names elsewhere — a grep saying + one word while the fix writes another — so both move together or + neither does. - `docs/domain/glossary.md` — **already done**, applied inline by the grilling session: the new **Chain debt** entry, plus corrections to **Round heading**, **Disposition ledger**, **Consumption gate**, @@ -550,3 +573,30 @@ state it should have named lives on specs. absence of `full-document`" and would call the same heading diff-scoped. The command and the recovery clause diverge on historical documents. - **The deferred grammar lint** now has one more anchored line to check. + +## Review rounds + +### 2026-09-07 — architect, fable 5, concerns (round 1, full-document) + +- fixed 2026-09-07 — [Important] the retired token lives in two rule files, and the Changes-by-file list named only the lifecycle rule's; `workflow.md`'s decline-path paragraph narrates the same mechanism, sits in a subsection this design already edits for another reason, and would have shipped a split vocabulary — the very defect this design names when arguing the class and token must rename together; license: this design's own sentence that a grep saying one word while the fix writes another is worse than either name alone; the manifest now names the second site, its surrounding property-not-event wording, and why one site is easy to walk past +- fixed 2026-09-07 — [Minor] the backfill licence asserted that an implemented spec's `integrity:` stamp is "already informational", extending a word the rule scopes to plans; license: the rule text itself, which says no such thing about specs; the parenthetical is removed rather than repaired, and the harmlessness now rests on what the rule does state — a spec's stamp is read at one gate the document has long passed, and hash staleness joins no Unfinished-work entry + +Two propagation gate episodes precede this round. The first, before the +architect dispatch, returned one hit and is recorded below. The gate +before that dispatch had no round heading to write under, so both lines +land here, at this round's stamp, as the gate-line placement rule +prescribes. + +- hit fixed 2026-09-07 — the token rationale claimed the document's prose "reached for it seventeen times before the token did"; the count was taken over the whole document rather than the text before the token, where the true figure is three, and the whole-document figure had itself moved to thirty-five by the time it was checked; the claim is now a property rather than a count +- hit dismissed 2026-09-07 — the audit reported the frozen count as unsupported at three occurrences; counter: the derivation is right and the defect is worse than reported, since the sentence was wrong on scope *and* stale on value, so the line above records both rather than the single reading the hit named + +Answering the round's focusing question — what the process would newly +get wrong if this shipped as written — the reviewer named exactly one +thing, and it was the Important above: today no token is written +anywhere, so no contradiction between the two rule files is possible; a +literal reading of the old manifest would have created one. + +Its stop signal: no further full-document round. The two findings are +narrow, textually located, and touch neither the vehicle, the token +semantics, nor the derivations — the shape a short diff-scoped round +against these two fixes would close cleanly. From 9f08fb7fda7bbb9e6f769c24f61f203579d80769 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 11:05:48 +0200 Subject: [PATCH 083/126] docs: correct the self-report prediction from confirmed to partly held --- .../2026-09-07-auditor-self-report-errata.md | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/docs/specs/2026-09-07-auditor-self-report-errata.md b/docs/specs/2026-09-07-auditor-self-report-errata.md index e26c7f2..c4de70e 100644 --- a/docs/specs/2026-09-07-auditor-self-report-errata.md +++ b/docs/specs/2026-09-07-auditor-self-report-errata.md @@ -82,14 +82,19 @@ The README's generic "Agents self-report" became false the moment the auditors narrowed, so it now names both cases: verdict agents report family plus version, the audit agents report the family. -## The prediction, and its confirmation +## The prediction, and what testing it actually showed Package A shipped a falsifiable claim, which is why it went first: **a clean propagation run should now return two lines rather than one.** -**Confirmed 2026-09-07.** The first gate dispatched after the fix — a -propagation audit over this errata's own change set, which the Process -section below records as previously ungated — returned: +**It holds sometimes. Two clean runs after the fix, one carrying the +self-report and one not** — so the fix improved the behaviour without +making it reliable, and the section below, which first recorded this as +confirmed on a single observation, was written too early. + +The first gate dispatched after the fix — a propagation audit over this +errata's own change set, which the Process section below records as +previously ungated — returned: model: haiku @@ -97,22 +102,32 @@ section below records as previously ungated — returned: Two lines. The brief deliberately **did not ask for the self-report**, so the line came from the card alone; and it names the family without a -version, which is the narrowing this errata also made. One observation -confirms both halves. - -The contrast is the evidence: five dispatches before the fix, every one -clean, every one omitting the self-report, several of them asking for it -in the brief emphatically. One dispatch after the fix, clean, self-report -present, brief silent. Emphasis never moved it; the card did. - -One confound remains stated rather than hidden. This branch still has no +version, which is the narrowing this errata also made. + +**A later clean run returned `CLEAN` and nothing else**, from the same +fixed card, under a brief that likewise did not ask. So the tally across +this branch is five clean runs omitting the line before the fix, then one +carrying it and one omitting it after. + +That is worth stating precisely, because the honest reading is narrower +than either extreme. The fix did not fail: nothing before it ever +produced the line, and something after it did, so the card's contract is +at least sometimes what the agent follows. But the fix did not make the +behaviour reliable either, and a rule that fires half the time cannot be +the whole mechanism. Either the CLEAN clause was one cause among +several, or compliance is simply variable at this tier. + +The practical consequence is unchanged and was already recorded: a +dispatcher cannot count on the self-report arriving, so reliance on a +propagation gate rests on the derivation below — the prescribed rung is +the cheapest family, so a silent substitution could only run the audit +above tier, which does not invalidate a structural CLEAN. + +Two confounds remain stated rather than hidden. This branch still has no non-CLEAN propagation run, so "clean" and "omitted" never varied -independently before the fix — the pre-fix correlation was perfect and -unisolated, and the post-fix run is a single observation. The mechanism -is now the best-supported explanation rather than a proven one. -`integrity-auditor` has no clean path and was never implicated; its -unmet-precondition path, fixed here as the same class, remains -unmeasured. +independently, and the sample after the fix is two runs. `integrity-auditor` +has no clean path and was never implicated; its unmet-precondition path, +fixed here as the same class, remains unmeasured. ## Process From 3026a237f38f7ee9a4d3ea8dbce4964ce690be4d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 11:13:58 +0200 Subject: [PATCH 084/126] docs: architect round two LGTM, merge the mislabelled gate line, close the loop --- ...026-09-07-diff-scoped-chain-debt-design.md | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index bbc4fef..e860d6d 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -3,7 +3,7 @@ ticket: none date: 2026-09-07 status: draft grilled: 2026-09-07 -architect: concerns +architect: LGTM revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-09-02-ledger-as-finding-state-design.md] branch: feature/audit-errata base: develop @@ -576,19 +576,55 @@ state it should have named lives on specs. ## Review rounds +### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped) + +- fixed 2026-09-07 — [Minor] the gate line below was written as `hit dismissed` while its own `counter:` opened by affirming the audit's derivation; the grammar defines that clause as the derivation which *refutes* the hit, and the workflow rule reserves dismissal for a hit the session believes wrong — this session believed the hit right and understated, which is a fix, not a dismissal; license: those two definitions; the two lines for one hit are merged into the single `hit fixed` line the disposition always warranted, carrying the correction the dismissal had been invented to hold + +The reviewer re-derived the merged line's own facts rather than taking +them: three occurrences before the token, thirty-six across the document +today. That last number had already moved since the gate ran — which the +line anticipates by recording a property rather than a count, and which +is why the repair is the only one that cannot drift again. + +Answering the round's focusing question — whether a manifest is the right +home for a "no consumer left behind" guarantee — the reviewer's answer is +worth keeping as a recorded limit rather than a finding. A hand-written +enumeration is the right place to *record* completeness and the weakest +link in a document that otherwise insists on mechanically-derived state +everywhere. The real backstop is downstream: the propagation gate fires +after any multi-site edit during authoring, so the manifest is an +authoring aid and the gate is the guarantee. That division is correct as +it stands, and the implementation plan should not mistake the manifest +for the proof. + +Its stop signal: the loop closes here. Nothing the wave opened would +repay another round. + +**This close makes the document a second instance of its own subject.** +Round 2 was diff-scoped and returned LGTM, so this spec now carries +exactly the heading its proposed anchor matches, and the command returns +two documents instead of one: the audit-agents spec and this one. The +design predicted the class it belongs to before belonging to it. + +That is a demonstration rather than an embarrassment, and it costs +nothing to discharge honestly. The debt is real — nobody has read this +document whole since round 1, and three fix waves have landed since — so +it goes to the consumption gate like any other, before the plan is +written. What the gate must not do is treat the annotation as +paperwork: if the integrity audit is the chosen path, its dispositions +are applied first and the annotation follows, in the order this design +prescribes. + ### 2026-09-07 — architect, fable 5, concerns (round 1, full-document) - fixed 2026-09-07 — [Important] the retired token lives in two rule files, and the Changes-by-file list named only the lifecycle rule's; `workflow.md`'s decline-path paragraph narrates the same mechanism, sits in a subsection this design already edits for another reason, and would have shipped a split vocabulary — the very defect this design names when arguing the class and token must rename together; license: this design's own sentence that a grep saying one word while the fix writes another is worse than either name alone; the manifest now names the second site, its surrounding property-not-event wording, and why one site is easy to walk past - fixed 2026-09-07 — [Minor] the backfill licence asserted that an implemented spec's `integrity:` stamp is "already informational", extending a word the rule scopes to plans; license: the rule text itself, which says no such thing about specs; the parenthetical is removed rather than repaired, and the harmlessness now rests on what the rule does state — a spec's stamp is read at one gate the document has long passed, and hash staleness joins no Unfinished-work entry -Two propagation gate episodes precede this round. The first, before the -architect dispatch, returned one hit and is recorded below. The gate -before that dispatch had no round heading to write under, so both lines -land here, at this round's stamp, as the gate-line placement rule -prescribes. +A propagation gate episode precedes this round and returned one hit, +recorded below. It had no round heading to write under, so its line lands +here, at this round's stamp, as the gate-line placement rule prescribes. -- hit fixed 2026-09-07 — the token rationale claimed the document's prose "reached for it seventeen times before the token did"; the count was taken over the whole document rather than the text before the token, where the true figure is three, and the whole-document figure had itself moved to thirty-five by the time it was checked; the claim is now a property rather than a count -- hit dismissed 2026-09-07 — the audit reported the frozen count as unsupported at three occurrences; counter: the derivation is right and the defect is worse than reported, since the sentence was wrong on scope *and* stale on value, so the line above records both rather than the single reading the hit named +- hit fixed 2026-09-07 — the token rationale claimed the document's prose "reached for it seventeen times before the token did"; the audit's derivation was right and the defect was worse than it reported, since the sentence was wrong on scope *and* stale on value: the count had been taken over the whole document rather than the text before the token, where the true figure is three, while the whole-document figure had itself drifted past thirty-five; the claim is now a property rather than a count, which is the only repair that cannot drift again Answering the round's focusing question — what the process would newly get wrong if this shipped as written — the reviewer named exactly one From 3712972a67929eb2ea305b34a760a82b80a6df61 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 11:23:42 +0200 Subject: [PATCH 085/126] docs: third post-fix run puts the self-report tally at one in three --- .../2026-09-07-auditor-self-report-errata.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/specs/2026-09-07-auditor-self-report-errata.md b/docs/specs/2026-09-07-auditor-self-report-errata.md index c4de70e..5b5df6f 100644 --- a/docs/specs/2026-09-07-auditor-self-report-errata.md +++ b/docs/specs/2026-09-07-auditor-self-report-errata.md @@ -87,8 +87,8 @@ family plus version, the audit agents report the family. Package A shipped a falsifiable claim, which is why it went first: **a clean propagation run should now return two lines rather than one.** -**It holds sometimes. Two clean runs after the fix, one carrying the -self-report and one not** — so the fix improved the behaviour without +**It holds sometimes. Of three clean runs after the fix, one carried the +self-report and two did not** — so the fix improved the behaviour without making it reliable, and the section below, which first recorded this as confirmed on a single observation, was written too early. @@ -104,18 +104,20 @@ Two lines. The brief deliberately **did not ask for the self-report**, so the line came from the card alone; and it names the family without a version, which is the narrowing this errata also made. -**A later clean run returned `CLEAN` and nothing else**, from the same -fixed card, under a brief that likewise did not ask. So the tally across +**Two later clean runs returned `CLEAN` and nothing else**, from the same +fixed card, under briefs that likewise did not ask. So the tally across this branch is five clean runs omitting the line before the fix, then one -carrying it and one omitting it after. +carrying it and two omitting it after. That is worth stating precisely, because the honest reading is narrower than either extreme. The fix did not fail: nothing before it ever produced the line, and something after it did, so the card's contract is at least sometimes what the agent follows. But the fix did not make the -behaviour reliable either, and a rule that fires half the time cannot be +behaviour reliable either, and a rule that fires once in three cannot be the whole mechanism. Either the CLEAN clause was one cause among -several, or compliance is simply variable at this tier. +several, or compliance is simply variable at this tier — and the second +reading gains weight with every run, since nothing about the three +dispatches differed in the one respect the fix addressed. The practical consequence is unchanged and was already recorded: a dispatcher cannot count on the self-report arriving, so reliance on a From f8d5f32375342f1887e381300869f56fe772caac Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 11:32:57 +0200 Subject: [PATCH 086/126] docs: apply the integrity audit's dispositions and stamp the gate --- ...026-09-07-diff-scoped-chain-debt-design.md | 129 ++++++++++++++++-- 1 file changed, 118 insertions(+), 11 deletions(-) diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index e860d6d..dfd2dde 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -4,6 +4,7 @@ date: 2026-09-07 status: draft grilled: 2026-09-07 architect: LGTM +integrity: 2026-09-07 (sha: 4a838b2) revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-09-02-ledger-as-finding-state-design.md] branch: feature/audit-errata base: develop @@ -311,6 +312,24 @@ repeat that mistake rather than end it. `, debt discharged ` on its round-3 heading, with a ruling recorded in its own ledger. +**That backfill is the decline path, exercised late — not a fourth +one.** The distinction matters, because the three paths above claim to +be exhaustive and a worked example that quietly adds a fourth would +break the rule on its first use. Nothing else fits: no audit ran, no +later full-document round was dispatched, and none ever will be, since +the document is `implemented` and the work it designed has shipped. What +remains is exactly what the decline path is — the developer looking at a +chain nobody read whole and accepting it knowingly. The gate that should +have asked never fired; the developer answers its question anyway, years +late in process terms, and the `ruling:` records who decided rather than +naming a new mechanism. + +Writing the token without that reasoning would put a false claim in the +record. The annotation says a debt was discharged, and on this document +no reading ever happened — so the decline is the only honest discharge +available, and it must be a decision the developer actually takes rather +than a tidying-up the implementation performs on their behalf. + That is a body edit on an `implemented` document, which the lifecycle rule forbids: "amended only in frontmatter, never in the body". The package licenses this one class of exception in a sentence — a ledger @@ -474,8 +493,10 @@ debt-flavoured class would. three-path `, debt discharged `; the `integrity:` bullet's annotation-before-hash ordering; the Unresolved verdict owner leg's plan exception and its note on the deliberate co-firing; the three - census sentences rewritten count-free; and the one-sentence licence for - a ledger annotation on an `implemented` document. + census sentences rewritten count-free; the stop-signal line's shape, + which is ledger grammar and belongs beside the other line shapes rather + than with the instruction that writes it; and the one-sentence licence + for a ledger annotation on an `implemented` document. - `plugins/working-process/rules/workflow.md` — the confirming round's authority (counts against the cap, autonomous under consent) in `### Terminators` and `### What a diff-scoped LGTM certifies`; **the @@ -484,8 +505,9 @@ debt-flavoured class would. `, debt discharged `, and "the developer accepting the chain … the acceptance is recorded" becomes the three-path framing, since that wording is the property-not-event reading this design rejects; the - stop-signal record in `### Re-dispatch briefs`; the restored - concurrency reasoning and its one new consequence. + instruction to record a stop signal, in `### Re-dispatch briefs` beside + the ask that produces it; the restored concurrency reasoning and its + one new consequence. The retired token lives in **two** files, and this is the second. The lifecycle rule's occurrence is the definition site and the obvious one; @@ -546,15 +568,79 @@ learns whether the gate settled anything, and the live instance is what that silence costs: two of the three paths left no mark, the gate never fired, and the document reached `implemented` with nobody able to tell. -So the correction is narrower than superseding a decision. The design's +So the correction is narrower than superseding a decision. The first `revises:` pointer records a departure in one respect: a spec's diff-scoped LGTM does carry a standing obligation *until the gate is -recorded as settled*, where the ancestor treated the gate's existence as -settlement enough. - -Wave two's recorded seam is corrected differently — not wrong that a gap -exists, wrong about which gap. Its premise about plans fails, and the -state it should have named lives on specs. +recorded as settled*, where the autonomous-loop design treated the gate's +existence as settlement enough. + +**The second pointer, at +`./2026-09-02-ledger-as-finding-state-design.md`, records a different +kind of departure and is easy to miss because that document is right +about everything except the one thing it names.** Its open seams say: "A +plan's owed confirming round has no Unfinished-work entry … no command +matches it, so `process-status` reports clean while a confirming round is +owed." Both halves of that are wrong on plans, for the reason "What +measurement established" sets out — the withheld stamp leaves a verdict +the Unresolved-verdict command matches, and no grep-clean field can +co-occur with a diff-scoped LGTM heading under the live grammar. What +survives is the gap's existence, relocated: it lives on specs, where the +stamp is not withheld, and it is about a gate's offer rather than an owed +round. + +That is a departure worth the pointer rather than a correction worth a +footnote, because a reader building on wave two's seam would look for the +missing anchor on the wrong document kind and find the design already +sound there. + +## What the integrity audit settled + +The audit at this document's consumption gate returned two defects, both +fixed above, and six ranked implementer questions. Four are answered +here, because the answers were derivable from the rules and leaving them +to the plan would invite the plan to invent them. + +**The confirming-round arm blocks plan-writing; the audit arm does not.** +Workflow step 4 reads sequentially — the offer fires, "Then write the +implementation plan" — and a round that can flip `LGTM` to `concerns` +must resolve before anything is built on the verdict. The audit arm is +different in kind: it returns material for disposition rather than a +verdict, so plan-writing follows its dispositions rather than waiting on +a second opinion about them. This is the price asymmetry the design +already names, stated as sequencing rather than as cost. + +**The stop-signal line gets a shape, because every other ledger element +has one.** The ledger gives an exact template to disposition lines, to +the severity-free variant, and to both gate lines; a rider that +specifies placement and intent but no form would be the only element a +lint could not read. It takes the leading token `signal`, no severity, +and no authorizer: + + - signal + +It joins no anchor. A stop signal owes nobody a next move — it informs a +decision the developer makes — so it is closed the moment it is written, +like a gate line. + +**The Unresolved-verdict owner leg's exact wording belongs to the plan, +not here.** The design fixes what the leg must stop licensing and why; +the sentence that replaces it is prose the plan prescribes and a `grep` +verifies, like every other rule edit in the manifest. The one constraint +this design does impose on that wording: it states the plan exception +without a count, so a later document kind cannot make it stale. + +**Each new `workflow.md` fact lands in one subsection, not both.** The +cap statement joins the `Round cap` bullet in `### Terminators`, which +is where the count is defined; the autonomy statement joins +`### What a diff-scoped LGTM certifies`, which is where the confirming +round is introduced. Restating either in both places would create the +two-homes-for-one-fact defect this design refuses elsewhere. + +Two questions remain the developer's and are put to them rather than +answered: whether a future undischarged instance gets the same +retroactive decline as the live one, and whether `process-status` should +say anything about the deliberate co-firing on plans beyond what its +matching already does. ## Open seams @@ -578,6 +664,27 @@ state it should have named lives on specs. ### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped) +An integrity audit ran at the consumption gate after this round, on the +most capable tier and a fresh context, with coverage 638 of 638 lines. It +returned two defects and six ranked implementer questions, all disposed +before the plan was written: + +- fixed 2026-09-07 — [Important] the design claims three discharge paths are exhaustive — "all three write the same token … in every case" — while its own live-instance backfill discharged by a developer ruling, which is none of them; license: the exhaustiveness sentence itself, which a worked example may not quietly contradict; the backfill is now derived as the decline path exercised late, with the reasoning that nothing else fits and that writing the token without it would put a false claim in the record +- fixed 2026-09-07 — [Important] `revises:` names two documents and the supersedes section discussed one, leaving a reader unable to tell what this design departs from in the wave-two spec or whether the pointer was stale; license: the lifecycle rule's definition of `revises:` as a claim about the named document; the section now records the second departure — wave two's seam is wrong on plans in both halves, and the gap it should have named lives on specs +- fixed 2026-09-07 — four of the six implementer questions are answered in a new section rather than left for the plan to invent: that the confirming-round arm blocks plan-writing while the audit arm does not, that the stop-signal line takes a shape like every other ledger element, that the owner leg's exact wording is the plan's to prescribe, and that each new `workflow.md` fact lands in one subsection rather than both; license: the rules those answers derive from, cited at each answer +- fixed 2026-09-07 — the stop-signal rider was assigned wholly to `workflow.md`, but its line shape is ledger grammar; license: the ledger's own custody of every other line shape; the manifest now splits the rider, shape to the lifecycle rule and the instruction to write it beside the ask that produces it + +Two questions are the developer's and were put to them rather than +answered: whether a future undischarged instance gets the same +retroactive decline, and whether `process-status` should say anything +about the deliberate co-firing on plans. + +The audit is itself one of the three discharge paths, so this document's +own chain debt is discharged by this episode — but the token it would +carry does not exist yet, since these rules are what this design +proposes. The annotation lands when the implementation lands, and the +class the plan ships will find this document until it does. + - fixed 2026-09-07 — [Minor] the gate line below was written as `hit dismissed` while its own `counter:` opened by affirming the audit's derivation; the grammar defines that clause as the derivation which *refutes* the hit, and the workflow rule reserves dismissal for a hit the session believes wrong — this session believed the hit right and understated, which is a fix, not a dismissal; license: those two definitions; the two lines for one hit are merged into the single `hit fixed` line the disposition always warranted, carrying the correction the dismissal had been invented to hold The reviewer re-derived the merged line's own facts rather than taking From 092a3b917147234192ac8fdbb855f02dc32b3b97 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 12:35:29 +0200 Subject: [PATCH 087/126] docs: write the chain-debt implementation plan --- .../2026-09-07-diff-scoped-chain-debt.md | 1056 +++++++++++++++++ 1 file changed, 1056 insertions(+) create mode 100644 docs/plans/2026-09-07-diff-scoped-chain-debt.md diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md new file mode 100644 index 0000000..b68c393 --- /dev/null +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -0,0 +1,1056 @@ +--- +ticket: none +date: 2026-09-07 +status: draft +spec: ../specs/2026-09-07-diff-scoped-chain-debt-design.md +branch: feature/audit-errata +base: develop +--- + +# Diff-Scoped Chain Debt Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Give the review loop a durable record that a diff-scoped LGTM's chain debt was discharged — a sixth Unfinished-work class that surfaces the debt, a three-path `, debt discharged ` annotation that closes it, and the four rule corrections the new class exposes. + +**Architecture:** Two rule files change and two specs gain a ledger annotation. `spec-plan-lifecycle.md` owns the record — the new class, the annotation's grammar, the ordering against the `integrity:` hash, the Unresolved-verdict owner leg, the stop-signal line shape, and three census sentences rewritten count-free. `workflow.md` owns the loop's behaviour — the gate's pair offer, the confirming round's authority, the instruction to record a stop signal, and the restored concurrency reasoning. The split follows the two rules' existing division of labour; no sentence moves between them. + +**Tech Stack:** Markdown rule files distributed as a Rules payload; `rg` and `grep` commands published inside the rules are the enforcement mechanism; `claude plugin validate` is the structural check. + +## Global Constraints + +- **No code.** Every deliverable is prose in a Markdown file. The verification for each task is a check whose result changes, plus `claude plugin validate`. +- **Edit with the Edit tool, never `sed -i` or `printf >>`** — the process-artifacts rule requires it for artifacts under `docs/` and applies equally to rule files here. +- **Line width follows each file's existing habit** — prose wraps at ~72 characters; the indented grammar blocks and published command lines run long and stay on one line. +- **Public-repo hygiene:** English only, no machine-specific paths, no company or client names. +- **`claude plugin validate .` and `claude plugin validate plugins/working-process` must both pass** after every task. +- **The spec is the source.** Where this plan and `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md` disagree, the spec wins and the plan is wrong. +- **No version bump.** `plugins/working-process/.claude-plugin/plugin.json` already carries a `-dev.audit-errata` discriminator; the release PR mints the real number. +- **The manifest is an authoring aid, not the proof.** This plan's task list is a hand-written enumeration of edit sites, and the architect's round-2 answer names its limit outright: the real "no consumer left behind" guarantee is the propagation gate that fires after multi-site edits, not this list. Task 13 runs that sweep; no task may treat its own completeness as established by being listed here. +- **A check that searches for prose uses `rg -U` and puts `\s+` between *every* pair of words in the pattern; a check that searches for an anchored structural pattern uses `grep`.** These files wrap prose at about 72 characters, so a searched phrase may straddle a line ending and a single-line `grep` then returns 0 where the phrase is plainly present. The constraint is unconditional rather than applied where a wrap looks likely: where the wrap falls is not something a reader reliably predicts, and a uniformly `\s+` pattern is correct whether or not it wraps, so no judgement is exercised and no instance can be missed. An anchored pattern like `^- \*\*Chain debt\*\*` or `^ - signal ` cannot straddle by construction, so single-line matching is correct there. +- **`rg -c` prints nothing and exits 1 when its pattern does not match** — it never prints `0`. A step asserting absence with `rg` therefore expects *no output*; only `grep -c`, which does print `0`, is given a numeric zero expectation. +- **An anchored check on an indented block publishes *both* anchors — exact and tolerant — and asserts their equality.** Never one alone, and never a per-site decision about which. The exact anchor (`^ ` for a grammar block, `^- ` for a list entry) proves the prescribed text is well-formed at the indent the step prescribes; the tolerant anchor (`^\s*`) proves no variant survives anywhere else. Each alone has a blind spot that reads as success: the exact one passes while a leftover sits at another indent, the tolerant one passes while the prescribed block is mis-indented. Equality of the two counts is the assertion, and a divergence localizes which half failed. One case is copied rather than reasoned about: a check mirroring a command the rules publish reproduces it verbatim. +- **Every check that verifies an edit must return a different value before and after its step, and both values are stated.** A check whose before-value equals its after-value verifies nothing, however correct both numbers look — and it survives review precisely because nothing about it appears wrong. A check that verifies no edit is exempt only where its own step says so in words; Task 13 is the sole exempt task here, and its `Files:` line says it modifies nothing. + +--- + +### Task 1: The Chain debt class + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the `## Unfinished-work list` section, inserting a sixth entry after **Unfinished review-loop ledger** and before **Pending re-review** + +**Interfaces:** +- Produces: the class name **Chain debt** and its published command. Tasks 2, 6, 11, 12 and 13 all cite one or the other. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^- \*\*' "$f" # Unfinished-work entries, exact anchor +grep -c '^\s*- \*\*' "$f" # same, tolerant anchor +grep -c '^- \*\*Chain debt\*\*' "$f" # the new entry, exact anchor +grep -c '^\s*- \*\*Chain debt\*\*' "$f" # the new entry, tolerant anchor +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before this task: `5`, `5`, `0`, `0`. The first two must be equal (no `- **` entry sits at another indent); the last two must be equal at zero. + +- [ ] **Step 3: Insert the entry** + +Place it directly after the **Unfinished review-loop ledger** entry's `Owner:` line, before `- **Pending re-review**`: + +```markdown +- **Chain debt** — a diff-scoped `LGTM` heading carrying no record that + what it owed was discharged. + `rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/` + Scope: a hit counts only inside a `## Review rounds` section — the + second entry to re-scope the default guard, for the reason the first + one does, and carrying `-n` for the same reason. + Owner: for a spec, the consumption gate's pair offer; for a plan, the + confirming full-document round. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `6`, `6`, `1`, `1`. Each pair must be equal; a divergence in the first pair means the entry landed at the wrong indent, a divergence in the second means the heading text is malformed. + +- [ ] **Step 5: Verify the published command runs and finds both live instances** + +```bash +rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ +``` + +Expected: exactly two lines, one from `docs/specs/2026-08-27-audit-agents-design.md` and one from `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`. Line numbers are not asserted — they move as the documents change, and asserting them would make this check fail for a reason it does not test. The command is copied into the rule verbatim, so this step proves the rule ships a command that runs. + +- [ ] **Step 6: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 7: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): add the Chain debt Unfinished-work class" +``` + +--- + +### Task 2: The Unresolved-verdict owner leg's plan exception + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the **Unresolved verdict** entry's `Owner:` leg under `## Unfinished-work list` + +**Interfaces:** +- Consumes: the class name **Chain debt** from Task 1. +- Produces: nothing later tasks read. + +The defect this fixes predates the package: the published leg licenses closing a plan's verdict with `concerns (resolved )` while `workflow.md` forbids terminating a plan's loop on a diff-scoped LGTM. The new class only illuminates it. The replacement states the exception without a count, so a later document kind cannot make it stale. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +rg -Uc 'Owner:\s+a\s+fresh\s+round\s+at\s+the\s+prescribed\s+tier,\s+or\s+the\s+resolution\s+annotation\s+above\.' "$f" +rg -Uc 'the\s+confirming\s+full-document\s+round\s+closes\s+the\s+verdict' "$f" +rg -Uc 'one\s+debt\s+seen\s+from\s+two\s+sides' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: `1`, then no output twice (`rg -c` prints nothing on no match). + +- [ ] **Step 3: Replace the owner leg** + +Find: + +```markdown + Owner: a fresh round at the prescribed tier, or the resolution + annotation above. +``` + +Replace with: + +```markdown + Owner: a fresh round at the prescribed tier, or the resolution + annotation above — except on a plan whose latest round heading is a + diff-scoped `LGTM`, where the confirming full-document round closes + the verdict and the annotation may not, since a plan's loop never + terminates on that heading. Such a plan matches Chain debt as well: + one debt seen from two sides, both extinguished by that round, and the + duplicate is deliberate. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: no output for the first pattern (the old sentence is gone), then `1` and `1`. + +- [ ] **Step 5: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 6: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "fix(working-process): the Unresolved-verdict owner leg no longer licenses skipping a plan's confirming round" +``` + +--- + +### Task 3: The three-path annotation replaces the retired token + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the annotation paragraph under `## The disposition ledger`, between "Every terminal line carries exactly one authorizer." and the historical-shapes block + +**Interfaces:** +- Produces: the token `, debt discharged ` and its three discharge paths. Tasks 4, 6, 7, 11 and 12 all write or cite it. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c 'chain accepted' "$f" +grep -c 'debt discharged' "$f" +grep -c '^ ### — architect, , LGTM (round 3, diff-scoped), debt discharged $' "$f" +grep -c '^\s*### — architect, , LGTM (round 3, diff-scoped), debt discharged $' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: `1`, `0`, `0`, `0`. The last two must be equal. + +- [ ] **Step 3: Replace the paragraph** + +Find: + +```markdown +One annotation extends those shapes, and nothing else does. A spec whose +developer accepts a +diff-scoped chain at the consumption gate gains `, chain accepted ` +on that round's LGTM heading: the dispatcher appends it there on the +decline, and its presence defeats the gate's re-ask, as `, waived ` +defeats the re-review offer. +``` + +Replace with: + +```markdown +One annotation extends those shapes, and nothing else does. A +diff-scoped `LGTM` heading gains `, debt discharged ` once the +chain debt it carries is discharged, and its presence defeats the +consumption gate's re-ask, as `, waived ` defeats the re-review +offer: + + ### — architect, , LGTM (round 3, diff-scoped), debt discharged + +The token goes after the closing parenthesis rather than inside it. A +parenthesised token qualifies a value — `concerns (resolved )` +changes what the verdict means — while a comma-appended token adds a +later event to a finished record, and this annotation is written later, +by a different actor, about a different event. + +Three paths discharge the debt, all three write the same token, and the +dispatcher writes it in every case: the developer declining the gate's +pair offer, written in the decline turn before the work that decline +licenses begins; an integrity audit, written once its dispositions are +applied and before the `integrity:` stamp; and any later full-document +round, at its stamping turn, whatever its verdict — the debt is +discharged by the reading, not by the grade. A full-document round reads +the whole document, so it annotates every unannotated diff-scoped `LGTM` +heading above it rather than only the one it follows. + +The token carries a date and nothing else. Each path leaves its own +trace — an `integrity:` stamp, a later full-document heading, or +neither — and no consumer reads the path, so recording it would give one +fact a second home. Where a session discharges the debt and dies before +annotating, the annotation's own derivation licenses a later session to +write it; only the decline path has nothing to derive from, and there +the debt correctly re-surfaces and the developer declines again. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `0`, `2`, `1`, `1`. The `debt discharged` count of `2` covers the definition sentence and the heading example — the three-path paragraph says "discharge the debt" rather than repeating the token, so it does not add to the count. Tasks 4 and 6 each add one more occurrence to this file, which is why Task 13 expects `4` here rather than `2`. The last two must be equal. + +- [ ] **Step 5: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 6: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): replace the decline-only chain token with the three-path debt-discharged annotation" +``` + +--- + +### Task 4: The annotation precedes the hash, and an implemented document admits it + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the `integrity:` frontmatter bullet and the `implemented` frontmatter bullet + +**Interfaces:** +- Consumes: the token from Task 3. +- Produces: the ordering Task 12 follows when it re-stamps this package's own spec. + +Two one-sentence insertions, in two different bullets, joined because both license the same annotation against a rule that would otherwise forbid or invalidate it. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +rg -Uc 'the\s+annotation\s+is\s+written\s+before\s+the\s+hash\s+is\s+recomputed' "$f" +rg -Uc 'One\s+class\s+of\s+body\s+edit\s+is\s+excepted' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: no output for either. + +- [ ] **Step 3: Insert the ordering sentence into the `integrity:` bullet** + +Find: + +```markdown + frontmatter's closing `---`, so writing the stamp never invalidates what + it stamps. Stamper and gate run one command, so the comparison can never +``` + +Replace with: + +```markdown + frontmatter's closing `---`, so writing the stamp never invalidates what + it stamps. Where the audit also discharges a chain debt, the annotation + is written before the hash is recomputed: the hash covers the + `## Review rounds` section, so a stamp written first is stale the moment + the annotation lands. Stamper and gate run one command, so the comparison can never +``` + +- [ ] **Step 4: Insert the body-edit exception into the `implemented` bullet** + +Find: + +```markdown + frontmatter, never in the body: a verdict certifies the body it was + given, and an `integrity:` hash covers exactly that text. +``` + +Replace with: + +```markdown + frontmatter, never in the body: a verdict certifies the body it was + given, and an `integrity:` hash covers exactly that text. One class of + body edit is excepted: a ledger annotation recording a process event, + such as `, debt discharged `, is a process record rather than a + design amendment. +``` + +- [ ] **Step 5: Run the check again** + +Expected after: `1` and `1`. + +- [ ] **Step 6: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 7: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "fix(working-process): order the debt annotation before the integrity hash and license it on an implemented document" +``` + +--- + +### Task 5: The stop-signal line shape + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — a new paragraph under `## The disposition ledger`, after the narrative-prose paragraph and before `### Gate lines` + +**Interfaces:** +- Produces: the line shape `- signal `. Task 9 writes the instruction that produces it and cites this shape by reference. + +The shape lives here because the ledger owns every other line shape; the instruction to write one lives in `workflow.md`, beside the ask that produces it. Splitting the rider this way is what the integrity audit settled. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^ - signal — ' "$f" # exact anchor, grammar-block indent +grep -c '^\s*- signal — ' "$f" # tolerant anchor +rg -Uc 'a\s+stop\s+signal\s+owes\s+nobody\s+a\s+next\s+move' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: `0`, `0`, and no output. The first two must be equal. + +- [ ] **Step 3: Insert the paragraph** + +Place it after "A lint over the section reads the anchored lines and ignores the prose." and before the `### Gate lines` heading: + +```markdown +A reviewer's stop signal takes a line of its own, under the heading of +the round that gave it: + + - signal + +It carries the leading token `signal`, no severity — a judgment about +the next round's marginal value is not a finding — and no authorizer, +since nobody licensed it. It joins no anchor: a stop signal owes nobody +a next move, so it is closed the moment it is written, as a gate line +is. The workflow rule owns the ask that produces it. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `1`, `1`, `1`. The first two must be equal; a divergence means the block sits at the wrong indent. + +- [ ] **Step 5: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 6: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "feat(working-process): give a reviewer's stop signal a ledger line shape" +``` + +--- + +### Task 6: Three census sentences rewritten count-free + +**Files:** +- Modify: `plugins/working-process/rules/spec-plan-lifecycle.md` — the payload paragraph under `## The disposition ledger`, the default-guard paragraph under `## Unfinished-work list`, and the anchor paragraph after the list + +**Interfaces:** +- Consumes: the class from Task 1 and the token from Task 3 — the third rewrite names both. +- Produces: nothing later tasks read. + +Each sentence encodes a census of the list and went stale the moment Task 1 added a sixth entry. Updating the numbers would repeat wave two's frozen-counter mistake; the sentences state properties instead, so a seventh class costs no accounting edit. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +rg -Uc 'Four\s+of\s+the\s+five\s+Unfinished-work\s+commands' "$f" +rg -Uc 'the\s+review-loop\s+entry\s+below\s+is\s+the\s+one\s+that\s+does' "$f" +rg -Uc 'Those\s+anchors\s+all\s+sit\s+on\s+a\s+frontmatter\s+field' "$f" +rg -Uc '[Aa]n\s+entry\s+publishing\s+its\s+own\s+scope' "$f" +``` + +The fourth pattern opens with `[Aa]` because the replacement idiom appears sentence-initially in one rewrite and mid-sentence in the other; `rg` is case-sensitive by default, so a bare `an` would silently miss half of what this step counts. + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: `1`, `1`, `1`, and no output for the fourth. The three stale sentences are present and the replacement idiom is absent. + +- [ ] **Step 3: Rewrite the payload sentence** + +Find: + +```markdown +Payload costs nothing structurally. Four of the five Unfinished-work +commands anchor a frontmatter field and are held to the frontmatter +block by the list's default scope guard, so no body line reaches them at +all; the fifth is this ledger's own, anchored on `^- `, which an indented +continuation does not match. +``` + +Replace with: + +```markdown +Payload costs nothing structurally. An Unfinished-work command under the +list's default scope guard is held to the frontmatter block, so no body +line reaches it at all; an entry publishing its own scope anchors a +leading disposition token or a round heading, and an indented +continuation matches neither. +``` + +- [ ] **Step 4: Rewrite the default-guard sentence** + +Find: + +```markdown +entry re-scopes it only by publishing its own match scope as a fourth +leg, and the review-loop entry below is the one that does. +``` + +Replace with: + +```markdown +entry re-scopes it only by publishing its own match scope as a fourth +leg, and the entries below that do so say it there. +``` + +- [ ] **Step 5: Rewrite the anchor sentence** + +Find: + +```markdown +tolerate. Those anchors all sit on a frontmatter field; the review-loop +entry anchors a leading disposition token instead, so there the close is +a rewrite — `open` or `held` becomes `fixed ` or +`declined `, and the anchor stops matching. +``` + +Replace with: + +```markdown +tolerate. Those anchors sit on a frontmatter field wherever the default +guard holds. An entry publishing its own scope anchors a body line +instead — a leading disposition token or a round heading — and there the +close is a rewrite or an appended annotation: `open` or `held` becomes +`fixed ` or `declined `, and a discharged chain debt gains +`, debt discharged `. Either way the anchor stops matching. +``` + +- [ ] **Step 6: Run the check again** + +Expected after: no output for the first three (all three stale sentences gone), then `2` for the fourth — the replacement idiom appears in the payload rewrite and the anchor rewrite. The default-guard rewrite uses "the entries below that do so", a different construction, and is verified by its own check below. + +- [ ] **Step 7: Verify the default-guard rewrite landed** + +```bash +rg -Uc 'the\s+entries\s+below\s+that\s+do\s+so\s+say\s+it\s+there' plugins/working-process/rules/spec-plan-lifecycle.md +``` + +Expected before this task: no output. Expected after: `1`. + +- [ ] **Step 8: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 9: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md +git commit -m "fix(working-process): state the list's anchor and payload properties without counting its entries" +``` + +--- + +### Task 7: The gate's pair offer and the confirming round's autonomy + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — the two paragraphs under `### What a diff-scoped LGTM certifies` that follow the opening definition + +**Interfaces:** +- Consumes: the token from Task 3. +- Produces: nothing later tasks read. + +This is the second and last site of the retired token. It narrates the same mechanism independently of the lifecycle rule's definition site, so leaving it would ship a grep saying one word while the fix writes another — the exact defect the design names when arguing that class and token rename together. The surrounding property-not-event wording ("the developer accepting the chain … the acceptance is recorded") goes with it. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/workflow.md +grep -c 'chain accepted' "$f" +grep -c 'debt discharged' "$f" +rg -Uc 'the\s+acceptance\s+is\s+recorded\s+rather\s+than\s+remembered' "$f" +rg -Uc 'The\s+confirming-round\s+arm\s+therefore\s+blocks\s+plan-writing' "$f" +rg -Uc 'runs\s+under\s+the\s+loop.s\s+standing\s+consent' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: `1`, `0`, `1`, then no output twice. + +- [ ] **Step 3: Replace both paragraphs** + +Find: + +```markdown +For a spec, the consumption gate before plan-writing offers the pair as +one question — an integrity audit or a confirming full-document round — +and never an offer followed by a re-offer of the option just declined. +When the `integrity-auditor` agent is absent the offer carries the +confirming round alone. Declining is the developer accepting the chain +explicitly, and the acceptance is recorded rather than remembered: the +dispatcher appends `, chain accepted ` to the diff-scoped LGTM +heading, and that annotation defeats the gate's re-ask. + +For a plan the loop never terminates on a diff-scoped LGTM: one +full-document confirming round follows, and the confirming round's +verdict is the one stamped. That carries the single named exception to +the relay-then-stamp order above — a plan's diff-scoped LGTM is relayed +and its round record written, and only the frontmatter stamp waits for +the confirming round. Recovery therefore reads the ledger rather than +the stamp: a plan whose latest round heading is a diff-scoped LGTM that +no later full-document round follows is re-offered its confirming round +at the document's next touch, whatever the frontmatter says. +``` + +Replace with: + +```markdown +For a spec, the consumption gate before plan-writing offers the pair as +one question — an integrity audit or a confirming full-document round — +and never an offer followed by a re-offer of the option just declined. +When the `integrity-auditor` agent is absent the offer carries the +confirming round alone. The two arms cost differently and the offer says +so: an audit returns material for the dispatcher to dispose of and +leaves the verdict alone, while a confirming round on a spec is a new +loop's first round, since the spec's LGTM already closed its loop — it +mints its own verdict and stamps it, so a `concerns` there flips the +field back while plan-writing waits. The confirming-round arm therefore +blocks plan-writing; the audit arm does not, and plan-writing follows +its dispositions. + +Declining is the developer discharging the chain debt by release rather +than by performance, and the discharge is recorded rather than +remembered: the dispatcher appends `, debt discharged ` to the +diff-scoped LGTM heading, in the shape the spec-plan-lifecycle rule +defines, and that annotation defeats the gate's re-ask. The other two +paths write the same token. + +For a plan the loop never terminates on a diff-scoped LGTM: one +full-document confirming round follows, and the confirming round's +verdict is the one stamped. That round runs under the loop's standing +consent like any other — the rules mandate it, so it is no decision of +the developer's and spends none of the round's one interruption. It +carries the single named exception to the relay-then-stamp order above — +a plan's diff-scoped LGTM is relayed and its round record written, and +only the frontmatter stamp waits for the confirming round. Recovery +therefore reads the ledger rather than the stamp: a plan whose latest +round heading is a diff-scoped LGTM that no later full-document round +follows is re-offered its confirming round at the document's next touch, +whatever the frontmatter says. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `0`, `1`, no output, `1`, `1`. + +- [ ] **Step 5: Confirm the retired token is gone from the whole repo's rule payload** + +```bash +rg -n --no-ignore 'chain accepted' plugins/ +``` + +Expected: no output. Before this task the lifecycle rule's occurrence was already removed by Task 3, so this step's before-value is one line (`workflow.md`) and its after-value is none. + +- [ ] **Step 6: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 7: Commit** + +```bash +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): price the gate's two arms and move the decline path onto the debt token" +``` + +--- + +### Task 8: The confirming round counts against the cap + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — the `Round cap` bullet under `### Terminators` + +**Interfaces:** +- Consumes: nothing. +- Produces: nothing later tasks read. + +The fact lands here and nowhere else: this bullet is where the count is defined, and restating it under `### What a diff-scoped LGTM certifies` would create the two-homes-for-one-fact defect the design refuses elsewhere. Task 7 owns the autonomy half for the same reason, in the subsection where the confirming round is introduced. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/workflow.md +rg -Uc "A\s+plan's\s+confirming\s+full-document\s+round\s+counts\s+like\s+any\s+other" "$f" +rg -Uc 'escalates\s+once\s+before\s+its\s+confirming\s+round' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: no output for either. + +- [ ] **Step 3: Extend the bullet** + +Find: + +```markdown + itself three fresh rounds after every compaction. +``` + +Replace with: + +```markdown + itself three fresh rounds after every compaction. A plan's confirming + full-document round counts like any other: the count folds round + headings, and excluding one kind would mean classifying them — a + second fragile derivation in the one place the rules already concede + the cap is best-effort. A plan whose loop spent its three rounds + therefore escalates once before its confirming round, which is the + most expensive shape a round takes and the one a cap guarding spend + should guard first. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `1` and `1`. + +- [ ] **Step 5: Confirm the fact has exactly one home** + +```bash +rg -Uc "confirming\s+full-document\s+round\s+counts\s+like\s+any\s+other" plugins/working-process/rules/workflow.md +``` + +Expected before: no output. Expected after: `1` — one occurrence, not two. A `2` here means the fact was also restated in `### What a diff-scoped LGTM certifies`, which this task forbids. + +- [ ] **Step 6: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 7: Commit** + +```bash +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): count a plan's confirming round against the round cap" +``` + +--- + +### Task 9: The instruction to record a stop signal + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — the paragraph under `### Re-dispatch briefs` that asks the reviewer for its stop signal + +**Interfaces:** +- Consumes: the line shape from Task 5, cited by reference rather than restated. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/workflow.md +rg -Uc 'The\s+signal\s+is\s+recorded\s+where\s+a\s+later\s+session\s+can\s+cite\s+it' "$f" +grep -c '^ - signal — ' "$f" +grep -c '^\s*- signal — ' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: no output, then `0` and `0`. The two zeros must stay zero after this task — the shape belongs to the lifecycle rule, and a copy here would be the second home this plan refuses. + +- [ ] **Step 3: Insert the instruction** + +Find: + +```markdown +enough, and it informs the developer's decision rather than replacing +it. Where the ledger records a deviation from a reviewer's suggestion, +``` + +Replace with: + +```markdown +enough, and it informs the developer's decision rather than replacing +it. The signal is recorded where a later session can cite it: one line +under the heading of the round that gave it, in the shape the +spec-plan-lifecycle rule defines. A signal surviving only in a relay +dies with the next compaction, and practice has needed it twice — once +to justify overriding one, once to close a loop on one. Where the ledger +records a deviation from a reviewer's suggestion, +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `1`, then `0` and `0` — unchanged, proving the shape was cited rather than copied. + +- [ ] **Step 5: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 6: Commit** + +```bash +git add plugins/working-process/rules/workflow.md +git commit -m "feat(working-process): record a reviewer's stop signal in the ledger" +``` + +--- + +### Task 10: The concurrency limit recovers its reasoning + +**Files:** +- Modify: `plugins/working-process/rules/workflow.md` — the "At most one live round" bullet under `## Dispatching a verdict agent` + +**Interfaces:** +- Consumes: nothing. +- Produces: nothing later tasks read. + +The ancestor design decided this and the shipped rule dropped it, so restoring it is errata. One sentence is genuinely new, because the ancestor ruled before the round sequence carried weight. + +- [ ] **Step 1: Write the failing check** + +```bash +f=plugins/working-process/rules/workflow.md +rg -Uc 'A\s+parallel\s+round\s+from\s+another\s+session\s+is\s+accepted\s+as\s+undetectable' "$f" +rg -Uc 'punches\s+a\s+hole\s+no\s+round\s+ever\s+read' "$f" +grep -c 'undetectable' "$f" +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: no output, no output, `1`. The single existing `undetectable` is the out-of-session-edit bullet three bullets below, which this task leaves alone. + +- [ ] **Step 3: Extend the bullet** + +Find: + +```markdown +- At most one live round per document per field within the session; + superseding a running round stops it when the platform offers a + stop, otherwise the stale result is relayed as stale and never + stamped. +``` + +Replace with: + +```markdown +- At most one live round per document per field within the session; + superseding a running round stops it when the platform offers a + stop, otherwise the stale result is relayed as stale and never + stamped. A parallel round from another session is accepted as + undetectable and stays benign: both rounds record in the body and the + field holds the later stamp. One consequence postdates that decision — + a diff-scoped LGTM certifies a chain, so an interleave punches a hole + no round ever read. The discharge paths are the mitigation, since an + audit and a full-document round each read the whole document, and a + heading-derived cap over-counts under interleave, which escalates + early. +``` + +- [ ] **Step 4: Run the check again** + +Expected after: `1`, `1`, `2`. + +- [ ] **Step 5: Validate** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 6: Commit** + +```bash +git add plugins/working-process/rules/workflow.md +git commit -m "fix(working-process): restore the concurrency limit's reasoning and name its one new consequence" +``` + +--- + +### Task 11: Backfill the live instance + +**Files:** +- Modify: `docs/specs/2026-08-27-audit-agents-design.md` — the round-3 heading and a new line in its `## Review rounds` section + +**Interfaces:** +- Consumes: the token from Task 3 and the body-edit licence from Task 4. + +**This task cannot run without the developer's ruling.** The backfill is the decline path exercised late, not a fourth path: no audit ran, no later full-document round was dispatched, and none ever will be, since the document is `implemented` and the work it designed has shipped. What remains is exactly what the decline path is — the developer looking at a chain nobody read whole and accepting it knowingly. Writing the token without that decision would put a false claim in the record: the annotation says a debt was discharged, and on this document no reading ever happened. + +- [ ] **Step 1: Ask the developer for the ruling** + +Put the question in one message: *the audit-agents spec reached `implemented` on a chain nobody read whole; do you accept that chain now, on the record, as the decline path exercised late?* Wait for the answer. A refusal ends this task and leaves the class with one permanent hit, which Task 13 then reports rather than hides. + +- [ ] **Step 2: Write the failing check** + +```bash +f=docs/specs/2026-08-27-audit-agents-design.md +grep -c '^### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped)$' "$f" +grep -c 'debt discharged' "$f" +grep -c 'ruling:' "$f" +``` + +- [ ] **Step 3: Run it and confirm the before-values** + +Expected before: `1`, `0`, `0`. + +- [ ] **Step 4: Annotate the heading** + +Find: + +```markdown +### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped) +``` + +Replace with (substituting the ruling's actual date for ``): + +```markdown +### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped), debt discharged +``` + +- [ ] **Step 5: Record the ruling in the ledger** + +Append to the same round's lines, after the two existing `fixed` lines: + +```markdown +- fixed — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: ; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged ` +``` + +The severity bracket is omitted because the sole authorizer is `ruling:` and no reviewer graded it — both legs hold, as the ledger's own rule requires. + +- [ ] **Step 6: Run the check again** + +Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), `1`. + +- [ ] **Step 7: Confirm the class no longer reports this document** + +```bash +rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ +``` + +Expected before this task: two lines. Expected after: one line — `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`, which Task 12 closes. + +- [ ] **Step 8: Commit** + +```bash +git add docs/specs/2026-08-27-audit-agents-design.md +git commit -m "docs: discharge the audit-agents spec's chain debt by recorded decline" +``` + +--- + +### Task 12: Discharge this package's own spec and re-stamp its hash + +**Files:** +- Modify: `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md` — the round-2 heading and the `integrity:` frontmatter field + +**Interfaces:** +- Consumes: the token from Task 3 and the ordering from Task 4. + +The spec is a second instance of its own subject: round 2 was diff-scoped and returned LGTM. Its debt was already discharged by the integrity audit at the consumption gate — the audit is one of the three paths — but the token that records it did not exist until Task 3 shipped. This task writes the annotation the audit earned, then re-stamps the hash, in exactly the order Task 4 prescribes. + +- [ ] **Step 1: Write the failing check** + +```bash +f=docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +grep -c '^### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped)$' "$f" +grep -n '^integrity:' "$f" +sed '1,/^---$/d' "$f" | shasum | cut -c1-7 +``` + +- [ ] **Step 2: Run it and confirm the before-values** + +Expected before: `1`; the `integrity:` line reads `integrity: 2026-09-07 (sha: 4a838b2)`; and the recomputed hash is `4a838b2`, matching the stamp. If the recomputed hash already differs, stop — the document changed since the audit, and the stamp must not be carried forward over an unaudited edit. + +- [ ] **Step 3: Annotate the heading** + +Find: + +```markdown +### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped) +``` + +Replace with: + +```markdown +### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped), debt discharged 2026-09-07 +``` + +- [ ] **Step 4: Recompute the hash** + +```bash +sed '1,/^---$/d' docs/specs/2026-09-07-diff-scoped-chain-debt-design.md | shasum | cut -c1-7 +``` + +Expected: a value other than `4a838b2`. Record it; the next step writes it. + +- [ ] **Step 5: Re-stamp the field** + +Replace `integrity: 2026-09-07 (sha: 4a838b2)` with `integrity: 2026-09-07 (sha: )`. + +- [ ] **Step 6: Verify stamp and body agree** + +```bash +f=docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +grep '^integrity:' "$f" +sed '1,/^---$/d' "$f" | shasum | cut -c1-7 +``` + +Expected: the hash in the field equals the recomputed hash. The stamp covers the text below the frontmatter, so writing the field never invalidates what it stamps. + +- [ ] **Step 7: Confirm the class reports nothing** + +```bash +rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ +``` + +Expected before this task: one line. Expected after: no output. Both live instances are now discharged, and the class ships without a permanent hit. + +- [ ] **Step 8: Commit** + +```bash +git add docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +git commit -m "docs: annotate this spec's discharged chain debt and re-stamp its integrity hash" +``` + +--- + +### Task 13: End-state sweep + +**Files:** +- none unless a check fails + +This task modifies nothing, so the before-and-after constraint does not apply to it: every check below is an end-state assertion, and the exemption is claimed here in words rather than inferred. Its purpose is to catch what a hand-written manifest cannot guarantee. The propagation gate is the real backstop, and Step 6 is where it runs. + +- [ ] **Step 1: The retired token survives nowhere in shipped content** + +```bash +rg -n --no-ignore 'chain accepted' plugins/ docs/domain/ +``` + +Expected: one line — `docs/domain/glossary.md`, the `_Avoid_` ban that names it. Design documents under `docs/specs/` and `docs/plans/` keep their historical occurrences and are out of scope: an archived document records what it recorded. + +- [ ] **Step 2: The new token appears in both rule files** + +```bash +grep -c 'debt discharged' plugins/working-process/rules/spec-plan-lifecycle.md +grep -c 'debt discharged' plugins/working-process/rules/workflow.md +``` + +Expected: `4` and `1`. The lifecycle rule's four are Task 3's definition sentence and heading example, Task 4's body-edit exception, and Task 6's anchor rewrite. A zero on either side means one of the two rule files was missed — the split-vocabulary failure the design names. + +- [ ] **Step 3: The Unfinished-work list has six entries and no accounting sentence** + +```bash +f=plugins/working-process/rules/spec-plan-lifecycle.md +grep -c '^- \*\*' "$f" +grep -c '^\s*- \*\*' "$f" +rg -Uc 'Four\s+of\s+the\s+five' "$f" +``` + +Expected: `6`, `6`, and no output. + +- [ ] **Step 4: Every published command in the list runs** + +Run each `rg` command the `## Unfinished-work list` section publishes, exactly as written, from the repo root. Expected: each exits without a usage error. Hits are read against each entry's scope, and the whole sweep should report no unfinished work — no `grilled: grilling`, no unresolved verdict, no open or held ledger line, no pending re-review, no misplaced stamp, and no chain debt. A hit that survives is reported to the developer rather than fixed here. + +- [ ] **Step 5: Validate the plugin** + +```bash +claude plugin validate . && claude plugin validate plugins/working-process +``` + +Expected: both pass. + +- [ ] **Step 6: Dispatch the propagation gate** + +Dispatch the `propagation-auditor` agent on the cheapest available family, named explicitly, over this branch's change set. The brief derives its own changed-interface list rather than receiving one: an earlier round in this series was handed a list of tokens to hunt, hunted exactly those, and returned CLEAN while missing an entire changed interface the brief had described only as context. Write the brief as positive scope — what to report — never as a prohibition. Fix confirmed hits under their own derivation and record each as a gate line under the last round heading of the document it concerns; dismiss a hit only in writing, with its counter-derivation. + +- [ ] **Step 7: Report and hand back** + +Report to the developer: what the sweep found, what the gate returned, whether the `propagation-auditor` reported its model, and any hit still outstanding. A missing self-report is expected rather than anomalous — the prescribed rung is already the cheapest family, so a silent substitution could only run the audit above tier, which does not invalidate a structural CLEAN. Then offer the plan-adversary round: `status` moves to `approved` on the developer's word, not this task's. + +--- + +## Open questions for the developer + +Three, batched rather than asked one at a time: + +1. **Task 11's ruling.** The audit-agents spec reached `implemented` on a chain nobody read whole. Do you accept that chain on the record now, as the decline path exercised late? Without it Task 11 does not run and the class ships with one permanent hit. +2. **Future undischarged instances.** Does a document found in this state later get the same retroactive decline, or does each one come back to you? The design left this open deliberately. +3. **`process-status` and the plan co-firing.** Should the skill say anything about a plan matching both Unresolved verdict and Chain debt, beyond what its matching already does? The design refuses suppression machinery; this asks only about reporting. From 4a858c695f9e05f8f0a110efcb1c10818d038a5b Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 12:51:51 +0200 Subject: [PATCH 088/126] docs: record the developer's rulings on the backfill and on completed work --- .../2026-09-07-diff-scoped-chain-debt.md | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index b68c393..67ad5e3 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -42,6 +42,10 @@ base: develop **Interfaces:** - Produces: the class name **Chain debt** and its published command. Tasks 2, 6, 11, 12 and 13 all cite one or the other. +The owner leg carries a second sentence the spec does not, and the departure is recorded here because it sits beside the text it concerns. The spec says a decline "has nothing to derive from, and there the debt correctly re-surfaces and the developer declines again" — true while it was written, when no standing decision existed. The developer ruled on 2026-09-07 that completed work is not chased, which makes the decline derivable for a document already at `status: implemented` and licenses a session to write the annotation without asking. The spec's sentence still governs every document in flight, where a decline remains a fresh decision. This is a developer ruling taken after the spec closed, so it outranks the plan's "the spec is the source" constraint rather than breaching it; the constraint bars the plan from inventing design, not the developer from deciding. + +The sentence lands on the **owner** leg, never on the scope leg. The spec refuses a `status` predicate in a class scope, because `process-status` states that a scope "narrows where a hit counts, never whether the file qualifies" — an owner leg says what the next move is and carries no such constraint. + - [ ] **Step 1: Write the failing check** ```bash @@ -68,7 +72,11 @@ Place it directly after the **Unfinished review-loop ledger** entry's `Owner:` l second entry to re-scope the default guard, for the reason the first one does, and carrying `-n` for the same reason. Owner: for a spec, the consumption gate's pair offer; for a plan, the - confirming full-document round. + confirming full-document round. On a document already at + `status: implemented` the debt is discharged by recorded decline + without any dispatch: completed work is not re-reviewed, so the + annotation is written citing that standing decision, and a document + still in flight keeps the pair offer. ``` - [ ] **Step 4: Run the check again** @@ -850,13 +858,9 @@ git commit -m "fix(working-process): restore the concurrency limit's reasoning a **Interfaces:** - Consumes: the token from Task 3 and the body-edit licence from Task 4. -**This task cannot run without the developer's ruling.** The backfill is the decline path exercised late, not a fourth path: no audit ran, no later full-document round was dispatched, and none ever will be, since the document is `implemented` and the work it designed has shipped. What remains is exactly what the decline path is — the developer looking at a chain nobody read whole and accepting it knowingly. Writing the token without that decision would put a false claim in the record: the annotation says a debt was discharged, and on this document no reading ever happened. - -- [ ] **Step 1: Ask the developer for the ruling** - -Put the question in one message: *the audit-agents spec reached `implemented` on a chain nobody read whole; do you accept that chain now, on the record, as the decline path exercised late?* Wait for the answer. A refusal ends this task and leaves the class with one permanent hit, which Task 13 then reports rather than hides. +**The developer's ruling is recorded and dated 2026-09-07** — see *Developer rulings* below. The backfill is the decline path exercised late, not a fourth path: no audit ran, no later full-document round was dispatched, and none ever will be, since the document is `implemented` and the work it designed has shipped. What remains is exactly what the decline path is — the developer looking at a chain nobody read whole and accepting it knowingly. Writing the token without that decision would have put a false claim in the record, since on this document no reading ever happened; the ruling is what makes the annotation true. -- [ ] **Step 2: Write the failing check** +- [ ] **Step 1: Write the failing check** ```bash f=docs/specs/2026-08-27-audit-agents-design.md @@ -865,11 +869,11 @@ grep -c 'debt discharged' "$f" grep -c 'ruling:' "$f" ``` -- [ ] **Step 3: Run it and confirm the before-values** +- [ ] **Step 2: Run it and confirm the before-values** Expected before: `1`, `0`, `0`. -- [ ] **Step 4: Annotate the heading** +- [ ] **Step 3: Annotate the heading** Find: @@ -883,21 +887,21 @@ Replace with (substituting the ruling's actual date for ``): ### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped), debt discharged ``` -- [ ] **Step 5: Record the ruling in the ledger** +- [ ] **Step 4: Record the ruling in the ledger** Append to the same round's lines, after the two existing `fixed` lines: ```markdown -- fixed — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: ; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged ` +- fixed — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: 2026-09-07; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged ` ``` -The severity bracket is omitted because the sole authorizer is `ruling:` and no reviewer graded it — both legs hold, as the ledger's own rule requires. +The two dates differ on purpose and the ledger requires both: the leading date is when this line reached its terminal state, `ruling:` is when the decision it cites was taken. The severity bracket is omitted because the sole authorizer is `ruling:` and no reviewer graded it — both legs hold, as the ledger's own rule requires. -- [ ] **Step 6: Run the check again** +- [ ] **Step 5: Run the check again** Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), `1`. -- [ ] **Step 7: Confirm the class no longer reports this document** +- [ ] **Step 6: Confirm the class no longer reports this document** ```bash rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ @@ -905,7 +909,7 @@ rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ Expected before this task: two lines. Expected after: one line — `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`, which Task 12 closes. -- [ ] **Step 8: Commit** +- [ ] **Step 7: Commit** ```bash git add docs/specs/2026-08-27-audit-agents-design.md @@ -1047,10 +1051,13 @@ Report to the developer: what the sweep found, what the gate returned, whether t --- -## Open questions for the developer +## Developer rulings + +The two questions the spec put to the developer, answered 2026-09-07. Both are recorded here rather than in the spec: the spec is audited and hash-stamped, so amending it would re-arm the stamp and break Task 12's precondition for no gain. The lifecycle rule already routes them here — held spec questions are asked before the plan is written. + +1. **The live instance is backfilled.** The developer accepts the audit-agents spec's chain on the record, as the decline path exercised late. Task 11 runs and cites `ruling: 2026-09-07`. +2. **Completed work is not chased.** A document found in this state later gets the same recorded decline without any dispatch — no audit, no confirming round. Task 1's owner leg carries this as a standing decision so a future session can cite it instead of re-asking; the paragraph under that task records how it departs from the spec's narrower sentence and why the departure is the developer's to make. A document still in flight keeps the pair offer, where a decline remains a fresh decision. -Three, batched rather than asked one at a time: +One question stays open and is put again in narrower form, since reading `process-status` showed the original was aimed at the wrong surface: -1. **Task 11's ruling.** The audit-agents spec reached `implemented` on a chain nobody read whole. Do you accept that chain on the record now, as the decline path exercised late? Without it Task 11 does not run and the class ships with one permanent hit. -2. **Future undischarged instances.** Does a document found in this state later get the same retroactive decline, or does each one come back to you? The design left this open deliberately. -3. **`process-status` and the plan co-firing.** Should the skill say anything about a plan matching both Unresolved verdict and Chain debt, beyond what its matching already does? The design refuses suppression machinery; this asks only about reporting. +3. **Whether the co-firing note is guaranteed to reach the report.** On a plan matching both Unresolved verdict and Chain debt, the skill groups hits by document and reports "the owner the entry carries", so Task 2's `one debt seen from two sides` explanation rides to the report on the owner leg it already copies — but the skill's report line is one line per hit, so a long leg may arrive condensed. Guaranteeing the note would need a skill edit; leaving it means two adjacent lines whose owners both name the confirming round. The recommendation is to leave it: a skill that correlates class pairs needs extending for every future pair, and two lines naming one remedy read as one job. From 9734977435794c0c14a93bcd9e890bb8bb8bc171 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 12:54:48 +0200 Subject: [PATCH 089/126] docs: rule out a process-status edit and close the plan's open questions --- docs/plans/2026-09-07-diff-scoped-chain-debt.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index 67ad5e3..b99e656 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -1053,11 +1053,9 @@ Report to the developer: what the sweep found, what the gate returned, whether t ## Developer rulings -The two questions the spec put to the developer, answered 2026-09-07. Both are recorded here rather than in the spec: the spec is audited and hash-stamped, so amending it would re-arm the stamp and break Task 12's precondition for no gain. The lifecycle rule already routes them here — held spec questions are asked before the plan is written. +The questions the spec put to the developer, all answered 2026-09-07. They are recorded here rather than in the spec: the spec is audited and hash-stamped, so amending it would re-arm the stamp and break Task 12's precondition for no gain. The lifecycle rule already routes them here — held spec questions are asked before the plan is written. 1. **The live instance is backfilled.** The developer accepts the audit-agents spec's chain on the record, as the decline path exercised late. Task 11 runs and cites `ruling: 2026-09-07`. 2. **Completed work is not chased.** A document found in this state later gets the same recorded decline without any dispatch — no audit, no confirming round. Task 1's owner leg carries this as a standing decision so a future session can cite it instead of re-asking; the paragraph under that task records how it departs from the spec's narrower sentence and why the departure is the developer's to make. A document still in flight keeps the pair offer, where a decline remains a fresh decision. -One question stays open and is put again in narrower form, since reading `process-status` showed the original was aimed at the wrong surface: - -3. **Whether the co-firing note is guaranteed to reach the report.** On a plan matching both Unresolved verdict and Chain debt, the skill groups hits by document and reports "the owner the entry carries", so Task 2's `one debt seen from two sides` explanation rides to the report on the owner leg it already copies — but the skill's report line is one line per hit, so a long leg may arrive condensed. Guaranteeing the note would need a skill edit; leaving it means two adjacent lines whose owners both name the confirming round. The recommendation is to leave it: a skill that correlates class pairs needs extending for every future pair, and two lines naming one remedy read as one job. +3. **`process-status` stays untouched.** The original question was aimed at the wrong surface: the skill groups hits by document and reports "the owner the entry carries", so Task 2's `one debt seen from two sides` explanation already rides to the report on the owner leg the skill copies. Whether a long leg arrives whole or condensed does not matter, because two adjacent lines whose owners both name the confirming round read as one job. The developer ruled on 2026-09-07 to leave the skill alone, so the spec's `No process-status edit at all` refusal now covers reporting as well as scope, and a skill that correlates class pairs — which would need extending for every future pair — is refused rather than deferred. From bcc123d8624ba3e1c6cb73e9f794f6d690290337 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 13:21:14 +0200 Subject: [PATCH 090/126] docs: stamp plan-adversary round one and apply its six licensed fixes --- .../2026-09-07-diff-scoped-chain-debt.md | 109 ++++++++++++++---- 1 file changed, 87 insertions(+), 22 deletions(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index b99e656..20bf5e4 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -2,6 +2,7 @@ ticket: none date: 2026-09-07 status: draft +adversary: blocking spec: ../specs/2026-09-07-diff-scoped-chain-debt-design.md branch: feature/audit-errata base: develop @@ -89,7 +90,11 @@ Expected after: `6`, `6`, `1`, `1`. Each pair must be equal; a divergence in the rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ ``` -Expected: exactly two lines, one from `docs/specs/2026-08-27-audit-agents-design.md` and one from `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`. Line numbers are not asserted — they move as the documents change, and asserting them would make this check fail for a reason it does not test. The command is copied into the rule verbatim, so this step proves the rule ships a command that runs. +Expected: **four** lines. Two are the live instances — one in `docs/specs/2026-08-27-audit-agents-design.md`, one in `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`. The other two come from this plan itself: Tasks 11 and 12 quote a round heading verbatim at column 0 inside a fenced block, and the command matches a line, not a document. Line numbers are not asserted — they move as the documents change. + +The plan's own two lines are output the class rejects, not hits it reports. The scope leg confines a hit to a `## Review rounds` section, and these sit under `### Task` headings; the default guard exists for exactly this reason, in the lifecycle rule's own words — a document quoting the convention describes it rather than instantiating it. So this step confirms two things at once: the rule ships a command that runs, and the scope leg earns its keep on the first document that tests it. + +Round 1 offered truncating the two `Find:` blocks so they stop matching, and that is declined here. The blocks must stay byte-exact to be executable, and a plan that mangled its own quotations to keep a grep quiet would be hiding the case the scope leg was written for. Restating the expected values is the repair; demonstrating the guard is the bonus. - [ ] **Step 6: Validate** @@ -186,15 +191,15 @@ git commit -m "fix(working-process): the Unresolved-verdict owner leg no longer ```bash f=plugins/working-process/rules/spec-plan-lifecycle.md -grep -c 'chain accepted' "$f" -grep -c 'debt discharged' "$f" +rg -Uc 'chain\s+accepted' "$f" +rg -Uc 'debt\s+discharged' "$f" grep -c '^ ### — architect, , LGTM (round 3, diff-scoped), debt discharged $' "$f" grep -c '^\s*### — architect, , LGTM (round 3, diff-scoped), debt discharged $' "$f" ``` - [ ] **Step 2: Run it and confirm the before-values** -Expected before: `1`, `0`, `0`, `0`. The last two must be equal. +Expected before: `1`, no output, `0`, `0`. The two token counts run under `rg -c`, which prints nothing rather than `0` on no match; the two anchored counts run under `grep -c`, which does print `0`. The last two must be equal. - [ ] **Step 3: Replace the paragraph** @@ -247,7 +252,7 @@ the debt correctly re-surfaces and the developer declines again. - [ ] **Step 4: Run the check again** -Expected after: `0`, `2`, `1`, `1`. The `debt discharged` count of `2` covers the definition sentence and the heading example — the three-path paragraph says "discharge the debt" rather than repeating the token, so it does not add to the count. Tasks 4 and 6 each add one more occurrence to this file, which is why Task 13 expects `4` here rather than `2`. The last two must be equal. +Expected after: no output, `2`, `1`, `1`. The `debt discharged` count of `2` covers the definition sentence and the heading example — the three-path paragraph says "discharge the debt" rather than repeating the token, so it does not add to the count. Tasks 4 and 6 each add one more occurrence to this file, which is why Task 13 expects `4` here rather than `2`. The last two must be equal. - [ ] **Step 5: Validate** @@ -373,9 +378,19 @@ Expected before: `0`, `0`, and no output. The first two must be equal. - [ ] **Step 3: Insert the paragraph** -Place it after "A lint over the section reads the anchored lines and ignores the prose." and before the `### Gate lines` heading: +Find: + +```markdown +ignores the prose. + +### Gate lines +``` + +Replace with: ```markdown +ignores the prose. + A reviewer's stop signal takes a line of its own, under the heading of the round that gave it: @@ -386,8 +401,15 @@ the next round's marginal value is not a finding — and no authorizer, since nobody licensed it. It joins no anchor: a stop signal owes nobody a next move, so it is closed the moment it is written, as a gate line is. The workflow rule owns the ask that produces it. + +### Gate lines ``` +The `Find:` block spans the sentence's real line break and carries the +`### Gate lines` heading along, so the `Replace with:` block restores +that heading at the end. Quoting the sentence on one line would match +nothing: the file wraps it after "and". + - [ ] **Step 4: Run the check again** Expected after: `1`, `1`, `1`. The first two must be equal; a divergence means the block sits at the wrong indent. @@ -540,8 +562,8 @@ This is the second and last site of the retired token. It narrates the same mech ```bash f=plugins/working-process/rules/workflow.md -grep -c 'chain accepted' "$f" -grep -c 'debt discharged' "$f" +rg -Uc 'chain\s+accepted' "$f" +rg -Uc 'debt\s+discharged' "$f" rg -Uc 'the\s+acceptance\s+is\s+recorded\s+rather\s+than\s+remembered' "$f" rg -Uc 'The\s+confirming-round\s+arm\s+therefore\s+blocks\s+plan-writing' "$f" rg -Uc 'runs\s+under\s+the\s+loop.s\s+standing\s+consent' "$f" @@ -549,7 +571,7 @@ rg -Uc 'runs\s+under\s+the\s+loop.s\s+standing\s+consent' "$f" - [ ] **Step 2: Run it and confirm the before-values** -Expected before: `1`, `0`, `1`, then no output twice. +Expected before: `1`, then no output, then `1`, then no output twice. Both token counts run under `rg -c`, so the absent one prints nothing rather than `0`. - [ ] **Step 3: Replace both paragraphs** @@ -615,12 +637,12 @@ whatever the frontmatter says. - [ ] **Step 4: Run the check again** -Expected after: `0`, `1`, no output, `1`, `1`. +Expected after: no output, `1`, no output, `1`, `1`. - [ ] **Step 5: Confirm the retired token is gone from the whole repo's rule payload** ```bash -rg -n --no-ignore 'chain accepted' plugins/ +rg -Un --no-ignore 'chain\s+accepted' plugins/ ``` Expected: no output. Before this task the lifecycle rule's occurrence was already removed by Task 3, so this step's before-value is one line (`workflow.md`) and its after-value is none. @@ -865,13 +887,14 @@ git commit -m "fix(working-process): restore the concurrency limit's reasoning a ```bash f=docs/specs/2026-08-27-audit-agents-design.md grep -c '^### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped)$' "$f" -grep -c 'debt discharged' "$f" +rg -Uc 'debt\s+discharged' "$f" grep -c 'ruling:' "$f" +grep -c '' "$f" ``` - [ ] **Step 2: Run it and confirm the before-values** -Expected before: `1`, `0`, `0`. +Expected before: `1`, no output (`rg -c` prints nothing on no match), `0`, `0`. - [ ] **Step 3: Annotate the heading** @@ -889,7 +912,7 @@ Replace with (substituting the ruling's actual date for ``): - [ ] **Step 4: Record the ruling in the ledger** -Append to the same round's lines, after the two existing `fixed` lines: +Append to the same round's lines, after the two existing `fixed` lines, **substituting the implementation date for both occurrences of ``** — the same substitution Step 3 makes, and the literal placeholder must not survive: ```markdown - fixed — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: 2026-09-07; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged ` @@ -899,7 +922,7 @@ The two dates differ on purpose and the ledger requires both: the leading date i - [ ] **Step 5: Run the check again** -Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), `1`. +Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), `1`, and `0` — the last is the one that distinguishes a correct edit from a placeholder left in place. Without it every other value here is identical whether the dates were substituted or not, which is the fault the plan's own constraint on before-and-after values names. - [ ] **Step 6: Confirm the class no longer reports this document** @@ -907,7 +930,7 @@ Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), ` rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ ``` -Expected before this task: two lines. Expected after: one line — `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`, which Task 12 closes. +Expected before this task: four lines. Expected after: three — the annotated heading drops out, leaving `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`, which Task 12 closes, and this plan's own two quoted blocks, which the class's scope leg rejects. - [ ] **Step 7: Commit** @@ -983,7 +1006,9 @@ Expected: the hash in the field equals the recomputed hash. The stamp covers the rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ ``` -Expected before this task: one line. Expected after: no output. Both live instances are now discharged, and the class ships without a permanent hit. +Expected before this task: three lines. Expected after: **two** — this plan's own quoted blocks in Tasks 11 and 12, which sit outside any `## Review rounds` section and which the class's scope leg therefore rejects. + +Both live instances are now discharged, so the class ships with no permanent **hit**. It does not ship with no permanent command *output*, and the difference is the whole point of the scope leg: a command returns lines, and confirmation turns a line into a hit. An earlier draft of this step claimed no permanent hit by asserting no output, which conflated the two. - [ ] **Step 8: Commit** @@ -1004,7 +1029,7 @@ This task modifies nothing, so the before-and-after constraint does not apply to - [ ] **Step 1: The retired token survives nowhere in shipped content** ```bash -rg -n --no-ignore 'chain accepted' plugins/ docs/domain/ +rg -Un --no-ignore 'chain\s+accepted' plugins/ docs/domain/ ``` Expected: one line — `docs/domain/glossary.md`, the `_Avoid_` ban that names it. Design documents under `docs/specs/` and `docs/plans/` keep their historical occurrences and are out of scope: an archived document records what it recorded. @@ -1012,8 +1037,8 @@ Expected: one line — `docs/domain/glossary.md`, the `_Avoid_` ban that names i - [ ] **Step 2: The new token appears in both rule files** ```bash -grep -c 'debt discharged' plugins/working-process/rules/spec-plan-lifecycle.md -grep -c 'debt discharged' plugins/working-process/rules/workflow.md +rg -Uc 'debt\s+discharged' plugins/working-process/rules/spec-plan-lifecycle.md +rg -Uc 'debt\s+discharged' plugins/working-process/rules/workflow.md ``` Expected: `4` and `1`. The lifecycle rule's four are Task 3's definition sentence and heading example, Task 4's body-edit exception, and Task 6's anchor rewrite. A zero on either side means one of the two rule files was missed — the split-vocabulary failure the design names. @@ -1031,7 +1056,15 @@ Expected: `6`, `6`, and no output. - [ ] **Step 4: Every published command in the list runs** -Run each `rg` command the `## Unfinished-work list` section publishes, exactly as written, from the repo root. Expected: each exits without a usage error. Hits are read against each entry's scope, and the whole sweep should report no unfinished work — no `grilled: grilling`, no unresolved verdict, no open or held ledger line, no pending re-review, no misplaced stamp, and no chain debt. A hit that survives is reported to the developer rather than fixed here. +Run each `rg` command the `## Unfinished-work list` section publishes, exactly as written, from the repo root. Expected: each exits without a usage error. Hits are read against each entry's scope, and the whole sweep should report no unfinished work — no `grilled: grilling`, no open or held ledger line, no pending re-review, and no misplaced stamp. + +Two classes need a word, because this plan is itself a document the sweep reads. + +**Chain debt on this plan.** A plan's loop terminates on a diff-scoped LGTM followed by a confirming full-document round, so by the time this task runs, this plan's own `## Review rounds` section may hold a diff-scoped LGTM heading. That is a real hit, not noise, and it is **discharged here rather than held**: a later full-document heading is on the page, and Task 3's own text says the annotation's derivation licenses a later session to write it. Annotate the heading, citing the confirming round. The two lines Tasks 11 and 12 quote inside fenced blocks are a different matter and stay — they sit outside any `## Review rounds` section and the scope leg rejects them. + +**Unresolved verdict on this plan.** A `blocking` or `concerns` round closed by annotation rather than by a fresh round leaves the field matching until the annotation lands. Read the field, and if a round's disposition is still open, that is unfinished work the developer owns rather than something this task closes. + +Any other hit that survives is reported to the developer rather than fixed here. - [ ] **Step 5: Validate the plugin** @@ -1047,7 +1080,9 @@ Dispatch the `propagation-auditor` agent on the cheapest available family, named - [ ] **Step 7: Report and hand back** -Report to the developer: what the sweep found, what the gate returned, whether the `propagation-auditor` reported its model, and any hit still outstanding. A missing self-report is expected rather than anomalous — the prescribed rung is already the cheapest family, so a silent substitution could only run the audit above tier, which does not invalidate a structural CLEAN. Then offer the plan-adversary round: `status` moves to `approved` on the developer's word, not this task's. +Report to the developer: what the sweep found, what the gate returned, whether the `propagation-auditor` reported its model, and any hit still outstanding. + +Report one thing more, which no earlier step covers: **the installed rule copies under `.claude/rules/working-process/` now drift.** They are a consumer of every sentence this plan rewrote — both carry the retired token today — and no task edits them, because a Rules payload is distributed by the `sync-rules` engine rather than by hand. Offer that run. The drift hook is the designed backstop, which is why this is a hand-back line rather than a task; leaving it unsaid would let the session's own rules stay a version behind the ones it just shipped. A missing self-report is expected rather than anomalous — the prescribed rung is already the cheapest family, so a silent substitution could only run the audit above tier, which does not invalidate a structural CLEAN. Then offer the plan-adversary round: `status` moves to `approved` on the developer's word, not this task's. --- @@ -1059,3 +1094,33 @@ The questions the spec put to the developer, all answered 2026-09-07. They are r 2. **Completed work is not chased.** A document found in this state later gets the same recorded decline without any dispatch — no audit, no confirming round. Task 1's owner leg carries this as a standing decision so a future session can cite it instead of re-asking; the paragraph under that task records how it departs from the spec's narrower sentence and why the departure is the developer's to make. A document still in flight keeps the pair offer, where a decline remains a fresh decision. 3. **`process-status` stays untouched.** The original question was aimed at the wrong surface: the skill groups hits by document and reports "the owner the entry carries", so Task 2's `one debt seen from two sides` explanation already rides to the report on the owner leg the skill copies. Whether a long leg arrives whole or condensed does not matter, because two adjacent lines whose owners both name the confirming round read as one job. The developer ruled on 2026-09-07 to leave the skill alone, so the spec's `No process-status edit at all` refusal now covers reporting as well as scope, and a skill that correlates class pairs — which would need extending for every future pair — is refused rather than deferred. + +## Review rounds + +### 2026-09-07 — plan-adversary, fable 5, blocking (round 1, full-document) + +- fixed 2026-09-07 — [Important] three verification steps publish false expected values, because the plan's own `Find:` blocks instantiate the anchor they verify: the published Chain-debt command returns four lines today, not two; license: the plan's own constraint that a check must return a stated value, plus the recomputation itself, which a recounted counter licenses; the three steps now state four, four-to-three and three-to-two, and each says why the plan's own two lines are output the scope leg rejects rather than hits; deviation: Task 1 Step 5, where the reviewer's alternative of truncating the `Find:` blocks is declined and the reason stated beside the text it concerns +- fixed 2026-09-07 — [Important] Task 11's ledger block carries literal `` placeholders with no substitution instruction, and every check in the task passes with them left in; license: the plan's own constraint that a check whose value cannot distinguish the two states verifies nothing, plus the substitution instruction Step 3 already carries, whose absence in Step 4 was the asymmetry; Step 4 now demands the substitution for both occurrences and Step 1 gains `grep -c ''`, expected `0` after, which is the one value a surviving placeholder changes +- fixed 2026-09-07 — [Minor] Task 5's placement anchor quotes a sentence that straddles a line wrap in the target file, so a single-line search for it returns nothing; license: the plan's own unconditional rule about wrapped prose, which the one task shipping no `Find:` block had escaped; Task 5 now carries a `Find:`/`Replace with:` pair anchored on the real line break plus the `### Gate lines` heading, verified unique and byte-exact +- fixed 2026-09-07 — [Minor] the token counts use single-line `grep -c`, against the plan's own unconditional rule that a prose search puts `\s+` between every pair of words; license: that constraint, which renounces exactly the reasoning that made these harmless — that every occurrence happens to be pinned inside a prescribed block; all seven sites now run `rg -Uc 'debt\s+discharged'` and `rg -Uc 'chain\s+accepted'`, and the four expectation lines they feed are restated for `rg -c` printing nothing where `grep -c` printed `0` +- fixed 2026-09-07 — [Minor] Task 13's expected-clean sweep can trip on this plan's own ledger once its loop closes on a diff-scoped LGTM, and the plan neither predicts the hit nor says which instruction wins; license: Task 3's own text that the annotation's derivation licenses a later session to write it, which settles the conflict without a new decision; Step 4 now names both self-referential classes, discharges the chain-debt hit under that derivation, and separates it from the two quoted blocks the scope leg rejects +- fixed 2026-09-07 — [Minor] the installed rule copies under `.claude/rules/working-process/` consume every changed sentence and no task names them; license: the plan's own consumer-enumeration duty, plus the sync-rules engine owning every Rules-payload write, which is why the repair is a hand-back offer and not a task that edits them; Task 13 Step 7 now reports the drift and offers the run + +The reviewer's stop signal is recorded below in the line shape Task 5 +ships. Writing it before that task lands dogfoods the shape rather than +minting an undefined one: the live grammar does not yet admit the line, +so until it does this record doubles as narrative prose, which the +section already permits. + +- signal 2026-09-07 — one short diff-scoped round over the two Important fixes earns its cost, since the first fix touches `Find:` blocks three tasks depend on; a fresh full-document round would not repay itself, and the four Minors touch neither the design, the token, nor the derivations + +Answering the round's focusing question — whether the plan avoided +mistaking the manifest for the proof or merely wrote the warning down — +the reviewer split the verdict, and the split is worth keeping. The +edit-site half held: every `Find:` block byte-matches its target, both +retired-token sites are covered, and Task 13 dispatches the propagation +gate with a derive-your-own-scope brief. The check half did not: the +four-line output behind the first Important was observable at authoring +time by running the plan's own flagship command over two documents the +plan itself edits. So the manifest is not mistaken for the proof — the +expected check outputs are. From 6655b1cf9593fa7acdab6da37f635e969027b191 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 19:50:35 +0200 Subject: [PATCH 091/126] docs: stamp plan-adversary round two and make the class counts contingency-aware --- .../2026-09-07-diff-scoped-chain-debt.md | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index 20bf5e4..86e0d7e 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -2,7 +2,7 @@ ticket: none date: 2026-09-07 status: draft -adversary: blocking +adversary: concerns spec: ../specs/2026-09-07-diff-scoped-chain-debt-design.md branch: feature/audit-errata base: develop @@ -90,7 +90,13 @@ Expected after: `6`, `6`, `1`, `1`. Each pair must be equal; a divergence in the rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ ``` -Expected: **four** lines. Two are the live instances — one in `docs/specs/2026-08-27-audit-agents-design.md`, one in `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`. The other two come from this plan itself: Tasks 11 and 12 quote a round heading verbatim at column 0 inside a fenced block, and the command matches a line, not a document. Line numbers are not asserted — they move as the documents change. +Expected: **four lines, plus one** if this plan's own ledger already holds a diff-scoped `LGTM` heading that nothing has annotated. + +The fixed four are two live instances — one in `docs/specs/2026-08-27-audit-agents-design.md`, one in `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md` — and two from this plan itself, where Tasks 11 and 12 quote a round heading verbatim at column 0 inside a fenced block, because the command matches a line, not a document. + +The contingent fifth is this plan's own review loop reaching its terminating shape: a plan's loop ends on a diff-scoped `LGTM` followed by a confirming full-document round, and the rules that would annotate that heading are what this plan ships. So between the loop closing and Task 3 landing, the heading sits unannotated. Task 13 Step 4 owns it and explains why it is a real hit discharged there rather than noise — unlike the two quoted blocks, it sits inside a genuine `## Review rounds` section and the scope leg does not reject it. + +Line numbers are not asserted — they move as the documents change. The plan's own two lines are output the class rejects, not hits it reports. The scope leg confines a hit to a `## Review rounds` section, and these sit under `### Task` headings; the default guard exists for exactly this reason, in the lifecycle rule's own words — a document quoting the convention describes it rather than instantiating it. So this step confirms two things at once: the rule ships a command that runs, and the scope leg earns its keep on the first document that tests it. @@ -930,7 +936,7 @@ Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), ` rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ ``` -Expected before this task: four lines. Expected after: three — the annotated heading drops out, leaving `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`, which Task 12 closes, and this plan's own two quoted blocks, which the class's scope leg rejects. +Expected: one line fewer than Task 1 Step 5 returned — four dropping to three, or five dropping to four where this plan's own unannotated LGTM heading is present, which that step explains. The annotated heading drops out, leaving `docs/specs/2026-09-07-diff-scoped-chain-debt-design.md`, which Task 12 closes, plus this plan's own two quoted blocks, which the scope leg rejects, plus that contingent heading if it exists. - [ ] **Step 7: Commit** @@ -1006,10 +1012,12 @@ Expected: the hash in the field equals the recomputed hash. The stamp covers the rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/ ``` -Expected before this task: three lines. Expected after: **two** — this plan's own quoted blocks in Tasks 11 and 12, which sit outside any `## Review rounds` section and which the class's scope leg therefore rejects. +Expected: one line fewer than Task 11 Step 6 returned — three dropping to **two**, or four dropping to three where this plan's own unannotated LGTM heading is present. The two that always remain are this plan's quoted blocks in Tasks 11 and 12, which sit outside any `## Review rounds` section and which the scope leg therefore rejects. Both live instances are now discharged, so the class ships with no permanent **hit**. It does not ship with no permanent command *output*, and the difference is the whole point of the scope leg: a command returns lines, and confirmation turns a line into a hit. An earlier draft of this step claimed no permanent hit by asserting no output, which conflated the two. +This plan's own contingent heading is a real hit rather than rejected output, and it is not this task's to close — Task 13 Step 4 discharges it under the derivation licence, after every rule edit has landed. + - [ ] **Step 8: Commit** ```bash @@ -1060,7 +1068,11 @@ Run each `rg` command the `## Unfinished-work list` section publishes, exactly a Two classes need a word, because this plan is itself a document the sweep reads. -**Chain debt on this plan.** A plan's loop terminates on a diff-scoped LGTM followed by a confirming full-document round, so by the time this task runs, this plan's own `## Review rounds` section may hold a diff-scoped LGTM heading. That is a real hit, not noise, and it is **discharged here rather than held**: a later full-document heading is on the page, and Task 3's own text says the annotation's derivation licenses a later session to write it. Annotate the heading, citing the confirming round. The two lines Tasks 11 and 12 quote inside fenced blocks are a different matter and stay — they sit outside any `## Review rounds` section and the scope leg rejects them. +**Chain debt on this plan.** A plan's loop terminates on a diff-scoped LGTM followed by a confirming full-document round, so by the time this task runs, this plan's own `## Review rounds` section may hold a diff-scoped LGTM heading. That is a real hit, not noise, and it is **discharged here rather than held**: a later full-document heading is on the page, and Task 3's own text says the annotation's derivation licenses a later session to write it. + +Append the bare `, debt discharged ` token to that heading, and nothing else. The confirming round's heading is what licenses the write, so it belongs in the session's derivation — never inside the token, which Task 3 rules "carries a date and nothing else" precisely so one fact gets no second home. + +The two lines Tasks 11 and 12 quote inside fenced blocks are a different matter and stay — they sit outside any `## Review rounds` section and the scope leg rejects them. **Unresolved verdict on this plan.** A `blocking` or `concerns` round closed by annotation rather than by a fresh round leaves the field matching until the annotation lands. Read the field, and if a round's disposition is still open, that is unfinished work the developer owns rather than something this task closes. @@ -1097,6 +1109,28 @@ The questions the spec put to the developer, all answered 2026-09-07. They are r ## Review rounds +### 2026-09-07 — plan-adversary, fable 5, concerns (round 2, diff-scoped) + +- fixed 2026-09-07 — [Important] fix 1's restated counts are right for today's tree and wrong for the tree the plan predicts at execution time: this plan's own loop terminates on a diff-scoped LGTM, that heading lands inside a real `## Review rounds` section where the scope leg does not reject it, and the rules that would annotate it ship during this very plan — so the three steps state absolutes that Task 13 Step 4 already contradicts in words; license: the plan's own constraint that a check must state the value it returns, plus Task 13 Step 4's written prediction of this exact ledger state, which makes the correction a recomputation rather than a decision; the three steps now state a fixed base plus one contingent line, each pointing at Task 13 Step 4 for why that line is a real hit discharged there +- fixed 2026-09-07 — [Minor] fix 5's "annotate the heading, citing the confirming round" reads as licensing a path clause inside the token, which Task 3's shipped grammar forbids — the token "carries a date and nothing else" precisely so one fact gets no second home; license: that sentence of Task 3; the instruction now names the bare token and puts the confirming round's heading where it belongs, in the session's derivation rather than in the annotation + +The reviewer ran every published before-value against the live tree and +reports them all verifying, which is the property round 1 found missing. +It also declined to refute the recorded deviation on fix 1: truncating +the `Find:` blocks would trade executability for a quiet grep and hide +the case the scope leg exists for. + +- signal 2026-09-07 — a dedicated round 3 would not repay itself: the Important's repair is one contingency sentence restated in three steps, self-licensed and verifiable by inspection, and the confirming full-document round this plan is owed regardless can absorb that check + +Answering the round's focusing question — whether the fix wave repaired +the habit or only its six instances — the answer narrowed rather than +flipped. Simulation now happens: every restated value verifies against +the live tree, which round 1's did not. But it was run against the +authoring-time tree while the plan itself describes the execution-time +state that breaks three of those counts. So the failure moved from +"never ran the command" to "ran it at the wrong timepoint", and forward +simulation is the half still owed. + ### 2026-09-07 — plan-adversary, fable 5, blocking (round 1, full-document) - fixed 2026-09-07 — [Important] three verification steps publish false expected values, because the plan's own `Find:` blocks instantiate the anchor they verify: the published Chain-debt command returns four lines today, not two; license: the plan's own constraint that a check must return a stated value, plus the recomputation itself, which a recounted counter licenses; the three steps now state four, four-to-three and three-to-two, and each says why the plan's own two lines are output the scope leg rejects rather than hits; deviation: Task 1 Step 5, where the reviewer's alternative of truncating the `Find:` blocks is declined and the reason stated beside the text it concerns From 2d5c5f8e0375af0af5dee2f041ab22fb301ae153 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:18:31 +0200 Subject: [PATCH 092/126] docs: stamp the confirming round and apply its six licensed fixes --- .../2026-09-07-diff-scoped-chain-debt.md | 112 +++++++++++++++--- 1 file changed, 97 insertions(+), 15 deletions(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index 86e0d7e..3b298f3 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -14,7 +14,7 @@ base: develop **Goal:** Give the review loop a durable record that a diff-scoped LGTM's chain debt was discharged — a sixth Unfinished-work class that surfaces the debt, a three-path `, debt discharged ` annotation that closes it, and the four rule corrections the new class exposes. -**Architecture:** Two rule files change and two specs gain a ledger annotation. `spec-plan-lifecycle.md` owns the record — the new class, the annotation's grammar, the ordering against the `integrity:` hash, the Unresolved-verdict owner leg, the stop-signal line shape, and three census sentences rewritten count-free. `workflow.md` owns the loop's behaviour — the gate's pair offer, the confirming round's authority, the instruction to record a stop signal, and the restored concurrency reasoning. The split follows the two rules' existing division of labour; no sentence moves between them. +**Architecture:** Two rule files change, the glossary gains one clause, and two specs gain a ledger annotation. `spec-plan-lifecycle.md` owns the record — the new class, the annotation's grammar, the ordering against the `integrity:` hash, the Unresolved-verdict owner leg, the stop-signal line shape, and three census sentences rewritten count-free. `workflow.md` owns the loop's behaviour — the gate's pair offer, the confirming round's authority, the instruction to record a stop signal, and the restored concurrency reasoning. The split follows the two rules' existing division of labour; no sentence moves between them. **Tech Stack:** Markdown rule files distributed as a Rules payload; `rg` and `grep` commands published inside the rules are the enforcement mechanism; `claude plugin validate` is the structural check. @@ -31,7 +31,7 @@ base: develop - **A check that searches for prose uses `rg -U` and puts `\s+` between *every* pair of words in the pattern; a check that searches for an anchored structural pattern uses `grep`.** These files wrap prose at about 72 characters, so a searched phrase may straddle a line ending and a single-line `grep` then returns 0 where the phrase is plainly present. The constraint is unconditional rather than applied where a wrap looks likely: where the wrap falls is not something a reader reliably predicts, and a uniformly `\s+` pattern is correct whether or not it wraps, so no judgement is exercised and no instance can be missed. An anchored pattern like `^- \*\*Chain debt\*\*` or `^ - signal ` cannot straddle by construction, so single-line matching is correct there. - **`rg -c` prints nothing and exits 1 when its pattern does not match** — it never prints `0`. A step asserting absence with `rg` therefore expects *no output*; only `grep -c`, which does print `0`, is given a numeric zero expectation. - **An anchored check on an indented block publishes *both* anchors — exact and tolerant — and asserts their equality.** Never one alone, and never a per-site decision about which. The exact anchor (`^ ` for a grammar block, `^- ` for a list entry) proves the prescribed text is well-formed at the indent the step prescribes; the tolerant anchor (`^\s*`) proves no variant survives anywhere else. Each alone has a blind spot that reads as success: the exact one passes while a leftover sits at another indent, the tolerant one passes while the prescribed block is mis-indented. Equality of the two counts is the assertion, and a divergence localizes which half failed. One case is copied rather than reasoned about: a check mirroring a command the rules publish reproduces it verbatim. -- **Every check that verifies an edit must return a different value before and after its step, and both values are stated.** A check whose before-value equals its after-value verifies nothing, however correct both numbers look — and it survives review precisely because nothing about it appears wrong. A check that verifies no edit is exempt only where its own step says so in words; Task 13 is the sole exempt task here, and its `Files:` line says it modifies nothing. +- **Every check that verifies an edit must return a different value before and after its step, and both values are stated.** A check whose before-value equals its after-value verifies nothing, however correct both numbers look — and it survives review precisely because nothing about it appears wrong. A check that asserts an **invariant** rather than verifying an edit is exempt, and the exemption is claimed in words on the step rather than inferred by a later reader: Task 9's paired anchors stay at zero to prove a shape was cited rather than copied, Task 11's placeholder guard stays at zero to prove no `` survived, and every check in Task 13 reports an end state. Each says so where it stands. --- @@ -47,6 +47,10 @@ The owner leg carries a second sentence the spec does not, and the departure is The sentence lands on the **owner** leg, never on the scope leg. The spec refuses a `status` predicate in a class scope, because `process-status` states that a scope "narrows where a hit counts, never whether the file qualifies" — an owner leg says what the next move is and carries no such constraint. +The scope leg carries one addition too, smaller and licensed differently: `and carrying -n for the same reason`. The spec's block ends at "for the reason the first one does", but the command the spec itself prescribes carries `-n`, and the sibling entry already explains why — confirming section membership needs line positions. So the clause states what the spec's own command implies rather than adding a decision. It is recorded here because the task's other addition is, and an undocumented departure beside a documented one reads as an oversight. + +This task also touches `docs/domain/glossary.md`, which the spec's Changes-by-file section says no implementation task covers. That sentence scopes the six changes the grilling session applied inline; developer ruling 2 postdates it and opens a seventh, recorded in Step 8. + - [ ] **Step 1: Write the failing check** ```bash @@ -110,10 +114,40 @@ claude plugin validate . && claude plugin validate plugins/working-process Expected: both pass. -- [ ] **Step 7: Commit** +- [ ] **Step 7: Widen the glossary's third discharge path** + +The entry enumerates that path as "the developer's recorded decline of the gate's pair offer". On an implemented document the gate never fired, so there is no pair offer to decline — yet ruling 2 licenses exactly that discharge, and the owner leg now ships it. The enumeration must cover what the rule permits. + +Find: + +```markdown +full-document round whatever its verdict, or the developer's recorded +decline of the gate's pair offer. Recorded as `, debt discharged ` +``` + +Replace with: + +```markdown +full-document round whatever its verdict, or the developer's recorded +decline — of the gate's pair offer, or, where the document is already +implemented and the gate never fired, of the question that offer would +have put. Recorded as `, debt discharged ` +``` + +- [ ] **Step 8: Verify the glossary edit** ```bash -git add plugins/working-process/rules/spec-plan-lifecycle.md +g=docs/domain/glossary.md +rg -Uc "decline\s+of\s+the\s+gate's\s+pair\s+offer\." "$g" +rg -Uc 'the\s+gate\s+never\s+fired' "$g" +``` + +Expected before: `1`, then no output. Expected after: no output, then `1`. + +- [ ] **Step 9: Commit** + +```bash +git add plugins/working-process/rules/spec-plan-lifecycle.md docs/domain/glossary.md git commit -m "feat(working-process): add the Chain debt Unfinished-work class" ``` @@ -787,7 +821,7 @@ records a deviation from a reviewer's suggestion, - [ ] **Step 4: Run the check again** -Expected after: `1`, then `0` and `0` — unchanged, proving the shape was cited rather than copied. +Expected after: `1`, then `0` and `0` — unchanged. **These two assert an invariant rather than verify an edit**, which is what exempts them from the before-and-after rule: they prove the shape stayed in the lifecycle rule and was cited here rather than copied. - [ ] **Step 5: Validate** @@ -886,6 +920,8 @@ git commit -m "fix(working-process): restore the concurrency limit's reasoning a **Interfaces:** - Consumes: the token from Task 3 and the body-edit licence from Task 4. +**The token's date is the discharge event's date, everywhere in this plan.** The spec rules that the annotation "names an event — this heading's debt was discharged on that date", so the date answers *when the discharge happened*, never when the edit was typed. On this document the discharge is the developer's decline, so the token reads `, debt discharged 2026-09-07` whatever day implementation lands. Task 12 resolves it the same way against its audit, and Task 13's contingent annotation against its confirming round. A ledger line's own leading date is a different date under a different rule — the ledger's — and the two are distinguished in Step 4. + **The developer's ruling is recorded and dated 2026-09-07** — see *Developer rulings* below. The backfill is the decline path exercised late, not a fourth path: no audit ran, no later full-document round was dispatched, and none ever will be, since the document is `implemented` and the work it designed has shipped. What remains is exactly what the decline path is — the developer looking at a chain nobody read whole and accepting it knowingly. Writing the token without that decision would have put a false claim in the record, since on this document no reading ever happened; the ruling is what makes the annotation true. - [ ] **Step 1: Write the failing check** @@ -910,25 +946,27 @@ Find: ### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped) ``` -Replace with (substituting the ruling's actual date for ``): +Replace with: ```markdown -### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped), debt discharged +### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped), debt discharged 2026-09-07 ``` +The date is the ruling's, not the implementation's, for the reason this task's preamble gives. + - [ ] **Step 4: Record the ruling in the ledger** -Append to the same round's lines, after the two existing `fixed` lines, **substituting the implementation date for both occurrences of ``** — the same substitution Step 3 makes, and the literal placeholder must not survive: +Append to the same round's lines, after the two existing `fixed` lines. **Two dates appear and they are not the same date.** The leading `` is the implementation date — when this line reached its terminal state, under the ledger's rule. The date inside the quoted token is `2026-09-07`, because it quotes what Step 3 wrote on the heading and the token records the discharge event. No literal `` may survive: ```markdown -- fixed — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: 2026-09-07; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged ` +- fixed — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: 2026-09-07; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged 2026-09-07` ``` -The two dates differ on purpose and the ledger requires both: the leading date is when this line reached its terminal state, `ruling:` is when the decision it cites was taken. The severity bracket is omitted because the sole authorizer is `ruling:` and no reviewer graded it — both legs hold, as the ledger's own rule requires. +Three dates therefore sit on this one line, each under its own rule: the leading date is the ledger's, `ruling:` is when the developer decided, and the quoted token's is the discharge event's. The ledger requires the first two even where they coincide. The severity bracket is omitted because the sole authorizer is `ruling:` and no reviewer graded it — both legs hold, as the ledger's own rule requires. - [ ] **Step 5: Run the check again** -Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), `1`, and `0` — the last is the one that distinguishes a correct edit from a placeholder left in place. Without it every other value here is identical whether the dates were substituted or not, which is the fault the plan's own constraint on before-and-after values names. +Expected after: `0` (the bare heading is gone), `2` (heading and ledger line), `1`, and `0`. The last stays `0` before and after, and **asserts an invariant rather than verifying an edit** — no literal `` may exist in this document at any point. It is the only value here that distinguishes a correct edit from a placeholder left in place; without it every other number is identical whether the dates were substituted or not. - [ ] **Step 6: Confirm the class no longer reports this document** @@ -1030,9 +1068,11 @@ git commit -m "docs: annotate this spec's discharged chain debt and re-stamp its ### Task 13: End-state sweep **Files:** -- none unless a check fails +- Modify, conditionally: `docs/plans/2026-09-07-diff-scoped-chain-debt.md` — Step 4's annotation, where this plan's own ledger holds an unannotated diff-scoped LGTM heading +- Modify, conditionally: whatever document Step 6's gate reports a hit against — the fix plus its gate line +- Otherwise none -This task modifies nothing, so the before-and-after constraint does not apply to it: every check below is an end-state assertion, and the exemption is claimed here in words rather than inferred. Its purpose is to catch what a hand-written manifest cannot guarantee. The propagation gate is the real backstop, and Step 6 is where it runs. +**Every check in this task asserts an end state rather than verifying an edit**, which is the exemption the before-and-after constraint requires be claimed in words. The two writes above are conditional repairs the checks discover, not edits any check verifies. The task's purpose is to catch what a hand-written manifest cannot guarantee: the propagation gate is the real backstop, and Step 6 is where it runs. - [ ] **Step 1: The retired token survives nowhere in shipped content** @@ -1066,11 +1106,13 @@ Expected: `6`, `6`, and no output. Run each `rg` command the `## Unfinished-work list` section publishes, exactly as written, from the repo root. Expected: each exits without a usage error. Hits are read against each entry's scope, and the whole sweep should report no unfinished work — no `grilled: grilling`, no open or held ledger line, no pending re-review, and no misplaced stamp. -Two classes need a word, because this plan is itself a document the sweep reads. +One known line is rejected output rather than a hit, and is named here so an executor is not left deciding whether the sweep failed: the Grilling-pending command returns `docs/plans/2026-07-13-rules-distribution.md`, where `grilled: grilling` appears in the body as part of a quoted frontmatter example. The default guard rejects it — a document quoting the convention describes it rather than instantiating it — exactly as Task 12 Step 7 predicts its own rejected output. + +Two classes need a word beyond that, because this plan is itself a document the sweep reads. **Chain debt on this plan.** A plan's loop terminates on a diff-scoped LGTM followed by a confirming full-document round, so by the time this task runs, this plan's own `## Review rounds` section may hold a diff-scoped LGTM heading. That is a real hit, not noise, and it is **discharged here rather than held**: a later full-document heading is on the page, and Task 3's own text says the annotation's derivation licenses a later session to write it. -Append the bare `, debt discharged ` token to that heading, and nothing else. The confirming round's heading is what licenses the write, so it belongs in the session's derivation — never inside the token, which Task 3 rules "carries a date and nothing else" precisely so one fact gets no second home. +Append the bare `, debt discharged ` token to that heading, and nothing else, `` being the confirming round's date — the discharge event's, by the rule Task 11's preamble states once for the whole plan. The confirming round's heading is what licenses the write, so it belongs in the session's derivation — never inside the token, which Task 3 rules "carries a date and nothing else" precisely so one fact gets no second home. The two lines Tasks 11 and 12 quote inside fenced blocks are a different matter and stay — they sit outside any `## Review rounds` section and the scope leg rejects them. @@ -1094,6 +1136,15 @@ Dispatch the `propagation-auditor` agent on the cheapest available family, named Report to the developer: what the sweep found, what the gate returned, whether the `propagation-auditor` reported its model, and any hit still outstanding. +Commit first, if Step 4 or Step 6 wrote anything. Those writes are process artifacts and ride along with the work's commits rather than being left dirty: + +```bash +git add -A docs/ +git commit -m "docs: discharge this plan's own chain debt and close the gate's hits" +``` + +Where neither step wrote, there is nothing to commit and this step is skipped. + Report one thing more, which no earlier step covers: **the installed rule copies under `.claude/rules/working-process/` now drift.** They are a consumer of every sentence this plan rewrote — both carry the retired token today — and no task edits them, because a Rules payload is distributed by the `sync-rules` engine rather than by hand. Offer that run. The drift hook is the designed backstop, which is why this is a hand-back line rather than a task; leaving it unsaid would let the session's own rules stay a version behind the ones it just shipped. A missing self-report is expected rather than anomalous — the prescribed rung is already the cheapest family, so a silent substitution could only run the audit above tier, which does not invalidate a structural CLEAN. Then offer the plan-adversary round: `status` moves to `approved` on the developer's word, not this task's. --- @@ -1109,6 +1160,37 @@ The questions the spec put to the developer, all answered 2026-09-07. They are r ## Review rounds +### 2026-09-07 — plan-adversary, fable 5, concerns (round 3, full-document) + +The confirming round the loop owed. It simulated all thirteen tasks in +order against the live payload files: every `Find:` block matches +byte-exactly and uniquely **at its execution moment**, none broken by an +earlier task's edit to the same file; every stated before-value and +after-value verifies, end-state counts included; the counting chain +resolves; Task 12's hash precondition holds. The recorded deviation on +Task 1 Step 5 survived attack — Tasks 11 and 12 need those headings +byte-exact as Edit anchors, so truncating them would trade a quiet grep +for two broken edits. + +- fixed 2026-09-07 — [Important] Task 11's two substitution instructions contradict each other, so the token's date is unresolved: Step 3 writes the ruling's date into the heading while Step 4 orders the implementation date for both occurrences and calls it the same substitution, and every published check passes with either date written; license: the spec's ruling that the token "names an event — this heading's debt was discharged on that date", plus the ledger's own rule that a terminal line's leading date is when the line reached that state; the token's date is now stated once as the discharge event's date, Step 4 distinguishes the leading date from the quoted token's date, and Task 13's contingent annotation carries the same rule +- fixed 2026-09-07 — [Minor] Task 13 can write two documents — Step 4's contingent annotation and Step 6's gate lines — while its `Files:` line says it modifies nothing, which is also the line the before-and-after exemption rests on, and no step commits them; license: the process-artifacts rule that artifact updates ride along with their work's commits and are never left dirty; the `Files:` line now names both conditional writes, the exemption is re-anchored to the checks rather than to the task, and a conditional commit step closes them +- fixed 2026-09-07 — [Minor] the before-and-after constraint claims Task 13 is the sole exempt task while Tasks 9 and 11 both carry deliberate invariant guards that score the same value before and after; license: the constraint's own requirement that an exemption be claimed in words rather than inferred, which both guards already do; the constraint now exempts any check whose step declares it asserts an invariant, and the "sole exempt task" claim is gone +- fixed 2026-09-07 — [Minor] Task 1's scope leg adds ", and carrying `-n` for the same reason", which the spec's prescribed block does not contain, recorded nowhere — unlike the owner-leg addition the same task documents at length; license: the spec's own prescribed command, which carries `-n`, and the sibling entry that explains why; the addition is now recorded beside the owner-leg departure it sits next to +- fixed 2026-09-07 — [Minor] the glossary's Chain debt entry enumerates the third discharge path as "the developer's recorded decline of the gate's pair offer", which no longer covers the instance developer ruling 2 licenses — an implemented document where the gate never fired and so offered no pair to decline; license: ruling 2 itself, plus the spec's own reasoning for the live instance that the gate which should have asked never fired; Task 1 gains a glossary step, and the departure from the spec's "no implementation task covers these" is recorded there +- fixed 2026-09-07 — [Minor] Task 13 Step 4 predicts a hit-clean sweep without predicting its known rejected output: the Grilling-pending command returns one line today, a body quote of the frontmatter example in `docs/plans/2026-07-13-rules-distribution.md`; license: Task 12 Step 7's own practice of naming rejected output so an executor is not left deciding whether the sweep failed; the step now names that line and why the default guard rejects it + +- signal 2026-09-07 — another round would not repay itself: the Important is a two-sentence repair plus one date rule stated once, the five Minors are one-sentence touches, and this round performed the whole-document read the loop owed, so nothing unread remains for a round 4 to certify; the leftovers are worth a fix wave and the developer's eyes on the date rule, not a re-read + +Answering the round's focusing question — whether the pattern the first +two rounds found still holds — it narrowed again and did not close. Both +halves earlier rounds attacked are now sound, forward simulation +included, which was round 2's leftover. The residue moved one layer out +from wherever the last round pointed: date semantics *inside* the one +ledger line, the sweep commands Task 13 orders but the plan never ran, +and the plan's own exemption clause, which its own tasks contradict. +Three rounds, three addresses, one habit — the discipline holds wherever +a previous round looked and slips in the adjacent cell. + ### 2026-09-07 — plan-adversary, fable 5, concerns (round 2, diff-scoped) - fixed 2026-09-07 — [Important] fix 1's restated counts are right for today's tree and wrong for the tree the plan predicts at execution time: this plan's own loop terminates on a diff-scoped LGTM, that heading lands inside a real `## Review rounds` section where the scope leg does not reject it, and the rules that would annotate it ship during this very plan — so the three steps state absolutes that Task 13 Step 4 already contradicts in words; license: the plan's own constraint that a check must state the value it returns, plus Task 13 Step 4's written prediction of this exact ledger state, which makes the correction a recomputation rather than a decision; the three steps now state a fixed base plus one contingent line, each pointing at Task 13 Step 4 for why that line is a real hit discharged there From e0955e390eeeba7460e112cd28bc77ad66ff7913 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:20:42 +0200 Subject: [PATCH 093/126] docs: close the plan-adversary loop by resolution annotation --- docs/plans/2026-09-07-diff-scoped-chain-debt.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index 3b298f3..aac3c8f 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -2,7 +2,7 @@ ticket: none date: 2026-09-07 status: draft -adversary: concerns +adversary: concerns (resolved 2026-09-07) spec: ../specs/2026-09-07-diff-scoped-chain-debt-design.md branch: feature/audit-errata base: develop @@ -1191,6 +1191,20 @@ and the plan's own exemption clause, which its own tasks contradict. Three rounds, three addresses, one habit — the discipline holds wherever a previous round looked and slips in the adjacent cell. +**The loop closes here, by the developer's decision of 2026-09-07.** All +six of this round's findings were fixed under the licenses their ledger +lines cite, leaving nothing open or held, and the reviewer's stop signal +judged a fourth round unable to repay itself: this round performed the +whole-document read the loop owed, so no unread text remains for another +round to certify, and what it left behind was six one-sentence repairs. +A plan's loop terminates only on a full-document `LGTM`, which this +round did not give, so the close is the resolution annotation rather +than a terminator — `concerns (resolved 2026-09-07)`, this paragraph +being the body note the lifecycle rule requires. + +Scoping never spans a close: any later round on this plan opens a new +loop and reads the whole document again. + ### 2026-09-07 — plan-adversary, fable 5, concerns (round 2, diff-scoped) - fixed 2026-09-07 — [Important] fix 1's restated counts are right for today's tree and wrong for the tree the plan predicts at execution time: this plan's own loop terminates on a diff-scoped LGTM, that heading lands inside a real `## Review rounds` section where the scope leg does not reject it, and the rules that would annotate it ship during this very plan — so the three steps state absolutes that Task 13 Step 4 already contradicts in words; license: the plan's own constraint that a check must state the value it returns, plus Task 13 Step 4's written prediction of this exact ledger state, which makes the correction a recomputation rather than a decision; the three steps now state a fixed base plus one contingent line, each pointing at Task 13 Step 4 for why that line is a real hit discharged there From c5d38becfabd9a475c4e405641be26ff75cc1c6c Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:22:21 +0200 Subject: [PATCH 094/126] docs: approve the chain-debt plan --- docs/plans/2026-09-07-diff-scoped-chain-debt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index aac3c8f..66f6927 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-09-07 -status: draft +status: approved adversary: concerns (resolved 2026-09-07) spec: ../specs/2026-09-07-diff-scoped-chain-debt-design.md branch: feature/audit-errata From a247a27c13981a3c11d256f023708ace944fb56a Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:25:07 +0200 Subject: [PATCH 095/126] feat(working-process): add the Chain debt Unfinished-work class --- docs/domain/glossary.md | 4 +++- plugins/working-process/rules/spec-plan-lifecycle.md | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index bf2ef7a..1cfb586 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -362,7 +362,9 @@ responsibility for the part no round re-read — or explicitly decline to. The consumption gate owns it, not the loop, which owes nothing further once it terminates. Discharged three ways: an integrity audit, any later full-document round whatever its verdict, or the developer's recorded -decline of the gate's pair offer. Recorded as `, debt discharged ` +decline — of the gate's pair offer, or, where the document is already +implemented and the gate never fired, of the question that offer would +have put. Recorded as `, debt discharged ` appended to that LGTM's round heading, and the record says only that it happened and when, never how or how well. Distinct from the diff-scoped chain itself, the round-one-plus-reviewed-waves structure the LGTM diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 0761ed2..c38aed0 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -342,6 +342,18 @@ leg, and the review-loop entry below is the one that does. which is why this command carries `-n` where the others carry `-l`. Owner: an `open` line belongs to the document's next touch, which re-offers the remediation; a `held` line belongs to the developer. +- **Chain debt** — a diff-scoped `LGTM` heading carrying no record that + what it owed was discharged. + `rg -n --no-ignore --crlf '^### .*LGTM \(round [0-9]+, diff-scoped\)$' docs/` + Scope: a hit counts only inside a `## Review rounds` section — the + second entry to re-scope the default guard, for the reason the first + one does, and carrying `-n` for the same reason. + Owner: for a spec, the consumption gate's pair offer; for a plan, the + confirming full-document round. On a document already at + `status: implemented` the debt is discharged by recorded decline + without any dispatch: completed work is not re-reviewed, so the + annotation is written citing that standing decision, and a document + still in flight keeps the pair offer. - **Pending re-review** — a verdict produced below the prescribed tier, neither refreshed nor waived. `rg -l --no-ignore --crlf '^\s*(architect|adversary)-fallback: [a-z0-9-]+ \((degraded|chosen) [0-9-]+\)$' docs/` From 74606db682bb974ece74248bdd2307c4b6727b0d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:30:34 +0200 Subject: [PATCH 096/126] fix(working-process): the Unresolved-verdict owner leg no longer licenses skipping a plan's confirming round --- plugins/working-process/rules/spec-plan-lifecycle.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index c38aed0..fbbda06 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -330,7 +330,12 @@ leg, and the review-loop entry below is the one that does. and nothing closed it. `rg -l --no-ignore --crlf '^\s*(architect|adversary): (blocking|concerns)$' docs/` Owner: a fresh round at the prescribed tier, or the resolution - annotation above. + annotation above — except on a plan whose latest round heading is a + diff-scoped `LGTM`, where the confirming full-document round closes + the verdict and the annotation may not, since a plan's loop never + terminates on that heading. Such a plan matches Chain debt as well: + one debt seen from two sides, both extinguished by that round, and the + duplicate is deliberate. - **Unfinished review-loop ledger** — a disposition line nobody closed: an `open` line whose remediation never ran, or a `held` line whose question still waits. From 0645a0827318aaf84be9aef9f374b6cab33b45c6 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:33:40 +0200 Subject: [PATCH 097/126] feat(working-process): replace the decline-only chain token with the three-path debt-discharged annotation --- .../rules/spec-plan-lifecycle.md | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index fbbda06..4187b31 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -214,12 +214,37 @@ continuation does not match. Payload under a line is therefore invisible to every published command, and where it runs long it belongs in indented sub-bullets rather than in a longer line. -One annotation extends those shapes, and nothing else does. A spec whose -developer accepts a -diff-scoped chain at the consumption gate gains `, chain accepted ` -on that round's LGTM heading: the dispatcher appends it there on the -decline, and its presence defeats the gate's re-ask, as `, waived ` -defeats the re-review offer. +One annotation extends those shapes, and nothing else does. A +diff-scoped `LGTM` heading gains `, debt discharged ` once the +chain debt it carries is discharged, and its presence defeats the +consumption gate's re-ask, as `, waived ` defeats the re-review +offer: + + ### — architect, , LGTM (round 3, diff-scoped), debt discharged + +The token goes after the closing parenthesis rather than inside it. A +parenthesised token qualifies a value — `concerns (resolved )` +changes what the verdict means — while a comma-appended token adds a +later event to a finished record, and this annotation is written later, +by a different actor, about a different event. + +Three paths discharge the debt, all three write the same token, and the +dispatcher writes it in every case: the developer declining the gate's +pair offer, written in the decline turn before the work that decline +licenses begins; an integrity audit, written once its dispositions are +applied and before the `integrity:` stamp; and any later full-document +round, at its stamping turn, whatever its verdict — the debt is +discharged by the reading, not by the grade. A full-document round reads +the whole document, so it annotates every unannotated diff-scoped `LGTM` +heading above it rather than only the one it follows. + +The token carries a date and nothing else. Each path leaves its own +trace — an `integrity:` stamp, a later full-document heading, or +neither — and no consumer reads the path, so recording it would give one +fact a second home. Where a session discharges the debt and dies before +annotating, the annotation's own derivation licenses a later session to +write it; only the decline path has nothing to derive from, and there +the debt correctly re-surfaces and the developer declines again. Ledger lines written before this merge stay as written, as the `scope` token's introduction already established. The shapes they use are kept From 9a109d5ad734b6375942a4d24b8ff83a9365bba6 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:37:55 +0200 Subject: [PATCH 098/126] fix(working-process): order the debt annotation before the integrity hash and license it on an implemented document --- plugins/working-process/rules/spec-plan-lifecycle.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 4187b31..7084350 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -34,7 +34,10 @@ base: master # optional: branch the topic branch was cut from diffing it against those surfaces first — the document is the archive, not the specification of what stands today. It is amended only in frontmatter, never in the body: a verdict certifies the body it was - given, and an `integrity:` hash covers exactly that text. + given, and an `integrity:` hash covers exactly that text. One class of + body edit is excepted: a ledger annotation recording a process event, + such as `, debt discharged `, is a process record rather than a + design amendment. - `revises:` names the documents a newer one departs from — written on the newer document, pointing back, and never on the older one, which stays as its stamps left it. It records supersession, not lineage: a @@ -74,7 +77,10 @@ base: master # optional: branch the topic branch was cut from `integrity: (sha: )`, the date for the reader and the hash for the check. The hash covers the text below the frontmatter's closing `---`, so writing the stamp never invalidates what - it stamps. Stamper and gate run one command, so the comparison can never + it stamps. Where the audit also discharges a chain debt, the annotation + is written before the hash is recomputed: the hash covers the + `## Review rounds` section, so a stamp written first is stale the moment + the annotation lands. Stamper and gate run one command, so the comparison can never mismatch on convention: `sed '1,/^---$/d' | shasum | cut -c1-7` — `shasum` rather than `sha1sum` because stock macOS ships only the From 646bf5f55b3a51c4ab7952278df547adcfaa266d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:42:05 +0200 Subject: [PATCH 099/126] fix(working-process): ground the annotation-before-hash ordering in the hashed body --- plugins/working-process/rules/spec-plan-lifecycle.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 7084350..a04c826 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -78,9 +78,8 @@ base: master # optional: branch the topic branch was cut from the hash for the check. The hash covers the text below the frontmatter's closing `---`, so writing the stamp never invalidates what it stamps. Where the audit also discharges a chain debt, the annotation - is written before the hash is recomputed: the hash covers the - `## Review rounds` section, so a stamp written first is stale the moment - the annotation lands. Stamper and gate run one command, so the comparison can never + is written before the hash is recomputed: the annotation lands inside + the hashed body, so a stamp written first is stale the moment it lands. Stamper and gate run one command, so the comparison can never mismatch on convention: `sed '1,/^---$/d' | shasum | cut -c1-7` — `shasum` rather than `sha1sum` because stock macOS ships only the From 1cc6d6b7363a9917697bca53bd9ea0b70df94955 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:44:41 +0200 Subject: [PATCH 100/126] style(working-process): rewrap the integrity bullet after the ordering fix --- plugins/working-process/rules/spec-plan-lifecycle.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index a04c826..3d8ea61 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -79,7 +79,8 @@ base: master # optional: branch the topic branch was cut from frontmatter's closing `---`, so writing the stamp never invalidates what it stamps. Where the audit also discharges a chain debt, the annotation is written before the hash is recomputed: the annotation lands inside - the hashed body, so a stamp written first is stale the moment it lands. Stamper and gate run one command, so the comparison can never + the hashed body, so a stamp written first is stale the moment it lands. + Stamper and gate run one command, so the comparison can never mismatch on convention: `sed '1,/^---$/d' | shasum | cut -c1-7` — `shasum` rather than `sha1sum` because stock macOS ships only the From aac9a4027b20191fd764ff3273dda3b96d7fb2fe Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:47:21 +0200 Subject: [PATCH 101/126] feat(working-process): give a reviewer's stop signal a ledger line shape --- plugins/working-process/rules/spec-plan-lifecycle.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 3d8ea61..564a238 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -270,6 +270,17 @@ indented payload; a paragraph explaining why a wave went the way it did belongs there too. A lint over the section reads the anchored lines and ignores the prose. +A reviewer's stop signal takes a line of its own, under the heading of +the round that gave it: + + - signal + +It carries the leading token `signal`, no severity — a judgment about +the next round's marginal value is not a finding — and no authorizer, +since nobody licensed it. It joins no anchor: a stop signal owes nobody +a next move, so it is closed the moment it is written, as a gate line +is. The workflow rule owns the ask that produces it. + ### Gate lines The propagation gate, when that agent is available, writes two shapes of From de9f38cb947ce6f9386f482aaed09bb22186e47f Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:50:16 +0200 Subject: [PATCH 102/126] fix(working-process): state the list's anchor and payload properties without counting its entries --- .../rules/spec-plan-lifecycle.md | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 564a238..0d0caa3 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -212,11 +212,11 @@ their condition holds. Every terminal line carries exactly one authorizer. -Payload costs nothing structurally. Four of the five Unfinished-work -commands anchor a frontmatter field and are held to the frontmatter -block by the list's default scope guard, so no body line reaches them at -all; the fifth is this ledger's own, anchored on `^- `, which an indented -continuation does not match. Payload under a line is therefore invisible +Payload costs nothing structurally. An Unfinished-work command under the +list's default scope guard is held to the frontmatter block, so no body +line reaches it at all; an entry publishing its own scope anchors a +leading disposition token or a round heading, and an indented +continuation matches neither. Payload under a line is therefore invisible to every published command, and where it runs long it belongs in indented sub-bullets rather than in a longer line. @@ -362,7 +362,7 @@ matching line sits inside the document's frontmatter block — between the later pair — because a document quoting this convention in its body describes it rather than instantiating it. That guard is the default. An entry re-scopes it only by publishing its own match scope as a fourth -leg, and the review-loop entry below is the one that does. +leg, and the entries below that do so say it there. - **Grilling pending** — a session's outcomes are recorded and not yet applied. @@ -422,10 +422,12 @@ match, and that defeat is the recorded closed state. The leading anchors are tolerant on purpose, so a relocated field is still found. The Misplaced stamp command anchors `^\s+` instead, because there the indentation is the defect it looks for rather than an accident to -tolerate. Those anchors all sit on a frontmatter field; the review-loop -entry anchors a leading disposition token instead, so there the close is -a rewrite — `open` or `held` becomes `fixed ` or -`declined `, and the anchor stops matching. +tolerate. Those anchors sit on a frontmatter field wherever the default +guard holds. An entry publishing its own scope anchors a body line +instead — a leading disposition token or a round heading — and there the +close is a rewrite or an appended annotation: `open` or `held` becomes +`fixed ` or `declined `, and a discharged chain debt gains +`, debt discharged `. Either way the anchor stops matching. ## Lifecycle offers From f101c0958bd732262360135b6783e55344c6fc15 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:53:44 +0200 Subject: [PATCH 103/126] feat(working-process): price the gate's two arms and move the decline path onto the debt token --- plugins/working-process/rules/workflow.md | 36 ++++++++++++++++------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 0ffc032..71bf958 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -369,20 +369,34 @@ For a spec, the consumption gate before plan-writing offers the pair as one question — an integrity audit or a confirming full-document round — and never an offer followed by a re-offer of the option just declined. When the `integrity-auditor` agent is absent the offer carries the -confirming round alone. Declining is the developer accepting the chain -explicitly, and the acceptance is recorded rather than remembered: the -dispatcher appends `, chain accepted ` to the diff-scoped LGTM -heading, and that annotation defeats the gate's re-ask. +confirming round alone. The two arms cost differently and the offer says +so: an audit returns material for the dispatcher to dispose of and +leaves the verdict alone, while a confirming round on a spec is a new +loop's first round, since the spec's LGTM already closed its loop — it +mints its own verdict and stamps it, so a `concerns` there flips the +field back while plan-writing waits. The confirming-round arm therefore +blocks plan-writing; the audit arm does not, and plan-writing follows +its dispositions. + +Declining is the developer discharging the chain debt by release rather +than by performance, and the discharge is recorded rather than +remembered: the dispatcher appends `, debt discharged ` to the +diff-scoped LGTM heading, in the shape the spec-plan-lifecycle rule +defines, and that annotation defeats the gate's re-ask. The other two +paths write the same token. For a plan the loop never terminates on a diff-scoped LGTM: one full-document confirming round follows, and the confirming round's -verdict is the one stamped. That carries the single named exception to -the relay-then-stamp order above — a plan's diff-scoped LGTM is relayed -and its round record written, and only the frontmatter stamp waits for -the confirming round. Recovery therefore reads the ledger rather than -the stamp: a plan whose latest round heading is a diff-scoped LGTM that -no later full-document round follows is re-offered its confirming round -at the document's next touch, whatever the frontmatter says. +verdict is the one stamped. That round runs under the loop's standing +consent like any other — the rules mandate it, so it is no decision of +the developer's and spends none of the round's one interruption. It +carries the single named exception to the relay-then-stamp order above — +a plan's diff-scoped LGTM is relayed and its round record written, and +only the frontmatter stamp waits for the confirming round. Recovery +therefore reads the ledger rather than the stamp: a plan whose latest +round heading is a diff-scoped LGTM that no later full-document round +follows is re-offered its confirming round at the document's next touch, +whatever the frontmatter says. Scoping never spans a close. An annotation close ends the loop, and a later round on the same document opens a new one, reading the whole From 0b4ecf5195ad8ee5cd21eaf510471574b4ed297b Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 20:57:08 +0200 Subject: [PATCH 104/126] feat(working-process): count a plan's confirming round against the round cap --- plugins/working-process/rules/workflow.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 71bf958..2c3453c 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -338,7 +338,14 @@ evidence to attack, never a defence to protect. event is recorded nowhere, so the cap is best-effort by construction; a session that cannot count its own rounds escalates rather than assuming, since resetting to zero would let a long session grant - itself three fresh rounds after every compaction. + itself three fresh rounds after every compaction. A plan's confirming + full-document round counts like any other: the count folds round + headings, and excluding one kind would mean classifying them — a + second fragile derivation in the one place the rules already concede + the cap is best-effort. A plan whose loop spent its three rounds + therefore escalates once before its confirming round, which is the + most expensive shape a round takes and the one a cap guarding spend + should guard first. - All-Minor signal: two consecutive rounds whose findings are all Minor end the unattended run. Triage the round as always — by license, never by grade — and escalate with an offer of a fresh round instead of From 0593f2a8c09380d6659dbcf20b7de6a159a50b21 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:00:27 +0200 Subject: [PATCH 105/126] feat(working-process): record a reviewer's stop signal in the ledger --- plugins/working-process/rules/workflow.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 2c3453c..0fe1dfe 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -315,7 +315,12 @@ every round, whatever grades the findings carry — a round can leave one Important behind and still not repay a re-read. That judgment concerns the next round's marginal value, never whether the document is good enough, and it informs the developer's decision rather than replacing -it. Where the ledger records a deviation from a reviewer's suggestion, +it. The signal is recorded where a later session can cite it: one line +under the heading of the round that gave it, in the shape the +spec-plan-lifecycle rule defines. A signal surviving only in a relay +dies with the next compaction, and practice has needed it twice — once +to justify overriding one, once to close a loop on one. Where the ledger +records a deviation from a reviewer's suggestion, the brief invites refutation of the recorded rationale — a rationale is evidence to attack, never a defence to protect. From 0dceba8950ee2863d1b8b621220852c5ccf2767d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:04:58 +0200 Subject: [PATCH 106/126] fix(working-process): restore the concurrency limit's reasoning and name its one new consequence --- plugins/working-process/rules/workflow.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 0fe1dfe..944001b 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -162,7 +162,14 @@ available: - At most one live round per document per field within the session; superseding a running round stops it when the platform offers a stop, otherwise the stale result is relayed as stale and never - stamped. + stamped. A parallel round from another session is accepted as + undetectable and stays benign: both rounds record in the body and the + field holds the later stamp. One consequence postdates that decision — + a diff-scoped LGTM certifies a chain, so an interleave punches a hole + no round ever read. The discharge paths are the mitigation, since an + audit and a full-document round each read the whole document, and a + heading-derived cap over-counts under interleave, which escalates + early. - When the reviewed document changed after dispatch — known only conversationally; an out-of-session edit is accepted as undetectable — the relay says so and the stamp waits for the From 8d5c11cfe65ffc7ce036221375cb0403dd13cd22 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:10:52 +0200 Subject: [PATCH 107/126] docs: discharge the audit-agents spec's chain debt by recorded decline --- docs/specs/2026-08-27-audit-agents-design.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/specs/2026-08-27-audit-agents-design.md b/docs/specs/2026-08-27-audit-agents-design.md index d97096d..68363ad 100644 --- a/docs/specs/2026-08-27-audit-agents-design.md +++ b/docs/specs/2026-08-27-audit-agents-design.md @@ -302,7 +302,8 @@ rather than enumerate them. - fixed — [Minor] the recomputation owner was named only for the spec target while a plan may carry the stamp; license: this spec's own permitted-target sentence plus the sibling spec's no-gated-audit clause; scoped to spec-gate semantics, a plan's stamp informational and stale silently - fixed — [Minor] "It joins no Unfinished-work list entry" contradicted the Misplaced-stamp detecting entry four lines later; license: the two sentences themselves; scoped to "Staleness joins no Unfinished-work list entry" -### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped) +### 2026-08-27 — architect, fable 5, LGTM (round 3, diff-scoped), debt discharged 2026-09-07 - fixed — [Minor] the propagation comparison target named an absolute family where the mirrored mechanism compares dispatched against prescribed; license: the glossary's Tier entry (a rung resolves at dispatch time); the sentence now mirrors the integrity wording - fixed — [Minor] the propagation-auditor's self-report duty lived only under the integrity-auditor heading; license: this spec's own tier-verification paragraph defining the duty for both auditors; the propagation Output paragraph now points at it +- fixed 2026-09-07 — this round's diff-scoped LGTM left a chain debt that nothing recorded, and the document reached `implemented` unpaid; ruling: 2026-09-07; the developer accepted the chain on the record — the decline path exercised late, since no audit ran, no later full-document round was dispatched, and none can be — and the heading gains `, debt discharged 2026-09-07` From bf9ed96de35740c1f7b3aef405de6cd5d3e6f4fd Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:13:56 +0200 Subject: [PATCH 108/126] docs: annotate this spec's discharged chain debt and re-stamp its integrity hash --- docs/specs/2026-09-07-diff-scoped-chain-debt-design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index dfd2dde..d07c675 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -4,7 +4,7 @@ date: 2026-09-07 status: draft grilled: 2026-09-07 architect: LGTM -integrity: 2026-09-07 (sha: 4a838b2) +integrity: 2026-09-07 (sha: b98e782) revises: [./2026-08-17-autonomous-review-loop-design.md, ./2026-09-02-ledger-as-finding-state-design.md] branch: feature/audit-errata base: develop @@ -662,7 +662,7 @@ matching already does. ## Review rounds -### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped) +### 2026-09-07 — architect, fable 5, LGTM (round 2, diff-scoped), debt discharged 2026-09-07 An integrity audit ran at the consumption gate after this round, on the most capable tier and a fresh context, with coverage 638 of 638 lines. It From 86f899a12c7c6020131cbe0bf40907b1b4a699d0 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:30:43 +0200 Subject: [PATCH 109/126] docs: mark the chain-debt spec and plan implemented and sync the installed rules --- docs/plans/2026-09-07-diff-scoped-chain-debt.md | 2 +- docs/specs/2026-09-07-diff-scoped-chain-debt-design.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plans/2026-09-07-diff-scoped-chain-debt.md b/docs/plans/2026-09-07-diff-scoped-chain-debt.md index 66f6927..5cbf694 100644 --- a/docs/plans/2026-09-07-diff-scoped-chain-debt.md +++ b/docs/plans/2026-09-07-diff-scoped-chain-debt.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-09-07 -status: approved +status: implemented adversary: concerns (resolved 2026-09-07) spec: ../specs/2026-09-07-diff-scoped-chain-debt-design.md branch: feature/audit-errata diff --git a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md index d07c675..5dac47e 100644 --- a/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md +++ b/docs/specs/2026-09-07-diff-scoped-chain-debt-design.md @@ -1,7 +1,7 @@ --- ticket: none date: 2026-09-07 -status: draft +status: implemented grilled: 2026-09-07 architect: LGTM integrity: 2026-09-07 (sha: b98e782) From ca9f93edf6e620adfcf2f6e910ebf0d6ff728645 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:51:31 +0200 Subject: [PATCH 110/126] feat(working-process): per-round commits on a document branch --- docs/domain/glossary.md | 18 +++++++++-- .../rules/spec-plan-lifecycle.md | 31 +++++++++++++++++++ plugins/working-process/rules/workflow.md | 12 ++++--- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 1cfb586..00b6f73 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -321,9 +321,10 @@ _Avoid_: mechanical finding **Disposition ledger**: The record a review loop keeps inside the reviewed document, under one `## Review rounds` section: what each round found and what became of it. -It carries the loop's durable state, and nothing else does — the -session, the reviewer and the developer are all volatile, and these -documents stay uncommitted through the rounds. Per-finding and per-hit +It carries the loop's durable state — the session, the reviewer and the +developer are all volatile. Where the loop commits per round, git +carries which lines each round changed and the ledger keeps what no diff +shows: the intent and the authorizer. Per-finding and per-hit state is written into it, and so is one obligation the consumption gate owns, the chain debt, because no folding derives it; loop-level state is derived from the round headings and stored nowhere. The name comes from the terminal states @@ -371,6 +372,17 @@ chain itself, the round-one-plus-reviewed-waves structure the LGTM certifies. _Avoid_: chain accepted, chain closed, unclosed chain +**Document branch**: +The local branch a review loop's per-round commits live on, named +`.docs` — git refuses a ref nested under an existing branch, so a +suffix rather than a path segment. It carries the whole authoring phase, +a spec's rounds and its plan's alike, and the topic branch takes it at +the implementation-ready gate by fast-forward or by squash, the project's +choice. It survives that merge rather than closing with it, so the ref +marks where authoring ended and loop churn stays off any published +branch until somebody pushes it. +_Avoid_: docs branch, review branch, scratch branch + **Verdict agent**: An agent whose report ends in a verdict the dispatcher stamps into the reviewed document's frontmatter — `architect` and `plan-adversary`. diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 0d0caa3..8fcfc6f 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -466,5 +466,36 @@ suggestion covers only paths git tracks or would track; deliberately ignored documents are skipped silently, and committing itself stays with the developer. +One shape of that sooner call has a convention, because practice kept +reaching for it: **per-round commits on a document branch.** When the +developer authorizes it, the loop commits the reviewed document once per +round, as the round's last act. That boundary matches the ledger's own +unit — a round mutates the document several times (the stamp, the +triage, the fix wave, any gate episodes), and one commit after the wave +records what the round found together with what the session did about +it. + +The commits go to a local branch named `.docs`, never to the +topic branch itself. Git refuses a ref nested under an existing branch, +so `feature/-/docs` cannot exist while its parent does; the +suffix takes a dot because the branch convention already spends hyphens +on name parts, where `-docs` would read as a topic about documenting. + +The loop runs on that branch for the whole authoring phase — the spec's +rounds and the plan's alike — and the topic branch takes it at the +implementation-ready gate: by fast-forward where the history is wanted +whole, by squash where it is not. That choice belongs to the project +rather than the session, so a `CLAUDE.md` note — at the repo root or +beside the documents — records it where it binds, and a session with no +such note asks at the gate. Either way the document branch survives the +merge, which keeps loop churn off any published branch until somebody +pushes it and leaves the surviving ref marking where authoring ended. + +What per-round commits never do is replace the ledger. Git says which +lines changed; the ledger says with what intent and on whose license, +and a diff carries neither "narrowed the claim" nor a cited ADR. A +`` clause may thin to a sentence where the commit carries +the detail; it does not go. + Ticket value format, sourcing order, and backfill live in the ticket-frontmatter rule. diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 944001b..41ee8da 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -188,7 +188,10 @@ no single re-dispatch is offered on its own. At the session's first verdict dispatch, ask once whether the loop may run autonomously — yes / not now / not in this session — state the round cap with the question, and honour the answer for the rest of the Claude Code session -without asking again. A durable preference in the developer's own +without asking again. The same question carries a second clause wherever +the lifecycle rule's per-round commits are available: whether the loop +may commit the reviewed document once per round. One question, two +answers, asked once. A durable preference in the developer's own instructions is respected when present. Without consent every round behaves as it did before: relay, stamp, and every proposal waits for the developer. @@ -284,9 +287,10 @@ late-round class, and diff-scoping also ends stale-read findings. The ledger supplies what changed. The previous round's `fixed` lines and their `` clauses, together with any gate lines under the same heading, are the record of that wave, so the brief cites them and -needs no snapshot, commit, or hash — these documents stay uncommitted -through the rounds, and the ledger is the only durable account of the -diff. +needs no snapshot, commit, or hash. Where the loop is not committing per +round, the ledger is the only durable account of the diff; where it is, +the commit carries the lines and the ledger still carries the intent. The +brief cites the ledger either way. Diff-scoping forbids re-reviewing the document beyond the diff, and the ledger is part of the document — so without a clause the reviewer is cut From ace38a37def8666d0c71d5b793f1e8d815e55f6d Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 21:56:12 +0200 Subject: [PATCH 111/126] fix(working-process): part the commit suggestion from the per-round consent question --- plugins/working-process/rules/spec-plan-lifecycle.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 8fcfc6f..3b652f7 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -466,6 +466,14 @@ suggestion covers only paths git tracks or would track; deliberately ignored documents are skipped silently, and committing itself stays with the developer. +Asking whether the loop may commit per round is not that suggestion, and +the difference is the speech act rather than the timing. The suggestion +above says a moment to commit has arrived; the consent question asks +once, before any round runs, for standing authorization to use a +mechanism — and a "no" leaves the authoring phase exactly as this +paragraph describes it. That is why it may be asked during authoring +while the suggestion may not. + One shape of that sooner call has a convention, because practice kept reaching for it: **per-round commits on a document branch.** When the developer authorizes it, the loop commits the reviewed document once per From 0d15b22b7eb01ea3658e0cdfde5627856fd25ec0 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:01:51 +0200 Subject: [PATCH 112/126] docs(working-process): name what a local document branch costs --- plugins/working-process/rules/spec-plan-lifecycle.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 3b652f7..5cc6eb2 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -499,6 +499,13 @@ such note asks at the gate. Either way the document branch survives the merge, which keeps loop churn off any published branch until somebody pushes it and leaves the surviving ref marking where authoring ended. +Both halves of "local" are worth knowing before relying on it. Churn +stays private, and the history dies with the working copy: a teammate +cannot see it, and a lost machine takes it. That is still more than the +alternative, where the same rounds live only in a transcript, but it +means "return the document to the state round three read" is a promise +about one clone rather than about the repository. + What per-round commits never do is replace the ledger. Git says which lines changed; the ledger says with what intent and on whose license, and a diff carries neither "narrowed the claim" nor a cited ADR. A From 6fee2e4cdc26d14440252fcce2baa202bc80f9d4 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:10:17 +0200 Subject: [PATCH 113/126] chore: mint release version - working-process 0.15.0 --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index e8589bb..f878805 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, propagation-auditor and integrity-auditor audit agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.14.0-dev.audit-errata", + "version": "0.15.0", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"], From 6bb9a25bce5f0f90c3e3d614eab2a628087521eb Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:19:51 +0200 Subject: [PATCH 114/126] fix(working-process): scope the decline-path sentence to documents in flight --- docs/domain/glossary.md | 9 ++++----- plugins/working-process/rules/spec-plan-lifecycle.md | 7 +++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/domain/glossary.md b/docs/domain/glossary.md index 00b6f73..4d0e62f 100644 --- a/docs/domain/glossary.md +++ b/docs/domain/glossary.md @@ -365,11 +365,10 @@ once it terminates. Discharged three ways: an integrity audit, any later full-document round whatever its verdict, or the developer's recorded decline — of the gate's pair offer, or, where the document is already implemented and the gate never fired, of the question that offer would -have put. Recorded as `, debt discharged ` -appended to that LGTM's round heading, and the record says only that it -happened and when, never how or how well. Distinct from the diff-scoped -chain itself, the round-one-plus-reviewed-waves structure the LGTM -certifies. +have put. Recorded as `, debt discharged ` appended to that LGTM's +round heading, and the record says only that it happened and when, never +how or how well. Distinct from the diff-scoped chain itself, the +round-one-plus-reviewed-waves structure the LGTM certifies. _Avoid_: chain accepted, chain closed, unclosed chain **Document branch**: diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 5cc6eb2..6302048 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -249,8 +249,11 @@ trace — an `integrity:` stamp, a later full-document heading, or neither — and no consumer reads the path, so recording it would give one fact a second home. Where a session discharges the debt and dies before annotating, the annotation's own derivation licenses a later session to -write it; only the decline path has nothing to derive from, and there -the debt correctly re-surfaces and the developer declines again. +write it; on a document still in flight only the decline path has +nothing to derive from, and there the debt correctly re-surfaces and the +developer declines again. On a document already `implemented` the +Chain debt entry's owner leg makes even that derivable, from the +standing decision it cites. Ledger lines written before this merge stay as written, as the `scope` token's introduction already established. The shapes they use are kept From 8b78cab90b973a4970b4a83a479a6fa948e285ea Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:26:37 +0200 Subject: [PATCH 115/126] feat(working-process): verify a reviewer's citation before it enters the record --- .../agents/propagation-auditor.md | 17 ++++++++++++++++- plugins/working-process/rules/workflow.md | 11 +++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 7193e0b..2a22bc7 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -59,7 +59,7 @@ reliance and is re-dispatched at the right rung. - Report what you found and stop there: no severity, no ranking, no advice on the design. -## Duties — walk all seven; each is a class measured in a real loop +## Duties — walk every one below; each is a class measured in a real loop ### 1. Changed interface → consumer enumeration by parsing, never text match @@ -117,6 +117,21 @@ replacement texts, before any reader reads either. A command that fails to match what the document says it matches is a hit; so is a replacement text that defeats the anchor its own command relies on. +### 8. Citations the last review round introduced + +Open every file and line a recent finding cites and confirm it says what +the citing text claims. A reviewer's citation arrives with an exact +position, which reads like verification and is not one — the dispatcher +who copies it into the ledger turns one agent's evidence into the +project's record, and nothing between the two checks it. Measured twice +in one cycle: a line number off by one, and an identifier that does not +exist under the name the finding gave it. Both were quoted precisely, +both went into the document unchallenged, and both surfaced here. + +Read the source, never the finding's summary of it. Where a citation +names something outside the repository, report that you could not check +it rather than assuming either way. + ## Output Open with the self-report, one line: diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 41ee8da..de6c78b 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -149,6 +149,17 @@ available: - The relay carries the verdict, the model self-report, and every finding in substance — condense narrative prose, never drop a finding or its severity. +- A citation the report supplies — a file and line, an identifier, a + count — is checked against what it names before it is written into + the document or acted on by a fix. A precise citation reads like + verification and is not one, and the dispatcher who copies it into + the ledger launders a reviewer's evidence into the project's record. + The check is cheap and its absence is measured: one cycle relayed a + line number off by one and an identifier that did not exist, both + quoted with exact positions, both caught later by a propagation + audit rather than at the relay. This is the citation's analogue of + the model self-report comparison above — the same duty, on the other + thing a report asserts about the world. - The stamp — the field, any fallback record, and the round record the lifecycle rule defines — lands as one edit, body record first where edit granularity forces separate writes, and goes to the From fdbbba6918c6a11f654e217babfd0e590ecea9db Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:31:43 +0200 Subject: [PATCH 116/126] fix(working-process): name the citation check in the dispatch turn's ordered sequence --- plugins/working-process/rules/workflow.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index de6c78b..3d72e60 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -141,9 +141,13 @@ available: progress visible in the session's task list. - On the completion notification, in one turn and in this order: verify the agent's model self-report (the comparison the lifecycle - rule defines), relay the report to the developer, then stamp the + rule defines), relay the report to the developer, check every + citation the report supplies against what it names, then stamp the verdict (`LGTM` | `concerns` | `blocking`) into the reviewed - document's `architect:` / `adversary:` frontmatter field. The order + document's `architect:` / `adversary:` frontmatter field. The + citation check follows the relay rather than preceding it, because a + wrong citation in conversation costs a correction while a wrong one + in the record outlives the loop. The order has one named exception, defined under *What a diff-scoped LGTM certifies* below: a plan's diff-scoped LGTM. - The relay carries the verdict, the model self-report, and every From f63df230173174e30723bd873a7a43fc749e4c01 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:35:48 +0200 Subject: [PATCH 117/126] fix(working-process): name what the paired ordering sentences bind --- plugins/working-process/rules/spec-plan-lifecycle.md | 8 ++++++-- plugins/working-process/rules/workflow.md | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/working-process/rules/spec-plan-lifecycle.md b/plugins/working-process/rules/spec-plan-lifecycle.md index 6302048..460d1f5 100644 --- a/plugins/working-process/rules/spec-plan-lifecycle.md +++ b/plugins/working-process/rules/spec-plan-lifecycle.md @@ -445,8 +445,12 @@ is available, offer a Project memory review — released work-state notes close, resolved entries sweep to the archive. After any review round, relay the report to the developer, then stamp the verdict into the document's field — this sentence and the workflow -rule's verdict-agent dispatch subsection state the same ordering and -are edited together. The order has one named exception, defined in that +rule's verdict-agent dispatch subsection state the same +relay-before-stamp ordering and are edited together when that changes. +The subsection sequences further checks inside its own turn — the model +self-report before the relay, the report's citations after it — which +this sentence deliberately does not restate, so gaining one does not +make it stale. The order has one named exception, defined in that subsection: a plan's diff-scoped LGTM is relayed and its round record written, while only the frontmatter stamp waits for the confirming full-document round. diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 3d72e60..6ddb03f 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -442,5 +442,7 @@ document again. The `## Dispatching a verdict agent` section above — its bullet list and every subsection under it, this one included — and the lifecycle -rule's relay-then-stamp sentence state the same ordering and are edited -together. +rule's relay-then-stamp sentence state the same relay-before-stamp +ordering and are edited together when that changes. The other checks +this section sequences inside the dispatch turn are its own; adding one +leaves that sentence correct. From 81c7021377c7f093b40acdbd686f5c9d183ab5fe Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:43:49 +0200 Subject: [PATCH 118/126] fix(working-process): part a prescribed block from a reported one in the propagation audit --- .../agents/propagation-auditor.md | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 2a22bc7..32c7178 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -74,9 +74,24 @@ every shipped occurrence of the banned term. ### 2. Prescribed block versus shipped file Diff every verbatim block the document dictates against the file it -targets — the block that never landed and the shipped text a block no -longer matches are both hits. This is the recipe-and-record class that -cost three consecutive hand-diff rounds of the most capable model. +targets. What counts as a hit depends on what the document claims about +that block, so establish the claim first and check accordingly. + +Where the document **reports** a change already made, the block that +never landed and the shipped text a block no longer matches are both +hits. This is the recipe-and-record class that cost three consecutive +hand-diff rounds of the most capable model. + +Where the document **prescribes** a change not yet made — a plan before +its implementation, a design's changes-by-file promise — the target +file's not carrying the new text is the document working as intended. +What is checkable there is the block's anchor: the text the block says +it replaces must exist in the target file byte-exactly, or the edit +cannot execute. Report an anchor that does not match, one that matches +in several places, and one an earlier task in the same document has +already rewritten. Measured: four of sixteen non-clean results in one +outside cycle were prescribed text reported as missing from source, +and the rate went to zero once the two cases were told apart. ### 3. Added field, label, or state → carrier and consumer chains From 51987c354cfbab7743374f3244178ac97ab5c135 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:47:36 +0200 Subject: [PATCH 119/126] docs(working-process): name the report/prescribe partition on both identity surfaces --- plugins/working-process/README.md | 6 ++++-- plugins/working-process/agents/propagation-auditor.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/working-process/README.md b/plugins/working-process/README.md index 6566ac9..ed155fc 100644 --- a/plugins/working-process/README.md +++ b/plugins/working-process/README.md @@ -52,8 +52,10 @@ verdict dispatch and the integrity audit itself. as a task notification and is stamped after relay. - **`propagation-auditor` agent** — the mechanical audit of a spec or plan: it parses every changed interface to enumerate its consumers, - diffs every prescribed block against the file it targets, re-derives - every counter, and runs the document's own verification commands. Its + diffs every prescribed block against the file it targets — a landed + change against what shipped, a promised one against the anchor its + edit needs — re-derives every counter, and runs the document's own + verification commands. Its unit is the hit: located, binary, and carrying the derivation that produced it; a clean audit reports the single line `CLEAN`. It grades nothing, ends in no verdict, and stamps nothing. Dispatched in the diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 32c7178..3682181 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -1,6 +1,6 @@ --- name: propagation-auditor -description: "Mechanical propagation audit of a spec or plan before an expensive dispatch: parses changed interfaces to enumerate their consumers, diffs every prescribed block against the file it targets, re-derives every counter, and returns located hits with their derivation — or the single line CLEAN. Verdict-free and persona-free: it stamps nothing and grades nothing, so a passing gate is a precondition for the dispatch that follows, never a judgment on the design. Dispatch before every verdict-agent dispatch, after a fix wave, before an integrity audit, and after any multi-site edit during authoring. Run it on the cheapest available family, named explicitly — every duty is procedural, and the never-cheapest rule governs reviews, which an audit is not. Runs in the background; the report arrives as a task notification." +description: "Mechanical propagation audit of a spec or plan before an expensive dispatch: parses changed interfaces to enumerate their consumers, diffs every prescribed block against the file it targets — a landed change against what shipped, a promised one against the anchor its edit needs — re-derives every counter, and returns located hits with their derivation — or the single line CLEAN. Verdict-free and persona-free: it stamps nothing and grades nothing, so a passing gate is a precondition for the dispatch that follows, never a judgment on the design. Dispatch before every verdict-agent dispatch, after a fix wave, before an integrity audit, and after any multi-site edit during authoring. Run it on the cheapest available family, named explicitly — every duty is procedural, and the never-cheapest rule governs reviews, which an audit is not. Runs in the background; the report arrives as a task notification." background: true --- From 9c5f150437f286ae34616a3fde893aab404f2216 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:52:11 +0200 Subject: [PATCH 120/126] feat(working-process): an audit report's body governs, never its closing token --- plugins/working-process/rules/workflow.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 6ddb03f..c13c7af 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -267,6 +267,15 @@ an integrity audit. A hit's fix is licensed by its own derivation — a recounted counter and an enumerated missed call site decide themselves — so hits never wait for the developer. +An audit report's body governs, never its closing token. Where a report +lists located hits and also carries `CLEAN`, the hits are the report and +the gate has not passed. Measured twice in six runs of one day on the +cheapest family, the second under a brief that ruled the combination out +in as many words — so emphasis on the writing side is spent, and the +guard belongs to the dispatcher who reads. The same reading governs any +report an agent returns: what it found is in the entries, and the +framing around them is not a verdict to act on. + A hit the session believes is wrong is dismissed, never silently: the session writes the `dismissed` line the spec-plan-lifecycle rule defines and reports the dismissal in the next report it relays to the From 3b4b6aaac713e40b72855b0b7541edcbb73bd063 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:54:42 +0200 Subject: [PATCH 121/126] fix(working-process): scope the body-governs reading to agents that return no verdict --- plugins/working-process/rules/workflow.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index c13c7af..3f97d01 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -272,9 +272,14 @@ lists located hits and also carries `CLEAN`, the hits are the report and the gate has not passed. Measured twice in six runs of one day on the cheapest family, the second under a brief that ruled the combination out in as many words — so emphasis on the writing side is spent, and the -guard belongs to the dispatcher who reads. The same reading governs any -report an agent returns: what it found is in the entries, and the -framing around them is not a verdict to act on. +guard belongs to the dispatcher who reads. + +The reading generalises to the integrity audit's report and stops +there: an audit agent returns material and no verdict, so what it found +is in the entries and the framing around them decides nothing. A +verdict agent is the opposite case — there the verdict is the report's +point, and the dispatcher stamps it once the checks the dispatch +sequence above prescribes have run. A hit the session believes is wrong is dismissed, never silently: the session writes the `dismissed` line the spec-plan-lifecycle rule From 442d45dd2890dfd72bc02f37b060363cc9920a4c Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 22:59:47 +0200 Subject: [PATCH 122/126] fix(working-process): keep the body-governs rule where its evidence is --- plugins/working-process/rules/workflow.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/plugins/working-process/rules/workflow.md b/plugins/working-process/rules/workflow.md index 3f97d01..aac42df 100644 --- a/plugins/working-process/rules/workflow.md +++ b/plugins/working-process/rules/workflow.md @@ -267,19 +267,14 @@ an integrity audit. A hit's fix is licensed by its own derivation — a recounted counter and an enumerated missed call site decide themselves — so hits never wait for the developer. -An audit report's body governs, never its closing token. Where a report -lists located hits and also carries `CLEAN`, the hits are the report and -the gate has not passed. Measured twice in six runs of one day on the -cheapest family, the second under a brief that ruled the combination out -in as many words — so emphasis on the writing side is spent, and the -guard belongs to the dispatcher who reads. - -The reading generalises to the integrity audit's report and stops -there: an audit agent returns material and no verdict, so what it found -is in the entries and the framing around them decides nothing. A -verdict agent is the opposite case — there the verdict is the report's -point, and the dispatcher stamps it once the checks the dispatch -sequence above prescribes have run. +A report's body governs, never its closing token. Where a report lists +located hits and also carries `CLEAN`, the hits are the report and the +gate has not passed. It has happened more than once on the cheapest +family, and once under a brief that ruled the combination out in as +many words — so emphasis on the writing side is spent, and the guard +belongs to the dispatcher who reads. The rule is stated here rather +than generalised, because `CLEAN` is this agent's token and no other +report carries one. A hit the session believes is wrong is dismissed, never silently: the session writes the `dismissed` line the spec-plan-lifecycle rule From bb273888bef0d976e9bc93a680b4542941de5aad Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 23:14:49 +0200 Subject: [PATCH 123/126] docs(working-process): state the auditor's measurements as facts rather than rates --- .../agents/propagation-auditor.md | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 3682181..47879be 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -65,8 +65,9 @@ reliance and is re-dispatched at the right rung. For every interface the document changes — a signature, a name, a heading, an anchor, a field — enumerate its consumers by parsing the -structure that defines them. Measured: a text match missed 2 of 11 call -sites of a changed signature; an argument-counting parse missed zero. +structure that defines them. Measured: a text match missed call sites of +a changed signature that a parse counting arguments found — the +structure names a consumer where the text does not. Here: a renamed rule section, skill, agent, or anchor reaches every cross-reference to it, and a newly minted glossary `_Avoid_` ban reaches every shipped occurrence of the banned term. @@ -79,8 +80,8 @@ that block, so establish the claim first and check accordingly. Where the document **reports** a change already made, the block that never landed and the shipped text a block no longer matches are both -hits. This is the recipe-and-record class that cost three consecutive -hand-diff rounds of the most capable model. +hits. This is the recipe-and-record class that spent consecutive rounds +of the most capable model on hand-diffing what a parse settles. Where the document **prescribes** a change not yet made — a plan before its implementation, a design's changes-by-file promise — the target @@ -89,9 +90,9 @@ What is checkable there is the block's anchor: the text the block says it replaces must exist in the target file byte-exactly, or the edit cannot execute. Report an anchor that does not match, one that matches in several places, and one an earlier task in the same document has -already rewritten. Measured: four of sixteen non-clean results in one -outside cycle were prescribed text reported as missing from source, -and the rate went to zero once the two cases were told apart. +already rewritten. Measured in an outside cycle: prescribed text +reported as missing from source was a recurring false positive, and the +class vanished once the two cases were told apart. ### 3. Added field, label, or state → carrier and consumer chains @@ -113,17 +114,17 @@ claims. Diff the names one document uses against the names its sources define. A name the plan uses that the spec never defines is a spec gap, not a plan error — the invention is the symptom, and report it as the gap it is. -Measured: one such gap survived nine rounds as the cycle's deepest -Important. +Measured: one such gap survived round after round as the cycle's +deepest Important. ### 6. Boundary sentences Check every sentence in which one document reports another's state: frontmatter citations of another document's verdict or counts, a table's -row count against the table, the arithmetic of a review record. Roughly -one finding in ten in the measured cycle was a counter or a boundary -sentence — wrong in nearly every round, twice wrong after being -explicitly verified. +row count against the table, the arithmetic of a review record. Counters +and boundary sentences were a steady share of the measured cycle's +findings — wrong in nearly every round, and wrong more than once after +being explicitly verified. ### 7. Verification simulation @@ -138,10 +139,12 @@ Open every file and line a recent finding cites and confirm it says what the citing text claims. A reviewer's citation arrives with an exact position, which reads like verification and is not one — the dispatcher who copies it into the ledger turns one agent's evidence into the -project's record, and nothing between the two checks it. Measured twice -in one cycle: a line number off by one, and an identifier that does not -exist under the name the finding gave it. Both were quoted precisely, -both went into the document unchallenged, and both surfaced here. +project's record, and nothing between the two checks it. Measured +repeatedly: a line number off by one, an identifier that does not exist +under the name the finding gave it, and a file-and-line pointing at an +unrelated passage — the last on the day this duty shipped, in a report +whose finding was otherwise sound. Each was quoted precisely, and each +would have gone into a document unchallenged. Read the source, never the finding's summary of it. Where a citation names something outside the repository, report that you could not check From 1ebb3ad97cae482d5dd323896c7b766641ee0364 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 23:18:50 +0200 Subject: [PATCH 124/126] fix(working-process): keep each duty's motivating fact when its count goes --- plugins/working-process/agents/propagation-auditor.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/working-process/agents/propagation-auditor.md b/plugins/working-process/agents/propagation-auditor.md index 47879be..b30ad42 100644 --- a/plugins/working-process/agents/propagation-auditor.md +++ b/plugins/working-process/agents/propagation-auditor.md @@ -122,9 +122,9 @@ deepest Important. Check every sentence in which one document reports another's state: frontmatter citations of another document's verdict or counts, a table's row count against the table, the arithmetic of a review record. Counters -and boundary sentences were a steady share of the measured cycle's -findings — wrong in nearly every round, and wrong more than once after -being explicitly verified. +and boundary sentences recur, and they recur wrong: in the measured +cycle they were wrong in nearly every round, and wrong more than once +after being explicitly verified. ### 7. Verification simulation @@ -143,8 +143,9 @@ project's record, and nothing between the two checks it. Measured repeatedly: a line number off by one, an identifier that does not exist under the name the finding gave it, and a file-and-line pointing at an unrelated passage — the last on the day this duty shipped, in a report -whose finding was otherwise sound. Each was quoted precisely, and each -would have gone into a document unchallenged. +whose finding was otherwise sound. Each was quoted precisely. The first +two went into their documents unchallenged; the third was caught by the +check this duty prescribes. Read the source, never the finding's summary of it. Where a citation names something outside the repository, report that you could not check From 4bd441fd70542b91a5586d0d7404623473572e3e Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 23:25:45 +0200 Subject: [PATCH 125/126] docs(working-process): drop the threshold magnitudes from the integrity auditor's card --- plugins/working-process/agents/integrity-auditor.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/working-process/agents/integrity-auditor.md b/plugins/working-process/agents/integrity-auditor.md index e114f55..6511d87 100644 --- a/plugins/working-process/agents/integrity-auditor.md +++ b/plugins/working-process/agents/integrity-auditor.md @@ -48,12 +48,12 @@ version added a number the dispatcher had to ignore. ## Fresh context, and the preconditions it rests on -You read the document cold. The measured cause of textual decay is a -document of some nine hundred lines churned inside one session at roughly -650k tokens, and a reader carrying that session carries its blind spot: -the decision it remembers agreeing to reads as present whether or not the -text says it. Judge the text in front of you, and treat no claim about it -as settled because a dispatch brief asserts it. +You read the document cold. Textual decay was measured on a long +document churned entirely inside one long session, and its cause is that +a reader carrying that session carries its blind spot: the decision it +remembers agreeing to reads as present whether or not the text says it. +Judge the text in front of you, and treat no claim about it as settled +because a dispatch brief asserts it. Two preconditions hold before you read, and your dispatch brief should confirm both: From cc22bff712d6ca34dccd05440590b81779eef667 Mon Sep 17 00:00:00 2001 From: Jacek Nakonieczny Date: Mon, 7 Sep 2026 23:33:31 +0200 Subject: [PATCH 126/126] chore: mint release version - working-process 0.16.0 --- plugins/working-process/.claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/working-process/.claude-plugin/plugin.json b/plugins/working-process/.claude-plugin/plugin.json index f878805..449ccc4 100644 --- a/plugins/working-process/.claude-plugin/plugin.json +++ b/plugins/working-process/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "working-process", "description": "Spec-driven working process on top of superpowers: grilling-session, architect-session, system-designer-session, process-status and sync-rules skills, architect and plan-adversary verdict agents, architect-consult and system-designer-consult consultation agents, propagation-auditor and integrity-auditor audit agents, and process rules distributed as a Rules payload; domain plugins hook in via *-plan-review checklist skills and their own rules/ payloads", - "version": "0.15.0", + "version": "0.16.0", "author": { "name": "Missing Bits (Jacek Nakonieczny)" }, "license": "MIT", "keywords": ["process", "workflow", "spec", "plan", "review", "glossary", "adr", "architecture"],