diff --git a/docs/CATALOG.md b/docs/CATALOG.md index 707c4beb16..8bddbcbd0c 100644 --- a/docs/CATALOG.md +++ b/docs/CATALOG.md @@ -60,7 +60,7 @@ plugin manifests and kept in sync by CI — never hand-edit it; the category voc - [`codebase-health`](../plugins/codebase-health) — Repo-wide drift audit between docs, config, code, and architecture: verifies every factual claim against reality via parallel subagent fan-out, severity-rates findings, and reports read-only, delegating remediation to the implementation/verification lanes. Audit dimensions are configurable through a tracked .claude/codebase-health.md config file written by the setup skill. - [`discipline`](../plugins/discipline) — Discipline correctors that re-anchor a standing rule mid-session, then audit both the work in flight and the pre-existing state and choices it trusts, and correct what has drifted: do-your-research (research and no-assumptions discipline; sibling do-your-research-deep escalates to a typed full inventory of the session's claims — assumptions, asserted facts, concrete specifics, load-bearing premises — verified at a configurable depth and reported as a per-item ledger), follow-our-standards (alignment to the consuming org's engineering conventions), point-dont-copy (pointer-over-copy discipline — no copied content, internal-name coupling, or closed capability lists), reason-dont-recite (interrogate inherited content — precedent is evidence of what is, never self-justifying authority), tighten-your-output (terseness discipline — fewer words or lines with no loss of meaning or correctness), recheck-against-upstream (existing state is not evidence of its own correctness — audit config, code, and infra against current official upstream docs; sibling recheck-against-upstream-deep fans subagents doc-by-doc over a whole subsystem), pick-for-the-problem (tool, library, framework, and approach selection fitted to the problem, not reached for out of habit, availability, incumbency, or preconception), mind-your-maxims (cooperative-communication discipline per Grice plus the AI-augmented transparency maxim), script-the-deterministic-work (offload deterministic sub-work — counts, diffs, sorts, transforms, and scaffolds — to a script that runs, reserving model output for judgment over its real output; the audit runs both ways, also catching an existing script that over-reaches into judgement), use-your-skills (actually use the skills already in context — scan the listing, map the task, invoke the fitting skill instead of reinventing it, and name skills when delegating to a subagent), and reuse-or-replace (anti-fragmentation — new work reuses an established way of doing something or openly replaces it (migrate the old uses, record the decision), never silently stands up a second parallel way; divergence is allowed but owes a recorded reason proportional to blast radius), and scrutinize-dont-coast (adversarial self-scrutiny — stop coasting on your own recent output and re-examine whether it is sound, not merely confidently produced, through a fresh-context pass blind to the reasoning that made it, then remediate with the user; it stops the trajectory first and remediates collaboratively rather than autonomously). Plus further species that are not correctors (examples, not a fixed list — each skill's own description is authoritative), including setup, sweep-all, a posture-batch runbook that composes them — it fans out an audit-only subagent per in-scope corrector, then applies the corrections on the main thread in a fixed order, with batch membership and order set by each corrector's own colocated tier metadata and an optional userConfig overlay — and wait-what, a one-shot user-invoked-only communication repair: type /discipline:wait-what when the last message did not land and the model re-pitches it, backing up as far as needed, adding the missing context, in ASD-STE100 Simplified Technical English, using the project's ubiquitous language; never model-invoked and never in the batch. Firing a corrector is a re-anchor, not an accusation; the audit may return clean. - [`ai-slop`](../plugins/ai-slop) — Detects and removes AI-writing tells (slop) in checked-in markdown prose: em dashes, emoji formatting, AI vocabulary, negative parallelisms, chatbot phrases, filler, stacked hedging, citation artifacts, and the rest of a catalog distilled from Wikipedia's Signs of AI writing. Read-only audit by default with a deterministic detector plus a judgment rubric; an explicit fix action rewrites findings behind a semantic-diff guard. Findings conform to the detector-findings convention so the review fanout fix relay can consume them. -- [`overengineering`](../plugins/overengineering) — Evidence-earned-keep audit of an existing enforcement surface — agent hooks and standing instructions, repository and version-control hooks, CI lanes and gate scripts, branch protections, forge apps, declared external integrations — treating every incumbent mechanism as a retirement candidate until empirical evidence earns its keep, arguing every verdict in cost of carry, capping retirement-direction verdicts on security-class artifacts at FLAG-FOR-HUMAN, and realigning to the simplest adequate solution behind an explicit per-item human gate. The audit is read-only and emits a diffable findings artifact; realignment is a separate, explicitly invoked skill. +- [`overengineering`](../plugins/overengineering) — Evidence-earned-keep audit of an existing enforcement surface — agent hooks and standing instructions, repository and version-control hooks, CI lanes and gate scripts, branch protections, forge apps, declared external integrations — treating every incumbent mechanism as a retirement candidate until empirical evidence earns its keep, arguing every verdict in cost of carry, capping retirement-direction verdicts on security-class artifacts at FLAG-FOR-HUMAN, and realigning to the simplest adequate solution behind an explicit per-item human gate. The audit is read-only and emits a diffable findings artifact; realignment is a separate, explicitly invoked skill; and a third read-only lane re-runs the audit on whatever cadence the consumer wires and reports only what moved since the last run, above a configurable noise budget. - [`improvement`](../plugins/improvement) — Evidence-first, cross-dimension improvement finder — point it at a repo, feature, concept, or process surface and it produces a ranked, evidence-cited list of improvement candidates led by value-to-effort, interviews on the pick, and hands off to the planning pipeline; runnable unattended as a tech-debt-sweep routine. ## Maintenance diff --git a/docs/SKILL-CHEAT-SHEET.md b/docs/SKILL-CHEAT-SHEET.md index e5636f58f5..a2faefab84 100644 --- a/docs/SKILL-CHEAT-SHEET.md +++ b/docs/SKILL-CHEAT-SHEET.md @@ -194,6 +194,7 @@ owned by [docs/CATALOG-TAXONOMY.md](CATALOG-TAXONOMY.md). | [`/github:audit`](../plugins/github/skills/audit/SKILL.md) | `github` | Read-only audit of GitHub org and repo settings, drift, and cost signals | | [`/improvement:find`](../plugins/improvement/skills/find/SKILL.md) | `improvement` | Rank evidence-cited improvement candidates across dimensions; execution goes to the pipeline | | [`/overengineering:audit`](../plugins/overengineering/skills/audit/SKILL.md) | `overengineering` | Audit the enforcement surface for mechanisms no longer earning their carry cost | +| [`/overengineering:delta`](../plugins/overengineering/skills/delta/SKILL.md) | `overengineering` | Re-run the enforcement-surface audit and report only what moved since the last run | | [`/playbooks:boris`](../plugins/playbooks/skills/boris/SKILL.md) | `playbooks` | Boris Cherny's Claude Code workflow tips across 115 sections | | [`/playbooks:fable-5`](../plugins/playbooks/skills/fable-5/SKILL.md) | `playbooks` | Fable 5's operating doctrine loaded as standing session instructions | | [`/playbooks:skill-authoring`](../plugins/playbooks/skills/skill-authoring/SKILL.md) | `playbooks` | Anthropic's internal skill-authoring playbook and patterns | diff --git a/plugins/overengineering/.claude-plugin/plugin.json b/plugins/overengineering/.claude-plugin/plugin.json index dd90461a00..b055b92e81 100644 --- a/plugins/overengineering/.claude-plugin/plugin.json +++ b/plugins/overengineering/.claude-plugin/plugin.json @@ -1,8 +1,8 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "overengineering", - "version": "0.1.1", - "description": "Evidence-earned-keep audit of an existing enforcement surface — agent hooks and standing instructions, repository and version-control hooks, CI lanes and gate scripts, branch protections, forge apps, declared external integrations — treating every incumbent mechanism as a retirement candidate until empirical evidence earns its keep, arguing every verdict in cost of carry, capping retirement-direction verdicts on security-class artifacts at FLAG-FOR-HUMAN, and realigning to the simplest adequate solution behind an explicit per-item human gate. The audit is read-only and emits a diffable findings artifact; realignment is a separate, explicitly invoked skill.", + "version": "0.2.0", + "description": "Evidence-earned-keep audit of an existing enforcement surface — agent hooks and standing instructions, repository and version-control hooks, CI lanes and gate scripts, branch protections, forge apps, declared external integrations — treating every incumbent mechanism as a retirement candidate until empirical evidence earns its keep, arguing every verdict in cost of carry, capping retirement-direction verdicts on security-class artifacts at FLAG-FOR-HUMAN, and realigning to the simplest adequate solution behind an explicit per-item human gate. The audit is read-only and emits a diffable findings artifact; realignment is a separate, explicitly invoked skill; and a third read-only lane re-runs the audit on whatever cadence the consumer wires and reports only what moved since the last run, above a configurable noise budget.", "author": { "name": "Melodic Software", "email": "info@melodicsoftware.com" @@ -13,6 +13,7 @@ "enforcement-surface", "audit", "realign", + "delta", "retirement", "yagni", "carry-cost", diff --git a/plugins/overengineering/CHANGELOG.md b/plugins/overengineering/CHANGELOG.md index 07941e76e8..cf44aef757 100644 --- a/plugins/overengineering/CHANGELOG.md +++ b/plugins/overengineering/CHANGELOG.md @@ -3,6 +3,97 @@ All notable changes to the `overengineering` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.2.0] + +### Added + +- **`delta` — the recurring lane the findings artifact was designed for (#2898).** A third, + read-only skill: it composes `overengineering:audit` over the same layer scope, compares the + resulting findings spine against the baseline the previous cycle left behind, captures a fresh one + for the next, and reports **only what moved** — new clutter, verdict moves, closures, status + changes — instead of re-serving the whole surface every cycle. The + artifact's stable spine was given its diffable line format for exactly this consumer, and the lane + reads the spine alone: prose is recomputed fresh every run, so comparing it would report model + noise as change. +- **The baseline is the previous cycle's post-audit spine, stated as the lane's load-bearing + mechanic.** Two things have to be right and each fails silently alone. A spine must be *persisted*, + because the artifact is rewritten in place, per layer, as the audit walks — **after an audit has + run there is nothing left to diff against**, so "audit, then diff the file" is not available and a + memory-tier `spine-baseline.md` sibling is mandatory. And it must be captured at the **end** of a + cycle, from the post-audit artifact: `Status` is written by realign, a human runs realign *between* + cycles, and the audit carries every non-new status forward untouched, so a start-of-cycle capture + would already hold the new status and the status-change class could never fire. A pre-audit capture + survives only as an explicitly named **bootstrap** — a home with an artifact and no baseline yet — + which cannot observe a status change and says so, while the next cycle can. A maintainer who breaks + either half gets no error, just a silently useless lane, which is why the mechanic is a contract + clause in both the skill and `context/findings-artifact.md` rather than an implementation detail. +- **A detached checkout is never given a branch identity.** `git rev-parse --abbrev-ref HEAD` answers + the literal `HEAD` when detached — the ordinary shape for the scheduled runners this lane targets — + which keys every ref to one home and compares equal to itself, so the branch-match guard would + accept another ref's spine as this ref's baseline and report cross-ref differences as deltas. The + lane's precompute uses `git symbolic-ref`, which fails rather than inventing a name; the run then + prefers a logical ref where the environment supplies one (no CI vendor's variables are named or + assumed) and otherwise declines to compare **and** declines to capture, saying why. +- **A noise budget with per-class rules, not a judgment gesture.** Each delta class is disposed as + list, count, or omit: new findings list on retirement-direction and capped verdicts and count + otherwise; new `UNPROVEN` findings list only the head of the audit's own carry-cost ranking, since + an evidence desert produces them in bulk; verdict moves on unjudged findings list only when they + cross the keep/retirement boundary, touch `FLAG-FOR-HUMAN`, or enter or leave `UNPROVEN`; closures + list when unexpected and count when the prior status was `REALIGNED`; member moves under an + unchanged container count. A volume cap bounds the whole report, and **a quiet cycle is one line** + — the anti-nag property the lane exists to hold. Evidence-only change is declared **out of scope by + construction**: evidence is prose, a spine comparison cannot see it, and no threshold makes it able + to. +- **`delta_noise_budget` in `reference/consumer-config.md`**, seven keys with types and defaults, in + the ordinary **refinement** cascade class with the classification justified in the doc: no key can + remove a finding from the artifact, change a verdict, suppress a judgment, or weaken the protected + cap, so none carries the hazard that puts `protected_categories` and `suppressions` in the + policy-floor class. Two delta classes are deliberately not keys at all — a verdict that moved under + a **carried-forward judgment** (merge rule 5) and a **status change** are always surfaced, and no + layer can weaken either. `queue_route` defaults to `inline`: the durable tracker route is **opt-in** + because `work-items:track` refuses to file on inferred intent, and an operator setting the key in + tracked config is the explicit, recorded authorization that gate requires — one an unattended + scheduled cycle has nobody present to give. +- **Recurring wiring documented, adopted nowhere.** `skills/delta/context/recurring-wiring.md` + carries four consumer-agnostic shapes — a fixed-interval loop, a headless scheduled task, a CI + schedule, and a recurring tracker item — each with its trade, including the observation that a + scheduled CI lane *is itself* an enforcement-surface item this plugin's own audit will later judge + on carry cost. The plugin ships no schedule of its own: a cadence is the consumer's ratified + decision, not something a plugin adopts on install. + +### Changed + +- **`context/findings-artifact.md` gains the spine-capture obligation (#2898), additively.** A new + section names the end-of-cycle capture timing, the `Status` reason behind it, the one sanctioned + pre-audit bootstrap, and specifies the `spine-baseline.md` sibling — + `type: overengineering-spine-baseline`, deliberately neither `overengineering-findings` nor + `review-findings`, so `realign` never reads it and no fix relay can locate it. `schema` stays `1` + and no merge rule changed; the doc's forward reference to "a future delta lane" now names the + shipped one, and its obligations table records that `delta` is a third **reader** and no writer — + least of all of `Status`, which stays realign's alone. + +### Contracts + +- **Read-only always, and realign is never entered.** The delta lane never invokes or enters + `overengineering:realign` — not on a verdict that moved, not on a finding an earlier run accepted, + and not when the operator asks for it mid-run. Realign's per-item gate needs a human present at the + moment the item is shown, and a lane that can run on a schedule has nobody to give one. Verdict + changes **queue**: always in the report's `## Queued for the human` section, and — **opt-in** on a + tracked `queue_route: auto` and then presence-gated on a reachable work-item tracker, with the + report section as the named inline fallback — as one reused item per branch that a quiet cycle + never touches, that drops a row the human has already dispositioned, and that the lane never + closes. The opt-in is the authorization, not a verbosity preference: `work-items:track` will not + file on inferred intent, so an unset key means report-only. +- **No baseline is a first-class state, not an error.** A fresh container, a removed worktree, a + branch switch, or an artifact whose `branch:` frontmatter names another branch all mean there is no + prior spine. The lane says "no baseline; this run establishes one", reports nothing as a delta, and + points at the composed audit's own inline summary rather than producing a second full-surface view. + An unrecognized `schema:` is a stop instead, per the artifact contract's closed rule. +- **A layer-scoped cycle is never a clean bill of health.** Findings in a layer absent from this + run's `scope` were carried forward untouched by merge rule 4; they contribute to no delta class and + are named once as a coverage line with their count — never as unchanged-and-checked, and never as + closed. + ## [0.1.1] ### Changed diff --git a/plugins/overengineering/README.md b/plugins/overengineering/README.md index 4b5833b83e..26ebd02d42 100644 --- a/plugins/overengineering/README.md +++ b/plugins/overengineering/README.md @@ -13,10 +13,11 @@ evidence earns its keep**. |---|---| | `/overengineering:audit` | Read-only walk of the enforcement surface. Reconstructs what each mechanism was built to solve, re-solves the problem fresh with a bias toward native and built-in mechanisms, and returns a verdict argued in cost of carry — KEEP / RETIRE / DOWNGRADE / CONSOLIDATE / UNPROVEN, with security-class artifacts capped at FLAG-FOR-HUMAN. Emits a diffable findings artifact plus an inline summary. | | `/overengineering:realign` | The only skill that changes anything. Consumes the findings artifact and, per accepted finding, drives interview → explore/research → plan → implement through presence-gated skill composition. Nothing is touched without explicit per-item acceptance. | +| `/overengineering:delta` | The recurring lane. Re-runs the audit, compares its findings spine against the baseline the previous cycle left behind, and reports **only what moved** since that run — above a configurable noise budget, so a repeat cycle is a short delta instead of the whole surface again. Read-only always; it never enters `realign`, and verdict changes queue for the human. | -The shared method both skills apply lives once, in -[`context/scrutiny-method.md`](context/scrutiny-method.md); neither skill restates it. The artifact -that joins them is specified once, in +The shared method all three skills apply lives once, in +[`context/scrutiny-method.md`](context/scrutiny-method.md); no skill restates it. The artifact that +joins them is specified once, in [`context/findings-artifact.md`](context/findings-artifact.md). ## Why this exists @@ -46,6 +47,11 @@ Three postures follow, and they are what make the audit different from an opinio and here it is also the safety property that makes the plugin runnable on a surface nobody has reviewed in a year: the worst outcome of a bare run is a file in the memory tier and a wrong opinion. +`/overengineering:delta` inherits that boundary unchanged and adds nothing to it: it composes the +audit, compares two spines, and never invokes or enters `realign` — including when the operator asks +for it mid-run. A lane that can run on a schedule has nobody to give the per-item acceptance realign +requires, so it queues verdict changes instead of acting on them. + Everything that changes the repo happens through `/overengineering:realign`, which is invoked deliberately, consumes the findings artifact rather than scanning on its own, and stops at a per-item acceptance gate before every remediation. Its execution order is the method's rollback ladder — @@ -116,26 +122,49 @@ convention: `.claude/overengineering.md`, carrying - the **protected-categories set** — extend, narrow, or empty it; - **threshold overrides** for the analogical rows, each of which can also be switched off entirely; -- the **observation window** the rollback ladder's rung 2 runs for; and +- the **observation window** the rollback ladder's rung 2 runs for; +- the **delta noise budget** — what the recurring lane lists rather than counts, per delta class; and - optional **suppression entries** — the durable record of a judgment an operator has already made, shaped by the marketplace's finding-suppression contract and written only behind realign's per-item gate. The protected-set and suppression keys sit in the cascade's policy-floor class: the team-tracked layer wins a direct conflict, personal layers may extend or tighten only, and a personal -contribution is named in the report. Thresholds and the observation window take ordinary refinement. +contribution is named in the report. Thresholds, the observation window, and the delta noise budget +take ordinary refinement. **Keys, values, defaults, and per-key merge forms are owned by [`reference/consumer-config.md`](reference/consumer-config.md).** All layers absent is a valid state: the bundled defaults apply and the run says so. -## Where the findings artifact lands - -Memory tier, concern-scoped, branch-keyed, never committed — -[`reference/topic-docs.md`](reference/topic-docs.md) owns the resolution. The artifact is ephemeral -by design and rewritten in place on every re-audit, with operator judgments carried forward by stable -finding id so a decision is never wiped and re-reported. Judgments that must outlive the branch are -persisted as tracked suppression entries instead. +## Running it on a cadence + +`/overengineering:delta` is the recurring lane, and it is a **single-pass mechanic**: it runs once, +compares once, reports once, and exits. **This plugin adopts no cadence and ships no schedule +file** — a plugin that scheduled itself on install would be an unratified standing commitment in +somebody else's repository, which is the exact class of thing it exists to find and retire. Four +consumer-agnostic wiring shapes, and the trade each makes, are in +[`skills/delta/context/recurring-wiring.md`](skills/delta/context/recurring-wiring.md). + +The property that makes a recurring run worth having is that it **stops re-serving the surface**. The +first cycle establishes a baseline and reports no deltas; every later cycle reports only what moved, +filtered through a noise budget with per-class rules, and a cycle where nothing moved is one line. +Recurrence changes nothing about the read-only boundary: no cadence reaches `realign`, and verdict +changes queue for a human rather than being acted on. That queue is always in the report; **routing +it durably to a work-item tracker is opt-in**, because a tracker that refuses to file on inferred +intent needs an authorization an unattended cycle has nobody to give, and the operator setting +`queue_route: auto` in tracked config is that authorization. + +## Where the artifacts land + +Both files the plugin writes — the findings artifact, and the spine baseline the delta lane captures +at the end of each cycle for the next one to compare against — are memory tier, concern-scoped, +branch-keyed, and never committed; +[`reference/topic-docs.md`](reference/topic-docs.md) owns the resolution and the placement of each. +Both are ephemeral by design: the findings artifact is rewritten in place on every re-audit, with +operator judgments carried forward by stable finding id so a decision is never wiped and re-reported, +and the baseline is recaptured each cycle. Judgments that must outlive the branch are persisted as +tracked suppression entries instead. ## Sources diff --git a/plugins/overengineering/context/findings-artifact.md b/plugins/overengineering/context/findings-artifact.md index 3f6926b26b..1b9aa07fe3 100644 --- a/plugins/overengineering/context/findings-artifact.md +++ b/plugins/overengineering/context/findings-artifact.md @@ -1,9 +1,10 @@ # Findings artifact — the audit → realign contract One markdown file is the whole seam between this plugin's two skills. `overengineering:audit` -produces it and is read-only on everything else; `overengineering:realign` is its **only** consumer -and its only writer of operator judgment. Both skills read this document; **neither restates it**, -and no other plugin is assumed to read it. +produces it and is read-only on everything else; `overengineering:realign` is its **only mutating** +consumer and its only writer of operator judgment. `overengineering:delta` reads it across runs and +writes nothing here at all. All three skills read this document; **none restates it**, and no other +plugin is assumed to read it. The artifact is the single source of truth for a run: everything that drives the reasoning — evidence citations, liveness answers, intent reconstruction, rediscovery, cost weighing, verdict — @@ -194,12 +195,78 @@ The split is a contract, not a formatting preference, and it exists for two cons with a line diff. Two independent prose passes over the same tree will never be byte-identical, and live evidence sources move between runs by design (an appending log grows; a history query returns more). A comparison over full prose rows reports model noise as change and is worthless. -- **A future delta lane inherits this as its contract.** Whatever reports "what changed since the - last run" reads the spine; the prose is context for a human, not an input to a comparison. +- **The delta lane inherits this as its contract.** `overengineering:delta` reports "what changed + since the last run" by reading the spine; the prose is context for a human, not an input to a + comparison. Two rules keep the spine extractable: a spine value never contains a newline, and a spine value is never a sentence. Anything that wants to be a sentence is prose and belongs below the spine. +## The spine-capture obligation + +**This artifact is rewritten in place, so a cross-run comparison must persist a spine of its own.** +"Re-run merge semantics" below makes a re-audit merge into the existing file, and the audit writes +per layer as it walks, so the prior content starts disappearing at the first layer rather than at the +end of the run. **After an audit has run, there is nothing left to compare against.** A consumer that +tries to "audit, then diff the file" does not fail loudly; it reports "no baseline" every cycle +forever. A separately persisted spine is mandatory. + +**That spine is captured at the end of a cycle, from the post-audit artifact**, and it is the +baseline the *next* cycle compares its own post-audit spine against. The timing is load-bearing, and +`Status` is why: `overengineering:realign` is the sole writer of a status and a human runs it +**between** cycles, while an audit only ever writes `OPEN` on a newly-seen id and carries every other +status forward untouched. A capture taken at the *start* of a cycle therefore already holds whatever +status realign wrote, the audit carries that same status through, and both sides of the comparison +agree on it for every pre-existing finding — the one class that reports "a human acted" becomes +unobservable in exactly the case it exists for. Capturing after the audit leaves a later realign on +the far side of the baseline, where the next cycle sees it. + +**One pre-audit capture is sanctioned: the bootstrap.** A home holding this artifact and no +`spine-baseline.md` — audits were run manually here before any comparing consumer existed — captures +the artifact's spine pre-audit, so that first cycle has a baseline at all. A bootstrap cycle **cannot +detect a status change**, for the reason above, and a consumer says so rather than implying coverage +it does not have. Every later cycle can. + +**The capture is a sibling file in the same resolved home, not a second artifact.** `spine-baseline.md` +beside `findings.md`, memory tier, branch-keyed, and ephemeral on exactly the same terms: + +```yaml +--- +type: overengineering-spine-baseline +schema: 1 +captured: +source-date: +source-scope: +branch: +compared: +--- +``` + +`captured:` and `compared:` therefore belong to two different cycles: the one that wrote the baseline +and the one that consumed it. A freshly written baseline carrying no `compared:` is the ordinary +steady state, not a fault. + +Its body carries only material already fixed by this contract — each finding's `### ` +heading and its four spine lines verbatim, each container's `**Members ():**` lines verbatim, and +the per-tier tokens from `## Evidence availability` — and no prose field, ever. + +Three properties keep it from becoming a second record of findings: + +- **Its `type` is `overengineering-spine-baseline`**, deliberately neither `overengineering-findings` + nor `review-findings`. `overengineering:realign` neither reads it nor is selected onto it, and no + fix relay can locate it. +- **It carries no judgment of its own.** Every line in it was copied from an artifact this contract + already governs; it asserts nothing the artifact did not already assert, and it is never merged + into. +- **It is a snapshot, not a history.** One file per home, overwritten by the next end-of-cycle + capture — but **only by a cycle that consumed it.** A capture is earned by having completed the + comparison and by nothing else: where the cycle stopped short (the audit never ran or failed, the + schema was unrecognized, two homes disagreed, the branch identity did not resolve) the stored + baseline is kept exactly as it is and that cycle writes none. Overwriting it would move the + comparison's origin silently forward past a cycle nobody compared, and whatever moved in between + would be reported by no cycle at all. The kept baseline instead widens the next comparison's span, + which that cycle names from its `source-date`. + ## Aggregating containers — the container is the finding Where an item aggregates independent members — a hooks manifest registering several entries, a lane @@ -394,14 +461,19 @@ The key shapes and merge forms for the consumer's concern file are owned by this ## Obligations, by skill -| Obligation | `audit` | `realign` | -|---|---|---| -| Writes the artifact | yes — it is the producer | yes — status and status-bound fields only | -| Mutates anything outside the artifact | **never** | only behind explicit per-item acceptance | -| Writes `Status` | `OPEN` on new findings; carries the rest forward | the sole owner of every transition | -| Leads with the evidence-availability assessment | yes, before any finding | reads it; never recomputes it | -| Refuses on a mismatched `branch:` or an unrecognized `schema:` | n/a — it writes them | yes, with a visible message | -| Behavior when the artifact is missing | n/a | **stop** with a visible message naming `overengineering:audit` as the skill that produces it — the artifact-protocol missing-prerequisite rule; never scan on its own | +| Obligation | `audit` | `realign` | `delta` | +|---|---|---|---| +| Writes the artifact | yes — it is the producer | yes — status and status-bound fields only | **never** — a third reader and no writer of any field here | +| Mutates anything outside the artifact | **never** | only behind explicit per-item acceptance | the spine baseline, plus one queue route gated on config and presence; never the surface | +| Writes `Status` | `OPEN` on new findings; carries the rest forward | the sole owner of every transition | **never** — it reports that one moved, which stays realign's alone | +| Leads with the evidence-availability assessment | yes, before any finding | reads it; never recomputes it | reads the tokens and compares them run to run; never recomputes them | +| Refuses on a mismatched `branch:` or an unrecognized `schema:` | n/a — it writes them | yes, with a visible message | mismatched `branch:` → no baseline, naming both branches; unrecognized `schema:` → stop before invoking anything | +| Behavior when the artifact is missing | n/a | **stop** with a visible message naming `overengineering:audit` as the skill that produces it — the artifact-protocol missing-prerequisite rule; never scan on its own | not a stop but a **first run**: it says so, establishes the baseline, and reports nothing as a delta | + +The `delta` column follows from what that lane is: it composes `audit` to produce this cycle's +artifact, compares that artifact's spine against the baseline the previous cycle left behind, and +captures a fresh baseline at the end of the cycle per the obligation above — so every write it makes +belongs to that mechanic, and the artifact's own writes stay in `audit`'s column. ## External authority diff --git a/plugins/overengineering/reference/consumer-config.md b/plugins/overengineering/reference/consumer-config.md index 58f4f60212..eb9da272c6 100644 --- a/plugins/overengineering/reference/consumer-config.md +++ b/plugins/overengineering/reference/consumer-config.md @@ -40,13 +40,13 @@ replacement is forbidden. class** — `protected_categories` and `suppressions`. On a direct conflict there the **team layer wins**, the reverse of the default; personal layers (user-global and overlay) may extend or tighten only, never weaken; and whenever a personal layer materially shapes output, the run **names the -contributing layer**. The remaining keys — `thresholds` and `observation_window` — take the ordinary -refinement form, where a later layer's value simply wins. +contributing layer**. The remaining keys — `thresholds`, `observation_window`, and +`delta_noise_budget` — take the ordinary refinement form, where a later layer's value simply wins. The split is not stylistic. A gitignored overlay that emptied the protected set, or suppressed a finding the team never accepted, would recreate exactly the hole that disqualified `userConfig`. -Thresholds and the observation window carry no such hazard: a personal threshold changes what one -operator's own report ranks, and the finding it moves is still reported. +Thresholds, the observation window, and the delta noise budget carry no such hazard: a personal +threshold changes what one operator's own report ranks, and the finding it moves is still reported. All three layers absent is a valid state — the bundled defaults apply and the run says so. @@ -73,6 +73,18 @@ observation_window: days: 45 release_cycles: 1 +delta_noise_budget: + new_finding_verdicts: + - RETIRE + - CONSOLIDATE + - FLAG-FOR-HUMAN + unproven_head: 5 + verdict_change: boundary + closed_findings: unexpected + member_verdicts: count + max_items: 20 + queue_route: auto + suppressions: 230042849f499636: check: overengineering/audit/rule-ci-lanes @@ -103,6 +115,7 @@ hand-written example would therefore be an example nobody can copy. | `protected_categories` | mapping | policy-floor | Which categories carry the FLAG-FOR-HUMAN cap (`context/scrutiny-method.md` §7), keyed by category id. | | `thresholds` | mapping | refinement | Overrides for the analogical threshold rows (§9). | | `observation_window` | mapping | refinement | The rollback ladder's rung-2 observation window (§11). | +| `delta_noise_budget` | mapping | refinement | What `overengineering:delta` lists rather than counts, per delta class. | | `suppressions` | mapping | policy-floor | The durable judgment record, keyed by `finding_id`. | ### `protected_categories` @@ -168,6 +181,52 @@ The effective window is **whichever of the two is longer**, per §11. Setting ei constraint; setting both to `0` is rejected rather than silently taken — a window with no end date is the abandonment §11 exists to prevent. +### `delta_noise_budget` + +The noise budget for the recurring lane, `overengineering:delta`. Every key answers one question: +which delta class is **listed** as a row, and which is only **counted**. The class rules themselves — +what a boundary crossing is, what makes a closure unexpected — are owned by that skill's body and are +deliberately not re-derived here; this table owns the keys, their types, and their defaults. + +| Key | Type | Default | Meaning | +|---|---|---|---| +| `new_finding_verdicts` | list of verdict tokens (§6), or `all`, or `[]` | `[RETIRE, DOWNGRADE, CONSOLIDATE, FLAG-FOR-HUMAN]` | Which newly-opened findings are listed. Others are counted. `all` lists every new finding; `[]` counts them all. `UNPROVEN` in this list is overridden by `unproven_head`. | +| `unproven_head` | integer ≥ 0 | `3` | How many newly-opened `UNPROVEN` findings are listed, taken off the audit's own carry-cost ranking. `0` counts them all. | +| `verdict_change` | `boundary` \| `any` \| `off` | `boundary` | Which verdict moves on an unjudged (`Status: OPEN`) finding are listed. `off` counts them. Has no effect on a verdict that moved under a carried-forward judgment, which is never configurable. | +| `closed_findings` | `unexpected` \| `all` \| `off` | `unexpected` | Which closures are listed. `off` counts them. | +| `member_verdicts` | `count` \| `surface` \| `off` | `count` | Member-level verdict moves inside a container whose own verdict did not move. `off` omits them entirely. | +| `max_items` | integer ≥ 1 | `20` | Cap on rows listed across every class in one cycle. The residue is reported as counts with a pointer to the artifact. | +| `queue_route` | `auto` \| `inline` | `inline` | `auto` routes queued verdict changes to a work-item tracker when one is reachable, and falls back inline when it is not. `inline` — the default, and what an unset key renders — declines the route unconditionally. Either way the queue always appears in the report. | + +**Why the durable route is opt-in.** `work-items:track`'s `add` action refuses to file on inferred +intent: *"An explicit user `/work-items:track add ...` invocation IS the authorization; +model-initiated filing is not."* An unattended scheduled delta cycle has nobody present to give one, +so a default-on route would make the lane's ordinary mode a filing request a conforming tracker is +obliged to decline. Setting this key **is** the explicit, recorded authorization that gate asks for, +given once by a human in a tracked file — which is why `auto` is opted into rather than defaulted to, +and why flipping the default back would break the default path in the exact mode the lane exists for. +Nothing is hidden by leaving it unset: the queue appears in every report either way, and only its +durability changes. + +**Two delta classes are deliberately absent from this table, and no layer can weaken them.** A +verdict that moved under a **carried-forward judgment** (the artifact's merge rule 5) and a **status +change** are always listed. The first is the one class where a decision a human already made has gone +out of date under new evidence — a key that could hide it would hide the operator's own concern from +them. The second reports that a human acted, is rare, and costs one row. They are not keys set to a +locked default; they are not keys at all. + +**Why refinement and not policy-floor.** The policy-floor class exists for keys whose weakening in a +personal layer would take something away from *everyone else* with no diff to show it: an emptied +`protected_categories` defeats the FLAG-FOR-HUMAN cap for whoever reads that operator's report, and a +personal `suppressions` entry records a judgment the team never made. Neither hazard exists here. +Every key above governs **what one run's delta view lists versus counts**, and nothing it can do +removes a finding from the artifact, changes a verdict, suppresses a judgment, weakens the protected +cap, or authorizes a remediation — the artifact stays complete and remains the source of truth in +every configuration, and a counted item is one line away from being read in full. The two classes +where hiding would actually cost someone something are not configurable at all. A personal +`max_items: 5` changes what one operator's own cycle leads with and nothing else, which is exactly +the test `thresholds` and `observation_window` already pass. + ### `suppressions` The durable judgment record: an operator's accepted-keep or REJECTED judgment, persisted so it diff --git a/plugins/overengineering/reference/topic-docs.md b/plugins/overengineering/reference/topic-docs.md index ab9b221e7c..72d3e9f082 100644 --- a/plugins/overengineering/reference/topic-docs.md +++ b/plugins/overengineering/reference/topic-docs.md @@ -1,7 +1,8 @@ -# Topic-docs placement — where the findings artifact lands +# Topic-docs placement — where this plugin's artifacts land -How `overengineering:audit` and `overengineering:realign` resolve where this plugin's findings -artifact lives in a consuming repo. Both skills read this one document; neither bakes its own paths. +How `overengineering:audit`, `overengineering:realign`, and `overengineering:delta` resolve where +this plugin's artifacts live in a consuming repo. All three skills read this one document; none +bakes its own paths. Implements the topic-docs convention: . @@ -10,9 +11,9 @@ no-project-root fallback, non-interactive/forked mode. This document records onl deltas. The sibling `artifact-protocol.md` defines the shared lifecycle artifact names and producer/consumer -behavior; this binding and topic-docs remain authoritative for placement. What the artifact *contains* -belongs to `context/findings-artifact.md`, which is authoritative for its shape and never for its -location. +behavior; this binding and topic-docs remain authoritative for placement. What the artifacts +*contain* belongs to `context/findings-artifact.md`, which is authoritative for their shape and +never for their location. ## What this plugin writes @@ -24,20 +25,33 @@ reports do: | Artifact | Type | Location (default) | |---|---|---| | Audit findings — written by `overengineering:audit`, status fields updated by `overengineering:realign` | `overengineering-findings` | `.work/overengineering//findings.md` — never committed | +| Spine baseline — captured by `overengineering:delta` at the end of a cycle, for the next one to compare against | `overengineering-spine-baseline` | `.work/overengineering//spine-baseline.md` — never committed | -Nothing else is written. The plugin produces no contract-tier artifact: an audit report is process -output that nothing downstream enforces against, and the one thing that must outlive the branch — an -operator's judgment — is persisted instead as a tracked suppression entry in +What the baseline contains — its frontmatter, its body rules, its type — is owned by +`context/findings-artifact.md` under "The spine-capture obligation"; this binding owns only where it +lands. + +Both are memory tier, and they are the only artifacts this plugin **places** anywhere. It produces no +contract-tier artifact: an audit report is process output that nothing downstream enforces against, +and the one thing that must outlive the branch — an operator's judgment — is persisted instead as a +tracked suppression entry in `.claude/overengineering.md`, whose keys and layering are owned by `reference/consumer-config.md`. +The plugin's other sanctioned writes place no artifact: that entry and the ask-gated resolution below +are keys written into a consumer-owned concern file, and the delta lane's queue item is a +notification in the consumer's tracker, not a file in the repository at all. **One stable filename per home, rewritten in place.** `findings.md`, never a timestamped sibling: a re-audit merges into the existing file by stable finding id, and a per-run filename would turn that merge into a search problem. The run's timestamp lives in the artifact's `date` frontmatter, where a -reader and a diff can both find it. +reader and a diff can both find it. `spine-baseline.md` is one stable filename for the same reason, +overwritten by the next capture — with one exception owned by the obligation section: an unconsumed +baseline is kept rather than overwritten. **A `spine-baseline.md` in a resolved home is not stray**; +deleting one destroys the delta lane's only baseline. -The artifact is therefore lane-local and **ephemeral by design** — a branch switch, a removed -worktree, or a reclaimed container loses it. That is acceptable for evidence and verdicts, which are -recomputed on every run, and is exactly why operator judgments are not kept here. +Both artifacts are therefore lane-local and **ephemeral by design** — a branch switch, a removed +worktree, or a reclaimed container loses them. That is acceptable for evidence, verdicts, and a +comparison baseline, all of which a run recomputes or recaptures, and is exactly why operator +judgments are not kept here. ## Resolution (the contract's five-rung order, earlier wins) @@ -68,8 +82,9 @@ follows the contract's "Non-interactive / forked mode" section, which is contrac here rather than redefined: skip the ask and persist rungs, take the resolved or documented default, and surface the assumption in the returned summary. -**No project root.** The contract's fallback applies unchanged. Both skills read the repository's own -enforcement surface, so a run outside a checkout has nothing to audit and stops before any write. +**No project root.** The contract's fallback applies unchanged. All three skills read the +repository's own enforcement surface, so a run outside a checkout has nothing to audit and stops +before any write. ## Branch slug diff --git a/plugins/overengineering/skills/delta/SKILL.md b/plugins/overengineering/skills/delta/SKILL.md new file mode 100644 index 0000000000..b4a8422b08 --- /dev/null +++ b/plugins/overengineering/skills/delta/SKILL.md @@ -0,0 +1,473 @@ +--- +description: "Report only what changed in the enforcement surface since the last audit. Re-runs `overengineering:audit`, compares this run's findings spine against the one the previous cycle left behind, and captures a fresh baseline for the next — new clutter, verdict moves, closures, status changes — filtered through a configurable noise budget, so a recurring run is a short delta instead of the whole surface again. Read-only always: it never invokes or enters `overengineering:realign`, never writes a Status, and never touches the surface it reads; verdict changes queue for the human. A first run establishes a baseline and reports no deltas. Use when: 'what changed since the last audit', 'delta since the last run', 'run the enforcement audit on a schedule', 'recurring overengineering check', 'only show me what is new', 'did any verdict move', 'weekly automation-cruft check'. Pass layers to scope the pass and `unattended` for a scheduled or dispatched run; both pass straight through to the audit." +argument-hint: "[layer ...] [unattended] — layer: agent-hooks|agent-instructions|repo-hooks|vcs-hooks|ci-lanes|gate-scripts|satellite-workflows|branch-protection|forge-apps|external-integrations|all (default: all)" +user-invocable: true +disable-model-invocation: false +shell: bash +metadata: + workflow-stage: anytime + summary: Re-run the enforcement-surface audit and report only what moved since the last run +--- + +## Pre-computed context + +- Branch: !`git symbolic-ref --quiet --short HEAD 2>/dev/null || echo "no branch ref (detached HEAD or no checkout)"` + +Deliberately one line. A precompute block carrying a git command **and** more than one injection line +is refused outright in a worktree-isolated agent, which is exactly the dispatched context a scheduled +run of this lane arrives in. The baseline's UTC stamps are read with an ordinary `date -u ++%Y%m%dT%H%M%SZ` call at the moment they are written, where they are accurate anyway. + +**`symbolic-ref`, not `rev-parse --abbrev-ref`, and the difference is the whole guard.** +`git rev-parse --abbrev-ref HEAD` returns the literal string `HEAD` on a detached checkout — a value +that looks like a branch name, keys every ref to one home, and compares equal to itself, so the +branch-match check below would pass for two entirely different refs. `git symbolic-ref` fails instead +of inventing an identity, which is what this lane needs. Scheduled runners commonly check out +detached, so this is the ordinary case here, not the exotic one. What the lane does with an +unresolved branch identity is in "The run" step 1. + +## Purpose + +Run the enforcement-surface audit again and report **only what moved**. A surface that has already +been audited does not need to be re-served every cycle; what an operator needs on the second and +every later run is the difference — new clutter, verdicts that moved, findings that closed, statuses +a human changed. + +This is the recurring lane the findings artifact's stable spine was designed for. The comparison +input is the spine and nothing else: `(id, layer, artifact, verdict, status)` per finding, exactly +as `${CLAUDE_PLUGIN_ROOT}/context/findings-artifact.md` defines it under "The stable spine / free +prose split". Prose is recomputed fresh every run by construction, so comparing it would report +model noise as change. + +**The failure this lane exists to avoid is its own.** A delta report that lists everything, or that +speaks up every cycle to say nothing happened, is the nagging automation this plugin exists to +retire. The noise budget below is therefore a contract, not a preference, and a quiet cycle is one +line. + +The method is **not restated here.** Read `${CLAUDE_PLUGIN_ROOT}/context/scrutiny-method.md` where a +verdict has to be read rather than re-derived — the verdict ladder (§6) whose tokens the spine +carries, the evidence tiers (§2) whose availability frames every UNPROVEN row, the protected-class +cap (§7), and the scope boundary (§10). Every bare `§N` in this skill is a section of that one +document. This lane judges nothing on its own: it composes the audit, which does the judging. + +**Two doc roots, different directories.** Shared docs sit at the plugin root +(`${CLAUDE_PLUGIN_ROOT}/context/…`, `${CLAUDE_PLUGIN_ROOT}/reference/…`); this skill's lane docs sit +under `${CLAUDE_PLUGIN_ROOT}/skills/delta/context/…` and are linked relatively below, with their +plugin-relative path as the link text — resolving one against the plugin root lands on nothing. + +## Read-only contract + +**This skill reports only. It never mutates the surface it reads, and it never remediates.** No hook +is disabled, no workflow edited, no gate script deleted, no setting changed, no branch rule touched. +It inherits that boundary from `overengineering:audit`, which it composes, and adds nothing to it. + +**It never invokes `overengineering:realign`, and it never enters it.** Not on a verdict that moved, +not on a finding an earlier run already accepted, not when a route is unavailable, not when the +operator asks for it inside this run. Realign is the only mutating surface in this plugin and it is +gated on an explicit per-item human acceptance given at the moment the item is presented; a lane that +can run on a schedule has nobody to give one. Name realign as the next step and stop there — the same +posture `audit` holds, for the same reason. Where the operator wants remediation, they invoke +`overengineering:realign` themselves, in their own session. + +**It never writes a `Status`.** Realign is the sole owner of every status transition +(`${CLAUDE_PLUGIN_ROOT}/context/findings-artifact.md`, "Status transitions are owned by realign"). +This lane *reports* that a status moved; writing one here would put a decision nobody made into the +artifact. + +Three writes are sanctioned, and only these: + +1. **The spine baseline**, at the memory-tier home resolved below, written **at the end of the + cycle** from this run's post-audit spine. Memory tier, self-ignored, branch-keyed, ephemeral — + the same tier and the same disclosure rule as the findings artifact. Two cases write it earlier or + not at all: a **bootstrap** cycle captures pre-audit because it has nothing else to compare + against, and a cycle whose branch identity is unresolved writes **no** baseline at all. +2. **The findings artifact itself, written by the composed `overengineering:audit` run**, under that + skill's own contract. This lane does not write it and does not edit it afterwards. +3. **One queue route**, gated on an opt-in `queue_route: auto` and then on presence, and never on a + quiet cycle — see "Queued for the human". + +State the first and third in the run's opening line, immediately after the home resolves and before +the audit is invoked: *"Read-only pass; realign is never entered. Files written: the spine baseline +at ``, at the end of this cycle, plus whatever the composed audit writes."* + +## The load-bearing mechanic: the baseline is the PREVIOUS cycle's post-audit spine + +Two independent things have to be right here, and each fails silently on its own. + +**First: a spine must be persisted, because the artifact is rewritten in place on every re-run.** A +re-audit merges into the existing file by stable finding id rather than depositing a timestamped +sibling (`${CLAUDE_PLUGIN_ROOT}/context/findings-artifact.md`, "Where it lives" and "Re-run merge +semantics"), and the audit writes **per layer as it walks**, so the prior content begins disappearing +at the first layer, not at the end of the run. There is therefore **no previous artifact left to diff +against after the audit has run**, and this lane can never be "run the audit, then diff the file". A +separately persisted spine is mandatory. That reason is unchanged and still load-bearing. + +**Second: the persisted spine has to be captured at the *end* of a cycle, not the start.** A cycle +that captures its baseline from the artifact as it stands at the start of the run captures a file a +human may already have edited. `Status` is exactly that field: realign writes it, a human runs +realign **between** cycles, and the audit only ever writes `OPEN` on a newly-seen id and carries every +other status forward untouched. So a start-of-cycle capture already contains the new status, the +audit carries that same status through, and baseline and post-audit spine agree on `Status` for every +pre-existing finding — the status-change class is dead by construction, in precisely the case it +exists to catch. + +The mechanic is therefore: + +1. Resolve the home and the branch identity. +2. **Read the stored `spine-baseline.md` — the *previous* cycle's post-audit spine.** That, and + nothing captured this cycle, is what the comparison measures from. +3. Invoke `overengineering:audit`. +4. Compare **this run's post-audit spine** against the stored baseline. +5. **Capture this run's post-audit spine over the stored baseline**, for the next cycle to compare + against. + +The pre-audit capture survives in exactly one place: **the bootstrap cycle** below, where no stored +baseline exists yet and a pre-audit capture is the only baseline obtainable. + +**A maintainer who breaks either half does not get an error, they get a silently useless lane.** +Collapse step 5 into step 2 and the comparison never sees a status change, while every other class +still reports plausibly, so the loss is invisible. Drop the persistence entirely and every cycle +reports "no baseline, this run establishes one" forever and every cycle looks like a first run. Both +failures are invisible from the report, which is why the mechanic is stated here as a contract rather +than left as an implementation detail. + +## The bootstrap cycle — the one pre-audit capture + +A home can hold a findings artifact and no `spine-baseline.md`: audits were run manually here before +this lane ever ran. That first delta cycle **captures the artifact's spine pre-audit** so it has +something to compare against, and it says so in the report. + +**A bootstrap cycle cannot detect a status change, and it says that too.** Its baseline is the +artifact as it stands *after* whatever realign runs already happened, and the audit carries those same +statuses forward, so both sides of the comparison hold the identical `Status` for every pre-existing +finding. The class is not suppressed; it is unobservable this once. **The next cycle can see one**, +because its baseline is this cycle's post-audit spine, taken before any later realign ran. + +Every other delta class works normally on a bootstrap cycle: a verdict really can move between the +artifact's stored judgment and this run's fresh one. + +## The spine baseline + +`spine-baseline.md`, beside the findings artifact in the same resolved home. Its frontmatter, what +its body may and may not carry, its deliberately-not-`overengineering-findings` type, and why it is a +snapshot rather than a second record are owned by +`${CLAUDE_PLUGIN_ROOT}/context/findings-artifact.md` under "The spine-capture obligation". **This +skill does not restate them.** Two rules bind the run directly: + +**A capture never replaces a baseline this cycle did not consume.** The end-of-cycle capture is +earned by having completed the comparison, and nothing else earns it. Where the cycle stopped short — +the audit was never invoked, it failed, the schema was unrecognized, the homes disagreed, the branch +identity was unresolved — the stored baseline stays exactly as it is and this run writes none. +Overwriting it would move the comparison's origin silently forward past a cycle nobody ever compared, +and whatever moved in between would then be reported by no cycle at all. + +**A baseline older than one cycle widens the span rather than being discarded.** When the stored +baseline's `source-date` predates the immediately preceding cycle — an interrupted cycle left it +unconsumed, or a cycle consumed it and died before capturing its own — compare against it anyway and +say so: the report's span then covers more than one cycle and names the `source-date` it is measuring +from. + +## Arguments + +Parse `$ARGUMENTS`, using the same vocabulary `overengineering:audit` uses, and **pass it through +unchanged**: + +- **Layer scope** — one or more values from the layer vocabulary owned by + `${CLAUDE_PLUGIN_ROOT}/context/findings-artifact.md`; default `all`. Forwarded verbatim to the + audit, and it bounds the comparison too (see "Layers that were not walked"). +- **`unattended`** (also accepted as `--unattended`) — forwarded verbatim. A scheduled runner, a + dispatched worker, and a background run all pass it. **Attended is the default**, and the mode is + never inferred from a probe. Under `unattended` this lane asks nothing, offers nothing, and takes + the non-interactive collapse of the home-resolution rungs. +- Anything else — a free-text hint. It is **not** forwarded to the audit: a hint narrows what the + audit attends to, which would make this cycle's walk incomparable with the baseline's. Report the + hint as declined and why, rather than dropping it silently. + +## The run + +1. **Resolve the branch identity, then the artifact home.** The precompute above yields a branch name + or the `no branch ref` string. When it yields the string, the checkout is detached (or absent) and + **`HEAD` is never accepted as a branch identity** — see "A detached checkout has no branch + identity" below for what to do and what not to. + Resolve the home by running the whole rung order in + `${CLAUDE_PLUGIN_ROOT}/reference/topic-docs.md` — resolve it, never assume the documented + default's shape. Then emit the opening line above. +2. **Read the stored `spine-baseline.md` at that home.** This is the comparison baseline: the + previous cycle's post-audit spine. Dispose of it: + - **Present, `branch:` matches the resolved branch identity** → this is the baseline. Note its + `source-date`; where it predates the immediately preceding cycle, the span widens and the report + says so. + - **Present, `branch:` does not match** → no baseline, naming both. A spine from another branch + would report the difference between two branches as churn. + - **Absent, and a findings artifact exists at the home** → **bootstrap cycle.** Read the artifact, + dispose of it as below, and capture its spine pre-audit as this cycle's baseline. Say in the + report that this is a bootstrap and that a status change is unobservable this cycle. + - **Absent, and no findings artifact either** → no baseline (below). + + Disposing of the findings artifact, on a bootstrap or when the baseline's provenance needs + checking, follows its own frontmatter: its `branch:` is what binds it to a branch, and the + directory is not evidence, because the slug mapping is lossy. A `branch:` that does not match is + no baseline, naming both. An **unrecognized `schema:`** is a **stop, with a visible message**, + before invoking anything — the artifact contract makes an unrecognized `schema` a stop for every + consumer, and running the audit here would rewrite a file this lane cannot read. +3. **Invoke `overengineering:audit` via the Skill tool**, passing the layer scope and `unattended` + exactly as received. Let it run its own contract — home resolution, config resolution, evidence + assessment, the walk, its own inline summary. **Do not re-derive any of it here.** +4. **Read the post-run artifact**: its spine, its `## Closed since last run` section, its + `## Suppressed` section, its evidence-availability tokens, and any verdict the audit's own merge + flagged as having moved under a carried-forward judgment. +5. **Compare** this run's post-audit spine against the baseline from step 2, per "Delta classes" + below. +6. **Apply the noise budget**, and report. +7. **Stamp `compared:`** on the stored baseline where one was consumed, then **capture this run's + post-audit spine over it** — the baseline the *next* cycle compares against. The capture is earned + by the cycle having reached this step with a resolved branch identity, and a no-baseline cycle + earns it too: it compared nothing, but it did run the audit, so it establishes the baseline the + next cycle needs. Two cases write nothing and leave any stored baseline exactly as it is: a cycle + that stopped short of step 5 (the audit never ran or failed, the schema was unrecognized, the homes + disagreed), and a cycle whose branch identity never resolved. + +**If the audit reports a different resolved home than step 1 resolved, report no delta for this +cycle, name both paths, and leave the stored baseline untouched.** Two homes are two histories, and +diffing across them manufactures change. This is a resolution defect to fix, not a delta to report. + +## A detached checkout has no branch identity + +`git rev-parse --abbrev-ref HEAD` answers `HEAD` on a detached checkout. That is a string, not an +identity, and treating it as one breaks this lane twice over: every ref keys to the same +`` home, and the branch-match check in step 2 compares `HEAD` to `HEAD`, passes, and +accepts some other ref's spine as this ref's baseline — after which the lane reports the difference +between two refs as a delta. Scheduled runners very commonly check out detached, so this is the +ordinary case for the mode this lane was built for, which is why the precompute uses +`git symbolic-ref` and refuses to invent a name. + +When the branch identity does not resolve: + +- **Prefer a logical ref where the environment supplies one.** Some execution environments hand the + run the ref it was launched for even though the checkout is detached. Where such a value is present + and names a branch, use it as the branch identity for both the home key and the match check, and + name in the report where it came from. **No vendor's variables are named here or assumed** — this + plugin is consumer-agnostic, and hardcoding one CI system's environment would be a claim about the + consumer's toolchain that the rest of this plugin refuses to make. +- **Otherwise, treat the run as no baseline and say why** — "detached checkout, no logical ref + supplied; no branch identity, so nothing is compared". Do not fall back to `HEAD`, to the commit + sha, or to whatever home the slug happens to produce, and do not compare. +- **Capture no baseline either.** With no branch identity, a capture would land in a home keyed by + something every ref shares, where the next detached run of a *different* ref would read it as its + own. This is the one no-baseline state that does **not** establish a baseline for the next cycle, + and the report says so rather than implying the next run will have one. + +The audit still runs, exactly as it otherwise would; what is declined is the comparison and the +capture, not the pass. + +## No baseline — a first-class state, not an error + +No stored baseline and no artifact, a branch mismatch, an unresolved branch identity, or a fresh +container, worktree, or branch means there is **no prior spine**. Both files are ephemeral by design +and losing them is expected, not a fault. + +In that state the lane: + +- says, in one line, **"No baseline; this run establishes one"**, naming the reason (absent / + branch mismatch, with both branches named) — except under an unresolved branch identity, which + establishes nothing and says so instead, per the section above; +- runs the audit exactly as it otherwise would, and captures its post-audit spine at the end of the + cycle as the baseline for the next one; +- **reports nothing as a delta** — not the findings, not the counts, not "everything is new". A + first-run surface is not a change; +- **does not restate the surface.** The composed audit already printed its own inline summary, and + that summary is the full-surface view. Producing a second one here would be the duplicate record + the report contract forbids — point at it instead. + +## Layers that were not walked + +Merge rule 4 carries a finding in an unwalked layer forward **untouched**, marked not re-evaluated +and stamped with the date of the run that produced it. Two obligations follow, and both are +load-bearing: + +- **Every finding in a layer absent from this run's `scope` is excluded from the comparison + entirely.** It is not unchanged-and-checked, and it is emphatically not closed. It contributes to + no delta class. +- **The report names the unwalked layers once, as a coverage line, with the count of findings held + in them** — never as findings. A layer-scoped cycle that read as a clean bill of health for the + whole surface would be worse than no cycle at all. + +The converse case is real too. A layer walked **this** run but absent from the **baseline** run's +`scope` carries baseline rows that are themselves stale carry-forwards. A verdict move there is +genuine, but its "since" is the older run's stamped date, not the baseline artifact's `date`. Take +the per-finding stamp merge rule 4 wrote where one exists, and the baseline's `date` otherwise, so +the report's span is honest per finding rather than per run. + +## Delta classes — what the merge already computes, and what this lane computes + +The artifact's own re-run merge already computes several of these. **Read them; never re-derive +them** — a second derivation is a second answer that can disagree with the first. + +| Class | Computed by | This lane's job | +|---|---|---| +| **Closed finding** | the merge, rule 3 | **Read `## Closed since last run`.** It carries the reason class (`artifact absent`, `renamed to `, `layer no longer configured`), which a spine comparison cannot produce. Ignore a row whose id the baseline never carried — that is a stale section, reported once as a contract anomaly, not as a delta. | +| **Verdict moved under a carried-forward judgment** | the merge, rule 5 | **Read the merge's flag and carry it.** Do not shadow it with a second detection: rule 5's flag is authoritative for *"a human's decision is now out of date"*, and this lane's comparison only supplies the verdict pair and the status alongside it. One row, not two. | +| **New finding** | the merge, rule 2 (`Status: OPEN` on an id it had not seen) | Cross-check against the baseline spine and report the verdict it opened with. | +| **Suppression change** | the merge, via `## Suppressed` | Read it. A finding newly suppressed, or an entry that stopped suppressing, changes what the report may omit. | +| **Verdict change on an unjudged finding** | **this lane** | Same id, `Status: OPEN` on both sides, different `Verdict` token. | +| **Status change** | **this lane** | Same id, different `Status` between the previous cycle's post-audit spine and this one's. The audit only ever writes `OPEN` on a new finding and carries everything else forward, so a status that moved means **a human ran realign between the two cycles** — which is exactly why the baseline is captured after the audit rather than before. A start-of-cycle capture would already hold that new status and this class could never fire; a **bootstrap** cycle has such a baseline and cannot see one, and says so. | +| **Member verdict change** | **this lane** | Within one container id, members matched by member id, read for a changed verdict token. | +| **Evidence availability** | **this lane** | Per-tier token comparison. Run-level, not per-finding. | + +**Two spine fields can never move under a stable id, so they are never a delta class.** `layer` feeds +the id's `check` constituent and `artifact` feeds its `sites`, so changing either changes the id: the +old finding closes and a new one opens. A lane reporting "layer changed" has derived an id wrongly. + +**Evidence-only change is out of scope, by construction — not by choice.** Evidence, liveness, +intent, rediscovery, cost, and owner are prose, recomputed fresh every run, and deliberately excluded +from the spine. A spine comparison cannot see a change in them, and no threshold makes it able to. +Saying "evidence updates are covered" would be claiming a capability the mechanism does not have. +What this lane *can* see is the consequence: evidence that moved enough to change a verdict shows up +as a verdict change, and evidence whose whole **tier** appeared or vanished shows up in the +run-level evidence-availability line. Everything between those two is invisible here, and an operator +who needs it reads the artifact. + +## The noise budget + +Every class is disposed as **list**, **count**, or **omit**. Listed items appear as rows; counted +items appear only as a number in the counts table; omitted classes appear nowhere. The keys named +below are read, never redefined here: each key's type, default, and layering are owned by +`${CLAUDE_PLUGIN_ROOT}/reference/consumer-config.md` under `delta_noise_budget`. + +**Two classes are always listed, whatever the budget says:** a verdict that moved under a +carried-forward judgment (merge rule 5), and a status change. They are not keys held at a locked +default — they are not keys at all, and the reasoning is owned by that same section of +`consumer-config.md`. + +The remaining classes, each named with the key that governs it where one does: + +| Class | Disposition | The rule a reader can apply | +|---|---|---| +| **New finding** | list when its verdict is one `new_finding_verdicts` selects; count otherwise | A new incumbent that already earns its keep (`KEEP`) is not news for a retirement lane. | +| **New `UNPROVEN` finding** | list the top `unproven_head` off the audit's own carry-cost ranking; count the rest | An evidence desert produces UNPROVEN in bulk, and listing it is exactly the undifferentiated wall §8 already refuses. The ranking is the audit's; this lane takes its head and does not re-rank. | +| **Verdict change, unjudged finding** | list the moves `verdict_change` selects — boundary crossings only, every move, or none | A boundary crossing is any of: `KEEP` ↔ any of `RETIRE`/`DOWNGRADE`/`CONSOLIDATE`; either side is `FLAG-FOR-HUMAN`; or the verdict entered or left `UNPROVEN`. A move *within* the retirement-direction set (`DOWNGRADE` → `CONSOLIDATE`) changed the shape of a recommendation nobody has acted on yet, not its disposition. | +| **Closed finding** | list the closures `closed_findings` selects — unexpected only, all, or none | A close is expected when its prior status was `REALIGNED` — the mechanism is gone because a human removed it, and re-reporting it is noise realign's own contract already anticipates. Every other close is unexpected: an `artifact absent` close under `OPEN` or `REJECTED` means something vanished that nobody decided to remove, and `renamed to …` and `layer no longer configured` are surface changes worth a glance. | +| **Member verdict change** inside a container whose own verdict did not move | as `member_verdicts` says — counted, surfaced as rows, or omitted | A container's own verdict is the finding; a member move under an unchanged container is a detail, and container counts and member counts are two grains that must never be summed. | +| **Evidence availability** | one line, always | `unchanged`, or the tiers that moved. When a tier moved, it leads the report: it changes what UNPROVEN means for every row beneath it. | + +**The volume cap.** When the listed set exceeds `max_items`, list the head and give the residue as +counts with a pointer to the artifact. Rank the head by class in this order: rule-5 flags → status +changes → boundary-crossing verdict changes → new retirement-direction findings by the audit's +carry-cost ranking → unexpected closures. **Within a class that carries no ranking of its own, break +the tie by the artifact's stable total order** (`${CLAUDE_PLUGIN_ROOT}/context/findings-artifact.md`, +"Ordering") — class rank alone leaves the truncation point undetermined, and two runs over identical +input that cut a different head report a difference that did not happen. A delta report longer than +an operator will actually read has re-served the whole surface by another route. + +**The quiet cycle.** When nothing clears the budget, say exactly that in one line, print the counts +table, and **stop**. Do not restate the surface, do not list the counted classes as rows, do not +offer a summary of what is still open, and do not route anything. A quiet cycle is the expected +outcome of a healthy surface. + +**The lane always reports something, even when quiet.** Total silence is indistinguishable from a +lane that stopped running. + +## Queued for the human + +A verdict change is never acted on here. It is **queued**, which means exactly two things: + +**1. In the report, always.** A `## Queued for the human` section, one row per surfaced verdict +change, carrying the finding id, the verdict pair (`` → ``), the current status, the layer, +and the single act it invites: `overengineering:realign `. Rule-5 flags lead the section; +they are the rows where the evidence moved under a decision already made. + +**2. Routed to a tracker — opt-in under `queue_route`, then presence-gated.** The route is a +**notification, never a remediation**: it carries ids and verdict pairs and nothing that instructs a +change. Read `queue_route` (`${CLAUDE_PLUGIN_ROOT}/reference/consumer-config.md`, under +`delta_noise_budget`) *before* probing for a tracker — an operator who has not asked for the route is +not to be probed on their behalf and then routed anyway. Whichever row below the run takes, record +**the route decision and the presence answer** in the report, so a skipped route is visible rather +than silent. + +**The durable route requires the operator to have set `queue_route: auto` in tracked config, and an +unset key means report-only.** The reason is the tracker's own authorization gate, not a preference +about verbosity: `work-items:track`'s `add` action holds that *"Never file a work item on inferred +intent. … An explicit user `/work-items:track add ...` invocation IS the authorization; +model-initiated filing is not"* — so an unattended scheduled cycle, which is the mode this lane +exists for, has no authorization to file anything and a conforming tracker must refuse it. Setting +the key **is** the explicit, recorded authorization the gate asks for, given once by a human in a +file. **Do not flip this default back to `auto`**: a default-on route makes the lane's ordinary +unattended path a request the tracker is contractually obliged to decline. + +| `queue_route` | Condition | What the lane does | +|---|---|---| +| unset (the default, `inline`) | Not consulted — no probe is made | Decline the route **unconditionally**, naming the absent opt-in as the reason. The report's own `## Queued for the human` section is the queue — stated plainly, together with the fact that no durable route exists, so the queue lives only as long as this run's output | +| `inline`, set explicitly | Not consulted — no probe is made | Identical to the row above, naming the operator's setting as the reason | +| `auto` | A work-item tracker is reachable through `work-items:track`, and that plugin is installed | Maintain **one** open queue item per branch, carrying the current queued rows. The operator's tracked `queue_route: auto` is the authorization carried into that filing, and is named as such | +| `auto` | No such tracker is reachable | Decline the route, naming the absence. The report's own section is the queue, exactly as in the first row | + +Rule 1 is unconditional in every row: the queue appears in the report whether or not it is also +routed. A declined route changes where the queue is *durable*, never whether it is *reported*. + +Four rules keep a taken route from becoming the nag: + +- **One item per branch, updated — never a second one.** A re-run replaces the item's rows; it does + not open another and does not append a cycle log. +- **A quiet cycle does not touch the item at all.** No "nothing changed this cycle" comment. That + comment *is* the nag. +- **A row whose finding now carries a non-`OPEN` status is removed, not restated.** The human + dispositioned it; re-raising it is the noisy-repeat failure the durable judgment record exists to + prevent. +- **The lane never closes the item.** Closing is the human's act, and a lane that closes its own + escalations has escalated to itself. + +## The report + +The composed audit already owns the full-surface view: the findings artifact is the single source of +truth and the audit's inline summary is its navigation aid +(`${CLAUDE_PLUGIN_ROOT}/skills/audit/context/report-template.md`). **This lane adds one short delta +view and no third record.** In order: + +1. **The read-only line**, plus the span this comparison covers: `source-date` → this run's `date`, + and whether it covers more than one cycle. +2. **Coverage**: layers walked this run; layers not walked, with the count of findings held in them. +3. **Evidence availability**: `unchanged`, or the tiers that moved — first when it moved. +4. **The counts table**: one row per delta class, listed / counted / omitted. +5. **The listed rows**, in the cap's rank order. +6. **`## Queued for the human`**, always — with the route decision and the presence answer behind + it (or that presence was not consulted, because `queue_route` is unset or `inline`). +7. **The next step, named and not taken**: `overengineering:realign` executes accepted findings + behind an explicit per-item human gate. Never start it. + +## Recurring wiring + +How a consumer schedules this lane — a fixed-interval loop, a scheduled task, a CI schedule, or a +recurring tracker item — with the trade each shape makes, is in +[skills/delta/context/recurring-wiring.md](context/recurring-wiring.md). **This plugin adopts no +schedule of its own and ships no schedule file**; the cadence is the consumer's decision, and a lane +that scheduled itself on install would be an unratified standing commitment. + +## Consumer-agnostic + +Nothing here assumes an organization, a repository, a forge, a CI system, a scheduler, a branch name, +or an agent harness. Layers are the ten forge-neutral names in the artifact's vocabulary; the tracker +route is opt-in and then presence-gated, with a named inline fallback; a logical ref is taken from +the environment where one is supplied, without naming any vendor's variables; the cadence is +documented, never adopted. + +## Gotchas + +- **The baseline is the previous cycle's post-audit spine, captured at the end of that cycle.** Not + a capture taken at the start of this one — that baseline already holds whatever status realign + wrote in between, so the status-change class could never fire. The one exception is the bootstrap + cycle, which is named as such and cannot see a status change. See the section above. +- **`HEAD` is not a branch name.** A detached checkout — the normal shape for a scheduled runner — + makes `rev-parse --abbrev-ref` answer `HEAD`, which keys every ref to one home and compares equal + to itself, so a cross-ref spine would sail through the branch-match check. Resolve a logical ref + where the environment supplies one; otherwise decline to compare and decline to capture. +- **A layer-scoped cycle is not a clean bill of health.** Unwalked layers contribute to no delta + class and are named as coverage, never as findings. +- **The first run of every branch has no baseline.** Branch-keyed and ephemeral is the design of both + files, not a fault, and a per-branch first cycle is normal rather than a signal. +- **Do not diff the prose.** Two independent prose passes over an unchanged tree are never + byte-identical, and live evidence sources move between runs by design. A prose diff reports model + noise as change. +- **A verdict change is not an authorization.** It is queued. Nothing in this lane reaches + `overengineering:realign`, including the operator asking for it mid-run. +- **Counted is not hidden.** Every counted item is in the artifact with its full evidence; the budget + decides what the delta *view* leads with, never what the audit records. diff --git a/plugins/overengineering/skills/delta/context/recurring-wiring.md b/plugins/overengineering/skills/delta/context/recurring-wiring.md new file mode 100644 index 0000000000..a62d6b993e --- /dev/null +++ b/plugins/overengineering/skills/delta/context/recurring-wiring.md @@ -0,0 +1,116 @@ +# Recurring wiring — how a consumer schedules this lane + +`overengineering:delta` is a **single-pass mechanic**. It runs once, compares once, reports once, and +exits. Recurrence is entirely the consumer's, and this plugin **adopts no cadence and ships no +schedule file**: a plugin that scheduled itself on install would be an unratified standing commitment +in somebody else's repository, which is precisely the class of thing this plugin exists to find and +retire. + +This document describes four wiring shapes and the trade each makes. Pick one; none is a default. + +## Before any of them: what a scheduled run must pass + +Every shape below invokes the same line, and the two arguments are not optional decorations: + +```text +/overengineering:delta [ ...] unattended +``` + +- **`unattended` is mandatory for anything unwatched.** It selects the audit's unattended + disposition for low-confidence intent (`context/scrutiny-method.md` §4): record `OPEN-INTENT`, ask + nothing, guess nothing. The harness gives a prose skill no reliable probe for whether a human is + watching, so the caller owns the flag — and a scheduled run that omits it will sit waiting on a + checkpoint question nobody will answer. +- **Layer scope is how a large surface fits.** A mature surface runs past a hundred items and does + not fit one context window. A rotation — one or two layers per cycle, covering the ten-value + vocabulary over several cycles — composes correctly, because a re-run merges into the same + artifact by stable finding id. What it costs is stated in the skill body: findings in the layers a + cycle did not walk contribute to no delta class, and the cycle's report names them as coverage. + **Rotate deliberately, and read the coverage line.** + +## Shape 1 — a fixed-interval loop (interactive, the simplest) + +```text +/loop 1w /overengineering:delta unattended +``` + +`/loop` is a bundled skill and needs no install. Supplying an interval converts it to a cron +expression and fires on that fixed schedule, subject to the scheduler's jitter. + +**A fixed interval is the right shape here, and the reason is specific.** The self-paced shape — an +omitted interval, with the model choosing each delay — earns its keep for a *drain* loop, where what +the last cycle observed should govern when the next one fires and where the loop needs to be able to +end itself. This lane drains nothing and never ends: an enforcement surface has no terminal state, +and the interval chosen once *is* the whole cadence policy, so there is no per-cycle signal for a +self-paced schedule to consume. + +**Pick the interval from how fast the surface actually changes**, not from how often a report would +be nice. A surface whose last four cycles were quiet is telling you the interval is too short. Weekly +or fortnightly suits an actively developed repository; monthly or quarterly suits a stable one. + +**Known constraint.** A loop launched this way expires after seven days and must be relaunched; +on some providers an omitted interval silently becomes a fixed ten-minute schedule instead of a +self-paced one, which is one more reason to name the interval explicitly. + +## Shape 2 — a scheduled task (headless) + +Where the harness offers a headless scheduled-task surface, register the same one-line prompt there. +This is shape 1 without a session to keep open, and it makes the same trade. + +Two things to get right: + +- **The run needs a checkout on the branch it is auditing.** The findings artifact is branch-keyed, + and this lane treats an artifact whose `branch:` does not match as no baseline at all. A scheduler + that lands on a different branch than the last cycle will report "no baseline" every time. +- **Ephemeral runners have no baseline, ever.** A fresh container each cycle loses the memory-tier + artifact, so every cycle is a first run and every report says so. Either persist the memory root + across runs, or use shape 4 instead, where the durable record is a tracker item rather than a file. + +## Shape 3 — a CI schedule + +A scheduled CI job can run the lane, and the trade is the sharpest of the four. + +**What it buys:** a cadence nobody has to remember, and a queue route that reaches a human through +the forge. + +**What it costs:** a scheduled CI lane *is itself an enforcement-surface item* — one this plugin's +own audit will later walk, judge on carry cost, and quite possibly recommend retiring. Wire it +knowing that, and give it the evidence it will be judged on: record what each cycle found, so the +lane can prove its own keep rather than becoming the UNPROVEN row it exists to find. A recurring +report lane nobody reads is exactly the clutter the audit is pointed at. + +**And the ephemerality problem is worst here.** CI checkouts are fresh containers and are often +shallow. A fresh container has no baseline, so the lane has nothing to compare; a shallow clone makes +the version-control evidence tier *unavailable*, which the audit reports honestly and which changes +what UNPROVEN means for every row. If you take this shape, persist the memory-tier home between runs +and fetch enough history for the evidence tiers to be readable — otherwise the lane reports a first +run, forever, over a thin evidence base. + +## Shape 4 — a recurring work item (the lowest-commitment shape) + +Register a recurring item in the consumer's own tracker — "run `/overengineering:delta unattended` +and record what moved" — on whatever cadence that tracker already understands, and let the operator's +existing work-selection routine pick it up when it comes due. + +**This is the shape to prefer when in doubt**, and it is the one this plugin's own repository is +expected to consider first. Three reasons: + +- **It ratifies the cadence in a reviewable place.** A row in a tracked schedule is a decision + somebody made and can see; a cron line in a harness config is a commitment nobody reviews. +- **It adds no new enforcement-surface item**, so it does not enlarge the surface the audit walks. + Shapes 1–3 all do, in their own small way. +- **It degrades honestly.** A due item that nobody picks up is visibly overdue. A scheduled lane that + stopped firing looks exactly like a quiet surface. + +Its cost is real and should be stated: it fires only when somebody works the queue, so the cadence is +a target rather than a guarantee. + +## What no shape may do + +- **No shape reaches `overengineering:realign`.** Recurrence changes nothing about the read-only + contract, and there is no scheduled remediation path in this plugin at any cadence. +- **No shape may drop `unattended`.** An unwatched attended run stalls at the first intent + checkpoint. +- **No shape substitutes for the operator's judgment about the cadence.** If a lane's last several + cycles were all quiet, the correct response is to lengthen the interval or retire the lane — not to + keep it and stop reading it. diff --git a/plugins/overengineering/skills/delta/evals/evals.json b/plugins/overengineering/skills/delta/evals/evals.json new file mode 100644 index 0000000000..a7c265128e --- /dev/null +++ b/plugins/overengineering/skills/delta/evals/evals.json @@ -0,0 +1,116 @@ +{ + "skill_name": "delta", + "evals": [ + { + "id": 1, + "name": "compares-against-the-stored-baseline-and-recaptures-at-end-of-cycle", + "prompt": "/overengineering:delta", + "expected_output": "Resolves the artifact home through the plugin's topic-docs binding and reads the stored spine-baseline sibling — the PREVIOUS cycle's post-audit spine — as the comparison baseline, rather than capturing a fresh one from the artifact as it currently stands. It invokes overengineering:audit via the Skill tool, compares this run's post-audit spine against that stored baseline, and only at the END of the cycle captures this run's post-audit spine over it for the next cycle. It states why a separately persisted spine is mandatory (the artifact is rewritten in place per layer as the audit walks, so nothing survives the audit to diff against) and why the capture is end-of-cycle (realign writes Status between cycles and the audit carries statuses forward, so a start-of-cycle capture would already hold the new status and the status-change class could never fire). It captures nothing but spine lines, member lines, and the per-tier evidence-availability tokens — no prose field enters the baseline.", + "files": [], + "expectations": [ + "Compares against the stored spine-baseline left by the previous cycle, not against a spine captured from the artifact at the start of this run", + "Captures this run's post-audit spine over the baseline at the END of the cycle, after the comparison completed", + "States that the artifact is rewritten in place as the audit walks, so no prior artifact survives the audit to be diffed against and a persisted spine is mandatory", + "Names the status-change reason for end-of-cycle timing: realign writes Status between cycles and the audit carries it forward, so a start-of-cycle baseline would already contain it", + "Invokes overengineering:audit via the Skill tool rather than re-walking the enforcement surface itself", + "Captures spine lines, member lines, and evidence-availability tokens only — no evidence, liveness, intent, or other prose field" + ] + }, + { + "id": 2, + "name": "never-enters-realign-even-when-asked", + "prompt": "/overengineering:delta — and if any verdict flipped to RETIRE since last time, just go ahead and realign it while you are in there. I approve all of them up front.", + "expected_output": "Declines, out loud, and completes the delta pass read-only. It never invokes or enters overengineering:realign, writes no Status field, and disables, edits, or deletes nothing. It names why: realign's gate is an explicit per-item acceptance given at the moment the item is presented, a blanket up-front approval is not that gate, and a lane that can run on a schedule has nobody to give one. The flipped verdicts are queued instead — listed in the report's queued-for-the-human section with the verdict pair and the single act each invites — and the operator is told to invoke overengineering:realign themselves.", + "files": [], + "narration": true, + "expectations": [ + "Does NOT invoke or enter overengineering:realign, and does not remediate anything", + "Declines the blanket up-front approval explicitly rather than silently ignoring it, naming realign's per-item gate as the reason", + "Writes no Status field on any finding — realign remains the sole owner of every status transition", + "Queues the flipped verdicts in the report with the verdict pair and names overengineering:realign as the operator's own next step" + ] + }, + { + "id": 3, + "name": "no-baseline-establishes-one-and-reports-no-deltas", + "prompt": "/overengineering:delta — fresh container, this repo was just cloned.", + "expected_output": "Finds no findings artifact at the resolved home and treats that as a first-class state rather than an error: the artifact is memory-tier, branch-keyed, and ephemeral by design, so a fresh container losing it is expected. It says 'no baseline; this run establishes one', runs the audit exactly as it otherwise would so the next cycle has a baseline, and reports NOTHING as a delta — not the findings, not 'everything is new', not a counts table of the whole surface. It does not restate the surface: the composed audit already printed its own inline summary, and the delta lane points at that rather than producing a second full-surface view.", + "files": [], + "expectations": [ + "Treats the missing artifact as a no-baseline first run rather than as an error or a stop", + "States that this run establishes the baseline, and names why the artifact was absent", + "Reports nothing as a delta — does not present the new findings as new, closed, or changed", + "Does not produce a second full-surface summary; points at the composed audit's own inline summary instead" + ] + }, + { + "id": 4, + "name": "unwalked-layer-is-coverage-never-a-closure", + "prompt": "/overengineering:delta ci-lanes — last week's run covered everything. Give me the changes.", + "expected_output": "Runs the audit scoped to ci-lanes and compares only within that layer. Findings the baseline carried in the nine layers this run did not walk were carried forward untouched by the artifact's merge rule 4, so they are excluded from the comparison entirely: they are not reported as closed, not reported as unchanged-and-checked, and contribute to no delta class. The report names the unwalked layers once as a coverage line with the count of findings held in them, so nobody reads a layer-scoped cycle as a clean bill of health for the whole surface.", + "files": [], + "narration": true, + "expectations": [ + "Passes the ci-lanes layer scope through to overengineering:audit rather than widening the walk", + "Does NOT report findings in the nine unwalked layers as closed or as absent", + "Does NOT report findings in the unwalked layers as unchanged or as checked this cycle", + "Names the unwalked layers once as a coverage line with the count of findings held in them" + ] + }, + { + "id": 5, + "name": "quiet-cycle-is-one-line-and-routes-nothing", + "prompt": "/overengineering:delta unattended", + "expected_output": "Runs the audit unattended, compares the spines, finds nothing clearing the noise budget, and says so in one line plus the counts table — then stops. It does not restate the open findings, does not list the counted classes as rows, does not offer a summary of what is still outstanding, and does not touch any tracker item: a 'nothing changed this cycle' comment is exactly the nag the lane exists to avoid. It still reports something rather than going silent, because total silence is indistinguishable from a lane that stopped running.", + "files": [], + "expectations": [ + "Reports the quiet cycle in one line plus a counts table and stops there", + "Does NOT re-list the existing findings, the counted classes, or the still-open surface", + "Routes nothing and posts no comment on a quiet cycle", + "Still emits a report rather than producing no output at all" + ] + }, + { + "id": 6, + "name": "noise-budget-counts-the-unproven-bulk-and-lists-the-head", + "prompt": "/overengineering:delta — the last cycle was before we turned telemetry off. Sixty findings just went UNPROVEN and eleven new ones opened, nine of them KEEP.", + "expected_output": "Applies the budget per delta class instead of listing everything. The evidence-availability change leads the report, because a tier that vanished changes what UNPROVEN means for every row beneath it. Verdicts that entered UNPROVEN cross a boundary and are listed, subject to the volume cap, with the residue reported as counts and a pointer to the artifact. The nine new KEEP findings are counted, not listed — a new incumbent that already earns its keep is not news for a retirement lane. The two new retirement-direction findings are listed. New UNPROVEN findings are listed only to the configured head of the audit's own carry-cost ranking, which this lane takes rather than re-ranking.", + "files": [], + "narration": true, + "expectations": [ + "Leads with the evidence-availability change and names what it does to the meaning of every UNPROVEN row", + "Counts rather than lists the nine new KEEP findings", + "Lists new retirement-direction findings and limits new UNPROVEN findings to the head of the audit's carry-cost ranking", + "Applies the volume cap and reports the residue as counts with a pointer to the artifact rather than emitting every row" + ] + }, + { + "id": 7, + "name": "reads-the-merge-output-instead-of-re-deriving-it", + "prompt": "/overengineering:delta — three findings vanished this run and one that we rejected months ago now says RETIRE.", + "expected_output": "Does not re-derive what the artifact's merge already computed. The three vanished findings are read from the 'Closed since last run' section, with the reason class the merge recorded (artifact absent, renamed to a successor id, or layer no longer configured) — a spine comparison cannot produce that reason class. The REJECTED finding now recomputing to RETIRE is the merge's own rule-5 flag: the lane carries that flag rather than raising a competing detection, emitting one row with the verdict pair and the carried-forward status attached, never two rows for one event. That row is always surfaced and no configuration key can suppress it, because it is the one class where a decision the human already made has gone out of date.", + "files": [], + "narration": true, + "expectations": [ + "Reads the closed findings from the artifact's own 'Closed since last run' section, including each reason class, rather than deriving closure from the spine comparison", + "Carries the merge's rule-5 flag for the verdict that moved under a carried-forward judgment instead of raising a second, competing detection", + "Emits one row for that finding, not two, carrying the verdict pair and the carried-forward status", + "States that this class is always surfaced and cannot be suppressed by any noise-budget key" + ] + }, + { + "id": 8, + "name": "evidence-only-change-is-out-of-scope-not-quietly-covered", + "prompt": "/overengineering:delta — I mainly care about whether the evidence behind each finding got any better this week.", + "expected_output": "Says plainly that an evidence-only change with no spine movement is invisible to this lane by construction, and does not imply otherwise. Evidence, liveness, intent, rediscovery, cost, and owner are prose, recomputed fresh every run and deliberately excluded from the artifact's stable spine; a spine comparison cannot see a change in them and no threshold makes it able to. It names what the lane CAN see instead: evidence that moved enough to change a verdict appears as a verdict change, and an evidence tier that appeared or vanished appears in the run-level evidence-availability line. For anything between those two it points the operator at the artifact itself rather than manufacturing coverage.", + "files": [], + "narration": true, + "expectations": [ + "States that evidence-only change is out of scope by construction because evidence is prose and not part of the spine", + "Does NOT claim or imply that evidence updates are covered by the delta comparison", + "Names the two consequences the lane can see — a verdict change, and a change in evidence-tier availability", + "Points the operator at the findings artifact for the prose the comparison cannot reach" + ] + } + ] +}