---
description: "task-pipeline: run a substantial task through a disciplined, gated delivery cycle — an intake grill that expands the request into a checkable requirement list, then docs→brainstorm→spec→plan→build→tests→lint/deploy→post-deploy→docs/wiki→acceptance. Apply when the user asks to 'run this through the pipeline' / 'прогони по конвейеру', asks for 'the full cycle' / 'полный цикл', or starts any substantial feature/fix/build."
alwaysApply: false
---

# task-pipeline — gated delivery cycle (Cursor)

Self-contained rule (Cursor copies this file into projects — no external links).
Run a substantial task through an up-front **intake grill + 10 gated stages**. No
stage advances until its **gate** passes. Each gate is `auto` (verify it yourself,
pass/fail) or `manual` (wait for the user's explicit go).

**No companion skill is required.** Every rule below is the doctrine itself — the
grill, the design gate, the plan format, the build loop and TDD. Nothing to
install, nothing to resolve, nothing that breaks when a plugin is missing.

## Model — decide once, before you start

Recommended: **the most capable reasoning model the environment offers** (at time
of writing, the latest Opus generation — read that as a tier, not a string). Never
hardcode a model id: generations ship, tiers get renamed, and the user may be on a
different provider. Resolve the top tier available at runtime, tell the user what
you recommend and what they're on, let them confirm or override (per-stage
overrides welcome), record the answer — then **stop asking at every stage**. If the
recommended tier isn't available, say which one you're using and continue.

## Pacing — the run mode, and the context budget

Two rules about how a run keeps going. Settle the first at stage 0, in the same
block as the model; the second is unconditional and needs no setting.

**The run mode.** On, the run advances one item per iteration and does not ask
between items — the plan's tasks, the boundary between stages whose gate is
automatic, the per-module loop, the acceptance tail. It stops for exactly four
things: a manual gate, a block it can't resolve, a genuine ambiguity, completion.

- **Off unless recorded.** Read the project's pipeline config → `run.loop`. A
  recorded mode is the answer and is never re-asked; absent, the mode is **off**.
  Silence arms nothing, the same floor deploy authorization uses.
- **It buys pacing, never authorization.** It never collapses a manual gate, and
  never a deploy, publish, PR or shared-design-file write. A generic flag is not a
  specific authorization.
- **Prose does not survive a turn boundary.** Where the harness offers a loop
  primitive, arm it and say the interval, the job id and how to cancel; where it
  does not, the mode degrades to discipline plus the build ledger — and you say
  which of the two you are actually running rather than implying the stronger one.
- **Pick an interval longer than a typical item**, and one that divides its unit
  cleanly. If the job auto-expires, say when: a loop that quietly stops is worse
  than one never armed.
- **Parked at a manual gate, cancel the loop** and print the re-arm command beside
  the gate. A loop firing into a gate every few minutes is a nag, and a nagged
  operator stops reading.

**The context budget.** Near the end of the window: finish the item in flight,
**start no new one**, make the ledgers true, then continue. Compaction is a normal
event, not the end of the run — what loses work is crossing it mid-item.

- **It fires on evidence only:** a harness signal (a compaction warning, a
  pre-compaction hook) or the user saying so. Nothing returns the remaining
  percentage, so an estimate from transcript length is a guess — and announcing
  that context is nearly spent without a signal is presenting a guess as a
  measurement. A run that keeps volunteering it against a mostly-empty window
  trains the user to disregard the one time it is true.
- **Flushing updates what already exists** — the build ledger, the carry-over
  ledger, requirement statuses, the task list. Not a summary written for the
  compactor: that is a fourth copy of the truth that nobody maintains.

## Stage 0 — intake grill (MANDATORY, do this FIRST)

Never skipped, and nothing to install — the grill is part of this rule. No "the
task was already clear" exemption, no starting stage 1 while the user thinks. A
one-line task ("build feature X") is not enough to finish autonomously.

**Phase 1 — harvest the sources BEFORE the first question.** Find what the project
already knows about this task and read it: the code; **the code graph if one is
built** — [graphify](https://github.com/Graphify-Labs/graphify), detect
`graphify-out/graph.json`, and ask it what grep cannot (`graphify query "<the task,
as a question>"`, `graphify affected "<what is changing>"`, `graphify god-nodes`);
`CLAUDE.md` / `AGENTS.md`;
`CONTEXT.md` (or `CONTEXT-MAP.md`) and `docs/adr/`; `docs/` and `docs/ux/`; past
briefs/plans and their carry-over ledgers; **the knowledge wiki if one is
installed** — [obsidian-wiki](https://github.com/ar9av/obsidian-wiki), detect
`~/.obsidian-wiki/config` or a resolving `wiki-query`; and **any other repository
or hosted doc system the project names as its docs** (read-only, and never a source
you invented — it counts because the project names it). Query each by *this task's*
nouns; it is retrieval, not a full read; stop when the terms return nothing new.
Write a short **source ledger** into the brief — source, what it says about this
task, how fresh, and whether this run makes it stale. `none found` is a valid row;
the graph's row carries its **measured lag**, not a build date — run
`git rev-list --count <built_at_commit>..HEAD` and record `N commits / M days behind
HEAD` plus the signal it came from (`built_at_commit` exact, file `mtime`
approximate when the graph carries no stamp, or `unresolvable` when the stamp does
not resolve here), ending in `⚠ not trusted for reach until refreshed` on anything
but `current` — that exact string, so one marker is greppable across every
ledger. A date is the graph's own reply about itself; the lag is the only part
that says whether it describes the tree you are about to change. A graph goes stale
like any other source, and it **points while the code decides** — never the
tiebreaker.
**Read `docs/evidence/retro.md` in full if it exists** — its *standing
instructions* are what previous runs of this pipeline got wrong in this project, and
they bind this run (they are capped at ten, so reading them all is cheap). Stamp
each one the moment it fires: that date is the only evidence behind the
cold-retirement rule at stage 10.
If no wiki is installed, recommend it once and continue:
`pip install obsidian-wiki` → `obsidian-wiki setup --vault <path>`. If no graph is
built, recommend it once and continue: `uv tool install graphifyy` →
`graphify install` → `/graphify .`. Neither is ever a gate.

**Phase 2 — grill the user against that harvest**, then run the rest without
mid-flight questions:
1. One question per turn — never bundle.
2. Give a recommended answer with every question (+ one-line rationale).
3. Explore the codebase before asking — if a search/read answers it, do that.
4. **Validate every answer against the harvest.** When what the user says
   contradicts a doc you read, quote the doc and ask which governs: *"the March ADR
   says X, you just described Y — has it changed?"* The user **outranks every
   document, but only out loud** — an override quoted against its source is a
   recorded decision; an unquoted one is an undetected divergence that every later
   gate will pass over. When two sources disagree: code > host docs/ADRs > wiki >
   memory. Whichever side loses, if it's written down somewhere, log it for the
   stage-9 doc update.
5. Walk the decision tree depth-first; ask prerequisite decisions first.
6. Reconcile contradictions; chase dodges ("decide later" → "latest you can decide
   and still ship?").
7. Run the **autonomy sweep** — resolve now whatever would stop stages 1→10 later:
   external libs and where their docs live; **which doc sources beyond this repo are
   in play and whether stage 9 may write to them**; UI verdict; base branch, branch policy,
   commit convention, task tracker; the test command and what "green" means; the
   lint command; the deploy target, release toggle and **deploy authorization**;
   where logs/health live; which docs and runbooks this change updates. For UI
   tasks also: **is the design done visually (Figma) or text-only, is the Figma MCP
   connected, and if it isn't — ship text-only or stop and connect it?** The UX
   chain degrades to text-only on its own and never blocks, so an unasked question
   there silently ships a UI feature with no mockups. **And with Figma on, settle
   the destination here, never at drawing time: which team/org by name, and which
   file** — the one already recorded, a URL the user gives, or *creation in that
   named team, explicitly authorized*. A file URL says which file, not whose
   workspace, and a design that lands in someone's personal drafts is invisible to
   the people who need it. **Never create a file while a recorded one resolves; if
   it doesn't resolve, stop and ask — never create a replacement**, because "I
   couldn't open it so I made a new one" is how a project ends up with three design
   files and hides a permissions problem at the same time. Write the URL into the
   project's own record (`docs/ux/foundation.md` → Design tooling if the UX chain
   exists, otherwise the repo's `CLAUDE.md`/README) **before the first frame** — a
   file created and then lost to a crashed context is worse than none. Each item
   gets an answer or an explicit "stop and ask me here" — an unasked question is a
   scheduled interruption.

**Domain awareness while you grill.** Look for the project's own docs as you
explore — a root `CONTEXT.md` (or a `CONTEXT-MAP.md` pointing at per-context ones)
and `docs/adr/`. Then hold the user to them: call out terms that conflict with the
glossary ("your glossary defines 'cancellation' as X, you seem to mean Y"), replace
vague or overloaded words with a canonical one ("'account' — Customer or User?"),
stress-test relationships with concrete edge-case scenarios, and surface
contradictions between what the code does and what the user just said. Write
resolved terms into `CONTEXT.md` right then, not in a batch — one tight sentence
per term, aliases listed as "avoid", no implementation detail. Create these files
lazily, only once there's something real to write.

Offer an ADR (`docs/adr/NNNN-slug.md`, 1–3 sentences is a complete ADR) only when
all three hold: hard to reverse, surprising without context, and the result of a
real trade-off. Any one missing → skip it.

**Write the REQ spine before the brief is confirmed.** Turn the request into an
addressable list — one row per independently verifiable deliverable (not one per
sentence), each naming **how it is verified**: a test name, a `file:line`, a command
and its expected output, or a scenario id. *A requirement you can't say how to
verify is a badly-stated requirement* — split it here. Then freeze the list:
adding later is free, **removing or narrowing needs the user's explicit
agreement**. Quietly restating the task in smaller terms is the subtlest way to
lose it — every later gate then passes honestly on a task that shrank.

Seed a **carry-over ledger** next to the brief, append-only. Anything deferred,
dropped, or left half-done goes in the moment it's said — including implementer
concerns and non-blocking review findings. **Deferred out loud is forgotten.**

Read **the verification ledger** — `docs/evidence/verification.md` — and quote how
many rows sit at `never`: that is the project's standing exposure, and stage 0 is where
it is cheapest to look. `never` is a fact, not a failure; the count has no floor and may
never be given a target.

Read **the board** — `docs/evidence/backlog.md`, the project's work-list *between*
runs — and quote its open count in the brief; seed it from the template when absent. Its
priority is **computed, never assigned**: `prio = sev × blast + age_bonus`, with the
three inputs in the row so a ranking can be checked rather than trusted, and `age` moving
on its own is why the re-derivation at an iteration's end is real work. Where the ledger
records what *this run* deferred, the board is what the project still owes.

Stop when shared understanding is reached (every branch answered or explicitly
deferred) and lock the answers into a short brief the user confirms. Only then
start. Later stages read that brief instead of asking again.

**Deploy authorization has a hard floor:** a standing go counts only if it is
specific (named target + named preconditions). A vague "just do everything" does
not authorize an outward, irreversible action — stage 7 stops and asks.

## Stages 1→10

1. **Docs study** (auto) — ground every external lib/API on current docs, not recall.
2. **Brainstorm + decompose** (manual) — read the brief, explore the code, then 2–3
   approaches with a recommendation, YAGNI applied, design presented in sections and
   approved. **Hard gate: no code, no scaffolding before that approval** — including
   on "obviously simple" tasks. Record whether the task touches a user-facing surface
   (UI verdict). **If the brief is a platform, not a change** — several independent
   capabilities or separately shippable surfaces — cut it into modules before any
   spec: modules by capability, never by layer; a module qualifies as a brick only if
   it is independently specifiable, buildable and testable, owns its own entities,
   talks to others through declared contracts only, and can land while leaving the
   system working. Commit a module map (module, delivers, entities owned, depends on,
   contracts exposed, UI?, REQs, status) in build order — the **walking skeleton
   first**, then topologically, no cycles (a cycle means the cut is wrong). Every REQ
   maps to exactly one module. Then stages 3→10 run **per module**, one brick at a
   time; stages 0–2 run once, and the map's status column is the resume point. Single
   module → record "single module: <name>" and move on.
3. **Spec** (manual) — write and commit the design; lock every shared contract
   (types, schemas, signatures, file layout) plus a **Global Constraints** block of
   exact values every later task inherits. Self-review it for placeholders,
   contradictions, ambiguity and scope before showing it. For UI tasks, run the UX
   chain FIRST (see super-ux below) and embed it.
   **Before handing a spec or a plan over, read your rules back:** does every
   check you named actually exist (or say `review`)? does anything here
   contradict a decision already locked, including an option deliberately
   rejected? how many surfaces, guards and requirements is this now versus
   when the design was approved — print all three and let the operator
   decide. Leave the answers as a committed `Self-review` section of
   computed numbers, not ticks.
4. **Plan** (auto) — every task names the REQ ids it `Implements:`, and the set of those ids must **equal** the brief's REQ set — a difference is scope lost, print it and fix it. Zero-context tasks: exact paths, complete code in every step,
   the exact command and its expected output, TDD steps, DoD each, dependency graph
   + parallel groups, non-overlapping file ownership. **No placeholders** — no TBD,
   no "add error handling", no "similar to Task N", no undefined types.
5. **Dev** (auto) — isolate first (existing worktree? native worktree tool? else
   `git worktree` into an ignored dir), baseline tests green, then one task at a
   time: TDD (failing test → watch it fail → minimal impl → watch it pass →
   commit), then a review with **all three** verdicts — spec compliance, **REQ
   satisfied** (judged against the requirement's own statement, not the task's
   instructions), and code quality. Findings loop back to the implementer (max 5
   rounds, then adjudicate in writing); minor findings are recorded, never blocking.
   **After each task reports done, before the review, scan what that task changed
   for the defects an agent leaves behind** — a half-resolved merge, a stub that
   outlived the task, a code fence left open, a file "shortened" while being
   rewritten, a block duplicated by a retried edit, a section opened and abandoned.
   Zero tolerance on a diff: that task wrote it, that task fixes it. A subagent's own
   report is not evidence about the text it left behind, and a duplicated block eight
   tasks later is repaired by an agent that no longer remembers the code.
   Keep a progress ledger in
   a file so a lost context can resume instead of redoing finished work. Tasks in
   the same parallel group run concurrently **only** if each worker has its own
   worktree — otherwise sequential. Close the stage by integrating: sync with the
   base branch, re-run the full suite on the result, merge (or open a PR — that's
   outward, so ask first), remove the worktree.
6. **Tests** (auto) — full suite green (not just new tests); new/changed code
   covered including failure paths; no skip/xfail hiding red. Tests assert real
   behavior, never mock behavior. **Web front end? Check the surface in a browser,
   not in the diff.** A green suite cannot see a component that renders correctly and
   lands under a fixed header, a request that 404s while every unit test mocks it, or
   a console error that costs nothing at test time — and neither can a browser test
   suite, which asserts what someone wrote down and counts as coverage, not as the
   look. With a browser channel connected: load the surface, snapshot it, read the
   console and the network log, and quote what you read. Fix what the look finds
   before calling the stage green. Without one, say "verified by reading the diff" and
   treat that as the weaker claim it is. Two channels, either is enough, ranked by
   nothing: `npm install -D @playwright/cli@latest` (or
   `claude mcp add playwright npx @playwright/mcp@latest`) needs no plugin, and its CLI
   half puts no tool schema in the context window;
   `/plugin install chrome-devtools-mcp@claude-plugins-official` is the one that
   reaches Lighthouse and heap snapshots, and analyses a trace rather than only
   recording one. Never a gate. A CLI, a
   library or a backend service is never offered either.
7. **Lint + deploy** (manual) — lint clean AND suite green before deploy; deploy is
   outward → explicit user go, or the specific standing authorization recorded in
   the stage-0 brief.
8. **Post-deploy** (auto) — tail logs / health-check; clean boot or an honest
   degradation report (never silent success). **A deployed web target is opened, not
   curled** — a `200` proves the server answered and says nothing about a bundle that
   404'd or a console full of errors on load; both ship green past a health check. **Read the CI verdict, never assume
   it** — `gh run list --branch <b> --limit 1 --json databaseId,name,status,conclusion,headSha`,
   then `gh run view <id> --log-failed` on anything but success (unauthenticated
   fallback: `curl -s https://api.github.com/repos/<owner>/<repo>/commits/<sha>/check-runs`).
   Quote the conclusion with its run id, quote the failing step, and state one of
   three states: concluded / in progress (wait and re-read — "it was still running"
   is a report, not a verdict) / **no run found**, said out loud, because a project
   without CI is a legitimate state and not a green one. Probe credentials with a
   live call, never `gh auth status`, which answers from cache. This binds every
   stage that pushes — 7, 8 and 9 — not just this one. It reports; it does not
   block.
9. **Docs + wiki** (auto) — **the phase-1 source ledger is the work list**: every
    source the harvest read gets updated if this run changed or disproved it. Module
    docs and runbooks in the SAME change; the knowledge wiki via `wiki-update` when
    [obsidian-wiki](https://github.com/ar9av/obsidian-wiki) is installed (absent →
    recommend once, never block); **and the code graph via `/graphify . --update`**
    when `graphify-out/` exists (absent → recommend once, never block). The close-out
    has **three** artifacts, not two — the graph is what the *next* run's harvest
    queries first, so a stale one is a false premise carrying the authority of a
    machine: a wrong doc gets argued with, a wrong graph gets believed.
    **Then check the graph against the docs:** a hub `graphify god-nodes` reports
    that no document names is an undocumented seam; an edge the docs deny is either a
    leak in the code or a lie in the docs; a doc naming a module the graph has no
    node for describes something that no longer exists. Fix the doc-side findings
    here; hand absences to stage 10's ladder walk as REQ rows. Never "fix" the graph
    by hand — it is derived: fix the code or the doc and re-extract.
    Docs in **another repository** are outward:
    propose the edit and get an explicit go, or carry it over with the exact change
    written down. A doc that was worth reading at stage 0 and is wrong now is the
    next run's false premise.
10. **Acceptance** (manual) — the closing stage, in two halves.
    **First the ladder walk**, because the REQ table only finds what was named and
    lost: a comparison needs two sides and **an absence has one**. Walk each REQ
    bottom-up through its rungs — recorded decision → spec section → contract *and
    its failure behavior* → plan task with a satisfiable DoD → the change in the
    tree → an **executed** named assertion → the surface a user reaches, and its
    docs, **plus, on UI work designed visually, the frame as a second parallel
    statement of the same surface** — checking the seam between each pair: does the
    decision reach the spec;
    does the section say what happens when the contract fails; does every contract
    have a task; did the DoD land in the diff; would that test still pass with the
    production code deleted; can a user reach this and does a doc say so; and
    finally, does what shipped satisfy the requirement's own *statement* rather
    than the task's instructions. **And for a frame: does it render what the spec
    says, and does what shipped still match it?** A UX linter proves a frame link
    exists, is named right and isn't stale — it cannot read the picture, so a frame
    promising a retention window, a credit meter or a tier nobody built passes
    every lint there is, while being the version stakeholders believe. The spec is
    the contract: say which document you propose to move, don't quietly redraw, and
    remember that editing a shared design file is outward. **Also check the file,
    not just the frames:** deep links are `figma.com/design/:fileKey/…`, so
    comparing each screen link's key against the recorded destination is a string
    match — a differing key is a second design file with real work in it, and
    nothing else notices, because that file is internally consistent and its frames
    are named correctly. Order findings **by seam, not by file** — the seam tells you which layer of your process leaks. Every absence becomes a new
    REQ row with its check **before** the table is written; appending afterwards is
    how acceptance goes green over a gap. Findings owned by a lower layer go back
    there (spec → stage 3, plan → stage 4).
    **Then the table:** one row per REQ, status `verified` / `partial` /
    `deferred` / `dropped`, and every `verified` carries **evidence** — a passing
    test name, a `file:line`, a command and its output. "Done" without evidence is
    downgraded to `partial`, never upgraded, and **a green from a check nobody has
    watched fail against a planted defect is not evidence at all**. Then ask out
    loud, list in hand: *here's what you asked for, here's what shipped, here's
    what's deferred and where it lives — what's missing?* Ask it even when the
    table is green.
    **In a project of several repositories, close the parent too.** A parent records
    each submodule as a **pointer to one commit**, and moving the submodule does not
    move the pointer — so the work is committed, pushed, CI green and done in its own
    roadmap, while anyone cloning the parent gets the commit *before* the change.
    Neither repository looks wrong on its own; the disagreement exists only between
    them, which is why it survives every check that runs inside one. Require this to
    report nothing, for the parent as well as every submodule:
    `git submodule status` (no line starting `+` — a `+` is the missing bump),
    `git -C <repo> status --porcelain`, `git -C <repo> log @{u}..HEAD --oneline`.
    The fix is two commands and the second is the one that gets forgotten:
    `git -C <submodule> push`, then `git add <submodule> && git commit`.
    **The last act is the retrospective** — `docs/evidence/retro.md`, **one file
    per project, not per run**. Every gate above is good at *this* run and blind
    across runs: the same class of failure gets caught, fixed and forgotten five
    times and nothing notices it is the same one. So, in this order —
    **0a. Every REQ this run shipped has a verification row**, and every row names a
    REQ some brief carries — both directions, because a shipped feature that entered no
    ledger and a ledger row about nothing are different failures.

    **0. Resolve the ledger onto the board first.** Every carry-over row still
    `open`, `unresolved`, or homed `backlog` leaves with a `B-NNN` id on
    `docs/evidence/backlog.md`, and the ledger row is updated to name it — both
    directions, because a pointer to an id nobody issued and a board row traceable to
    nothing are different failures. Then re-derive the board's priorities: `age` moved
    while the run was happening.

    **1. Stamp the run first** — date, topic, commit, verdict, counts. It costs one
    line and it is the only thing that makes the next step computable: one retirement
    trigger counts firings across the last five run stamps **or sixty days**, whichever
    comes first, so a prune placed ahead of the stamp reads a counter its own stage
    writes afterwards and can never run on real data. The calendar unit exists because
    the stamp counter only moves when this pipeline runs — ten consecutive releases of
    this repository carry no stamp at all.
    **2. Then prune.** Check every standing instruction against three
    retirement triggers: it became a check (a test, a lint rule, a gate, a hook →
    delete it; the check is the memory, and keeping both means it is read twice and
    obeyed once); every path, command or stage it names is gone (→ delete, it
    describes a system nobody runs); it has not fired in the last **five run
    stamps** (→ delete, that is the evidence it was situational). Then the cap:
    **ten standing instructions, hard** — at eleven the oldest never-fired row goes,
    because "they all matter" is exactly the state in which the list stopped being
    read. **Every deletion writes one line in the log; silent deletion is
    forbidden** — the record stays, the instruction leaves.
    **3. Write an entry, only if the run diverged** — symptom with evidence, the
    stage it *surfaced at*, the stage that **owned** it (usually earlier — a finding
    recorded against the stage that tripped over it comes back), the root cause
    ("the agent was careless" is not a cause, it is the absence of one), the fix by
    grade — **mechanical check > standing instruction (with its retire-when written
    at birth) > a note that expires in two runs** — and the check that catches it
    the first time from now on. A lesson true in any repository belongs upstream in
    the skill's own doctrine, not in one project's file — and where the project has
    opted in (`retro.publish` in its pipeline config, OFF when absent), that lesson
    is opened as an issue on the skill's own repository. The body is printed in full
    before it is sent and the printed string is the sent string; five rules govern
    what may leave — no host paths, no host identifiers, no code or config or data,
    no names, and a title stating the class rather than the incident. Nothing is
    published without that opt-in: an issue in someone else's repository is an
    outward act, and a generic flag is not a specific authorization.
    A retro left empty after a messy run is the failure it exists to stop. Phase 1
    of the next run reads those standing instructions **in full**, which is why the
    cap is not negotiable and the prune is a gate item, not a good intention.
    Gate: ladder walk ran, no REQ `unknown`, no ledger row without
    a home, every repository clean/pushed/pointed-at, user signs off, **and the
    retro is written — stamped first, then pruned before anything was added, at or
    under its cap, every deletion logged, and the counts printed beside this verdict**.

Cross-cutting: answer from the brief's autonomy section rather than re-asking, log every deferral in the ledger, never narrow the task silently, track
tasks, conventional commits, honest degradation (never claim a failed/skipped step
succeeded), and get explicit go before any outward/irreversible action (deploy,
publish, repo create, **editing a shared design file** — frames are read by
designers and stakeholders, so drawing in one is publishing, not local work — and
above all **creating** one, which needs a named team and never happens while a
recorded file resolves).

**Loop guard — break churn instead of iterating.** Every repeating pass (a fix
round, a re-entered stage, the next module) logs one line per touched file: the
file, the pass, and the reason that forced it — a finding id or a failed gate item.
"Cleanup" is not a reason. **Stop immediately** when: an edit undoes what an earlier
pass in this run deliberately did (A→B→A); the same file is edited twice for the
same reason; a finding already fixed or parked comes back; a stage is entered a
third time for one artifact; two loops edit one file. Hard caps: 5 fix rounds per
task, 2 re-entries per stage, 3 passes per module. On a stop: name shape A and shape
B with their evidence and who asks for each; escalate to the layer that owns the
conflict (two findings → the review rubric; finding vs plan → the user; plan vs spec
→ back to planning; ambiguous spec → back to spec; two modules claiming one file →
back to the module map) — **never settle a higher-layer conflict inside a lower
loop**; then re-plan the check as an ordered checklist, one owner and one
verification command per item, and go through it one at a time, one commit per item,
no opportunistic edits. Re-check the list once in the same order at the end. If it
trips again after a re-planned pass, stop and hand back with both shapes, the
evidence and your recommendation.

**Audit rules — for loops that *look* rather than edit.** A searching pass doesn't
oscillate, it **converges**: each pass edits the corpus the next pass reads, so the
newest edits are the least-reviewed text and are what the next pass finds. Measured
over seven passes on a real repository, by pass six the audit was mostly repairing
its own previous pass while the finding count still looked healthy. So:
- **Count two numbers every pass** — new findings, and findings caused by the last
  pass's own fixes. When the second overtakes the first, the axis is exhausted:
  **rotate the axis, don't look harder.** The axes are orthogonal by construction —
  seams down one deliverable (the ladder above), then invariants *across*
  deliverables (one name, one enum, one owner everywhere), then one class swept end
  to end (every error path, every count, every status vocabulary), then — where a
  code graph exists — **the graph against the docs**, the only axis that finds an
  absence without reading for it (a hub no document names, an edge the docs deny, a
  doc naming a module the graph no longer has), then **false success** (not "is this
  check correct" but "what does this mechanism print when it did not look?"), then
  **re-derivation** — a number the audit already produced, produced again by a
  command of a *different shape*, with **both printed**; agreement asserted instead
  of a pair printed is not a re-derivation.
- **Audit bottom-up.** A missing artefact at a low rung makes everything above it
  meaningless; top-down you polish a surface for a contract that doesn't exist.
- **A class that repeats twice becomes a check, not a note.** Once is an incident;
  twice is a category, and a category belongs in lint or CI where nobody has to
  remember it. The third instance in a ledger is how a mechanical defect becomes
  permanent.
- **What can't be fixed now becomes a ratchet, never a TODO** — a named, counted
  set that may only shrink, **printed beside every gate verdict**
  (`carry-over: 4 open (was 6) · unresolved: 0`). A TODO is invisible until someone
  opens the file; a ratchet makes "green" read as *"green, and here is exactly what
  was not looked at"*. If it grew, one sentence says why.
- **Never trust an unproven check.** Plant the defect, watch the check fail, remove
  it, then trust the green — same law as the failing test, applied to every gate,
  linter and script the run leans on.

## Documentation is a deliverable, and it has a gate

**Before the first question (stage 0), answer four things and write them to
`docs/DOCMAP.md`:** where settled things live, what each fact's single home is,
what a change of type X obliges, and what proves it. A project with no answers gets
them seeded — a decision register, an open-questions register and a documentation
gate — and the seeding is recorded as the register's first entry. **One decision
home per project:** an existing `docs/adr/` *is* the register; never create a second
beside it. Then **reconcile intent against as-built** — git says how it should be,
the run record says how it turned out — and resolve every divergence before you
start: the document is stale, the record is wrong, or they genuinely disagree and
that is a decision. There is no fourth option, and starting on an unresolved one
means building against a system that does not exist.

**The Doc Loop fires whenever anything is settled, at any stage — not at the end.**
Seven steps: orient and reconcile → reserve the id, then record → resolve the
question it answers → propagate → adjust scope → record as-built → commit with the
ids in the subject. Reading a "Next free ID" line is **not** reserving it: a second
agent reading it in the same minute gets the same number. Finishing the chat answer
is not finishing the task.

**Registers are append-only.** To reverse: add a new entry, edit **only the status
line** of the old one, leave its body intact. Three distinct markers, because one
word for "adds to" and "replaces a clause of" cannot be enforced: `Refines:` is
additive and the target needs no annotation; `Contradicts:` names a clause that
falls and the target **must** say so; `Supersedes:` retires the whole target and the
target **must** say so.

**The propagation matrix is not the harvest ledger.** The ledger names the documents
you *read*; the matrix names the documents you *owe*. The document nobody read is
exactly the document nobody updated. At stage 9, walk the matrix for every change
type the run produced, then run the documentation gate and print its ratchet counts.

## Gates: three axes, and how to build one that cannot lie

**Axis A — the stage gate type.** `auto` = verify the check yourself and stop on
fail; `judgment` = a named judge rules where no deterministic check exists, and the
ruling is recorded as judgement, never as a measurement; `manual` = wait for an
explicit operator go. Neither of the first two ever substitutes
for a required manual approval.

**Axis B — where the rule is actually enforced**, and a rule climbs this ladder
rather than starting at the top: doctrine line → review question at a named gate →
script check (promote here once the class has occurred **twice**) → CI step → hook.
A rule may sit on several rungs; what it may never do is *pretend* to be on a higher
one — that is the same failure as a gate that prints `FAIL` and exits `0`.

**Axis C — degrees of freedom**, and it is the one that gets skipped. Axis B says how
hard a rule bites; this says how much latitude the *instruction* leaves. **high** —
prose direction, no prescribed sequence, for steps where many routes reach a good
answer. **medium** — a named order with room inside each step. **low** — run exactly
this, in this order, for a step that is fragile, irreversible, or must be identical
every time. Match the level to how fragile the step is, not to how important it feels:
an open field versus a narrow bridge. **Over-constraining costs as much as
under-constraining and is harder to see** — a high-freedom step written as low freedom
produces an agent that follows the letter past the point where the letter stopped
fitting, and reports success, because it did what it was told.

**Before you run any check:** the base is green (or its known-red baseline is
recorded); the check has been probed; you have read its scope header and know what
it does **not** cover; you have read its ratchet floors.

**Anatomy of a gate script:** non-zero exit on any failure; the verdict block last
and **nothing after it**; a SCOPE header; portable (no `grep -P`, no in-place stream
edits, no bash-4 builtins); ratchet floors as variables with the counts printed
beside `OK`; skips printed, never silent; a section with no input yet prints
`dormant` and stays green so a fresh project never starts red; every count computed,
never restated; two-layer mappings checked in **both** directions.

**Probing:** copy the tree, plant the defect **in python** (an in-place stream edit
is not portable and silently edits nothing on BSD), run, assert `$?` is non-zero,
restore, assert zero. **Doubt the probe before the check** — four of five silent
probes on a real project were the probe's fault. Record the probe.

## False success — the failure that removes the reason to look

An actor's own reply is not evidence about the world. A failure is loud and gets
fixed; a mechanism that reports a win it never checked is silent, so it survives
every pass that reads for wrongness. Known shapes: a hook that fails open (any exit
code but 2 is non-blocking, so a crashed guard ALLOWS the action), a cancel that
accepts an id that was never scheduled and returns success, a check asserting the
new value is present instead of the old one being gone, a batch of edits reporting
done while one edit never applied, and a section with no input whose silence is
read as a pass.

Two rules:

1. **Verify by re-reading, not by the reply.** After a teardown, cancel, delete,
   disable, publish or migrate — query the authoritative state and assert the new
   condition.
2. **Assert the absence of the old, not the presence of the new.** A check that only
   proves the new value exists stays green while the old one is still shipping.

The test for any mechanism you are about to trust: what does it print when it did
not look? If that is indistinguishable from what it prints when it looked and found
nothing wrong, it is not evidence.

**In a build:** every step whose effect lives outside your own diff carries a
`verified-by:` line — the command that CONFIRMED the state, not the one that caused
it. A step without one is unverified, not done, and a review rates it Important.

## Hooks — the limit first

Hooks exist **only in Claude Code**. Elsewhere the same rules run as a self-check
and the run is recorded **`ungated`** — never describe a project as protected when
its agents run somewhere else. A `PreToolUse` hook blocks by **exit 2** with the
reason on stderr, or exit 0 with a `permissionDecision: deny` payload on stdout.
**Any other exit code is non-blocking, so a crashing guard fails open** and stops
guarding without announcing it — write the guard to exit 2 on its own errors. Keep
hooks cheap and narrowly matched; the full suite belongs in CI, which is late, and
late is the right trade for slow.

## The retro carries commits

Standing instructions (max ten) carry the commit that introduced them and the commit
of the run in which they last fired; every log entry, every retirement and every run
stamp carries one; and every SHA must resolve. A `file:line` rots at the next edit,
while `git show <sha>` reconstructs the whole incident months later. Entries older
than the last five run stamps **move** to an append-only archive that is *queried*
by the task's nouns rather than read — which keeps the in-force file short enough to
read in full, and makes pruning cost no knowledge.

## Three tracks for user-facing tasks (stage 3)

Three questions, three owners, and none substitutes for another: what the
interface must **do**, how it **sounds**, how it **looks**.

1. **UX track — super-ux (recommended).** If the task touches any UI
   (web/mobile/CLI/TUI), the WHY→UI→scenario chain comes BEFORE interface code:
   foundation (personas, JTBD, customer journey maps, user stories) → flows +
   screens → scenarios (the source of truth) → run its linter. Without the skill,
   still design that chain, get it approved, and trace every user-facing
   requirement to a scenario before building.
   Install: `npx skills add ssheleg/super-ux`.
2. **COPY track — copywriting (super-ux ships it).** Every string a product's
   user reads goes through it, against the brand pack; no pack means running
   brand-init BEFORE the first string, not after. Not through it: commit
   messages, PR text, code comments, developer READMEs, internal docs.
3. **VISUAL track — sheleg-design (recommended).** Tokens and themes,
   typography and rhythm, motion and how it degrades to rest, the Figma boundary
   (tokens as variables, never raw values carried across). Not through it: a
   purely structural change, text, a backend, an internal script.
   Install: `npx skills add ssheleg/sheleg-design`.

**A refusal is a sentence, never a silence.** "as is" ends the visual track and
"draft" ends the copy track; either is the operator's call and costs nothing, but
it is recorded and said out loud in the close-out. A track skipped silently and a
track that ran look identical afterwards.

## Routing — when this applies at all

**Work that LANDS IN THE REPOSITORY goes through the pipeline**, in two shapes: a
**change** — a feature, fix, refactor, migration, integration, rewrite, adoption or
hardening pass — and a **finding that lands** — an audit, a bug hunt, a production
check, a PR review, whose output is REQ rows, board rows and fixes rather than an
answer in the chat. In any phrasing.

**Not** for a question, an explanation, mapping code for a person to read, a typo or a
one-line edit. **Reading is not the test**: an audit, a bug hunt and a PR review all
begin by reading and all three end in the tree. The operator opts out of a qualifying
task by saying "без пайплайна" or "quick"; when they do, say out loud that the cycle
was skipped at their request.

A borderline case is named, not silently chosen: state which route you are taking and
why, in one line.

**Escalation while running.** Decide alone while the cost of being wrong stays inside
the repository and is reversible. Escalate a price, a legal posture, a promise to
somebody outside the team, anything spending money or reputation, and any irreversible
outward act. The tell is the cost of being wrong, not the size of the change.

## The first run in a project

Two entry conditions, and they are different problems.

**A new project:** stage 0 seeds the doc map, the registers and the documentation
gate before the first interview question. The gate is green on day one because
sections with nothing to check yet print `dormant`.

**An existing project:** offer the **entry audit** once — seven passes over the
documentation that already exists, *before* building on it: one decision home,
register integrity, propagation, the matrix's checked-by column, declared terms, the
UX chain, and the gate itself proven against a planted defect. Findings carry
`file:line`, the minimal fix and the **seam**, ordered by seam rather than by file.
It ends in a fix plan and **fixes nothing while reading**.

The step that decides whether adoption survives is **baselining the ratchets at
today**: the propagation floor to the next free id, the residue floor to the measured
count. A gate that is red on adoption day is switched off on day two. History is
**not** back-filled — an old decision enters the register the day somebody is about to
contradict it.

**Portability.** A decision about how the pipeline behaves belongs in the skill; a
decision about what this project decided belongs in the project. The test for a rule
you are about to write down: does it name a path, a command or a person? If not, it is
the pipeline's, and leaving it in one repository is a fork nobody named.

## Writing a propagation matrix — start with the row nobody writes

The most frequent change in any documented project is **adding a document**, and that
is the row people leave out — so the matrix ends up unable to catch the class it will
meet most often. Write it first, before the change types you can think of:

> **A new document or rule** → every surface that must *learn it exists*: the index a
> reader opens, the map, any manifest, the agent-facing rules file. Checked by:
> whatever check can resolve those, or `review` with the reason none can.

Measured on the project this pipeline comes from: nine findings across five audits
were that one missing row, with every check green throughout — a check only walks the
list it was given.
