Skip to content
113 changes: 113 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,114 @@ not all of `.context/`, which would strip the committed `codex-gate.on` adoption
merely shares the name (`docs/commands/reference.md`) fires too, which is the
redundant reminder invariant 2 accepts by name.

### Profiles — how much review this story gets

A story may carry a profile in its header: `**Risk:**` (`trivial|standard|high`),
`**Security:**` (`none|standard|high`), and a `**Validation:**` mode derived from them
(`battery` / `battery+check` / `battery+check+verification`, plus `+abuse-path` when and
only when security is `high`). The **story header is the single writable copy** — specs,
plans, commit bodies and this file's prompts carry the story **path** and read the values
fresh at each pass, never a remembered or copied value.

**The axes steer the questions; the mode steers the evidence.** Separate levers: one aims
the reviewer, the other obliges the author.

**Lens sets, appended to the gate prompt:**
- **risk `high`** → threats, abuse, rollback, data loss, idempotency, compatibility,
observability.
- **security `standard` or `high`** → assets, trust boundaries, roles, external systems,
abuse paths.
- **both** → the union appended **once**, each lens labelled with the axis that motivated
it; risk's *abuse* and security's *abuse paths* are **one lens carrying both labels**,
not two questions.

Lenses are **different questions, not more passes.** The 3-pass floor, the Blocker/Major
filter, the file-first findings protocol and the clean-final-pass rule are unchanged.

**Reading the profile — three cases, three answers:**
1. The artifact **cites no story** → run unprofiled and **say so** in the pass. Artifacts
predating this rule are the common case; stopping on them would halt in-flight work.
2. The cited story has **no profile line** → same: today's behaviour.
3. A profile is **present but unresolvable** → **stop and surface the cause**. That covers
the syntactic failures — unparseable line, a value outside the enums, two profile
blocks, a citation resolving to nothing — **and the semantic ones**: a `**Validation:**`
value disagreeing with `max(risk, security)`, or `+abuse-path` present without security
`high` or absent with it. Only the **latest `mode override`** in the log, moving in a
direction compatible with the current value, can explain such a mismatch — and if the
log also contains an `axis change`, only when that override was recorded **after** the
latest one, since an axis change voids every prior override. A log with no `axis
change` at all is the ordinary intake-time override, and its entry resolves the
mismatch on its own. A well-formed value can still be the wrong value, and a stale mode steers
weaker evidence while looking entirely valid; recomputing it is a profile change like
any other — proposed, human-confirmed, logged. Falling back to the lighter behaviour on
a malformed profile would under-review exactly the stories most likely to have one.

**The Gate-B triviality skip needs two independent conditions**, and an eligible profile
never makes a behaviour-changing diff skippable: the change itself is **behaviourally
trivial** (the pre-existing judgement, unchanged by profiles), **and** for a profiled story
`max(risk, security)` is 0 — risk `trivial` *and* security `none`, never risk alone. The
**skip reason is recorded in the commit body** — not in the profile log, which records
profile *changes*, and a skip changes no profile value. **A skip removes the review, never
the evidence**, and what is owed follows the profile: a skipped **profiled** story runs the
battery and lands its evidence entry beside the reason; a skipped **unprofiled** story
records the reason and the battery result and nothing more, because it owes no mode-derived
entry and keeps exactly today's judgement-based skip.

**A cycle citing several stories** aggregates along separate dimensions, never through one
winning mode: the **battery runs once** for the cycle; **each cited _profiled_ story
satisfies its own mode and suffix**, with its own named evidence entry, while a cited
**unprofiled** story has no mode and owes no entry; the **lens sets are unioned** across
all cited stories; and the cycle is skip-eligible only if **every** cited story is. A
single "max" would either under-serve the strictest story or impose its obligations on
unrelated ones.

**What the author owes before Gate B**, by mode: `battery` = the quality battery green ·
`battery+check` = battery + **a check that fails without the change** ·
`battery+check+verification` = battery + that check + a **named** verification of the risk
path · `+abuse-path` = one **named** abuse scenario plus evidence that the expected control
rejects or contains it. Level 2's two obligations are distinct; one artifact serves both
only if it demonstrates both.

A check need not be an automated test — where none is possible, a **named verification**
satisfies it and the entry says which route was taken and why. Either route owes the
**counterfactual**: the observation against the prior state. An **unobservable
counterfactual is a blocking evidence gap**, not a free pass — stop and surface; the human
may then lower the mode as a logged override. A fabricated test satisfies nothing.

**The evidence entry lives in the commit body** (see Mechanics), carries the **story path
and the named evidence but not the mode value**, and is **revalidated before every Gate-B
re-review and before the cycle-closing amend** — a fix changes the diff even when the
profile sits still. If revalidation changes the entry, the clean pass no longer covers what
is being committed: fix, re-review, close on the entry that pass validated.

**Every Gate-B call and re-review carries the path of every cited story**, so the reviewer
reads each profile itself, **plus the current evidence entry, quoted verbatim, for each
cited *profiled* story** — an unprofiled one owes no mode-derived evidence, so it
contributes a path and nothing else. One profiled story means one pair; a cycle citing
several carries all of them, because the reviewer cannot union lenses it cannot see or
judge evidence it was never given. A reviewer handed neither can only review the diff —
the lenses and the evidence obligations would exist and never be consumed.

**Two evidence gaps, two different answers.** Evidence that is *absent or inadequate* for
the mode is a **work gap**: produce it, then call. A project whose `AGENTS.md` names **no
verified quality command** cannot satisfy even `battery` — a **setup gap**: say what is
missing (`/workflow-init`'s battery step) rather than reviewing around it. Neither is a
reason to call Gate B against a weaker claim.

**Changing a profile:** the pass **proposes the complete resulting header** — both axes,
the recomputed mode, any renewed override — and the **human confirms it**, in both
directions; an agent never moves it alone. On confirmation, correct the header and append
one profile-log line. Any axis change **voids every prior override**, raised or lowered,
and `+abuse-path` follows the current security value. Passes already run under the lower
profile **keep counting** toward the floor; only the **final clean pass** must run under
the current profile. Inside an active Gate-B cycle, fold the edit into the active `WIP:`
snapshot by amend — a non-`WIP` commit reads to the hook as the cycle closing and would
discard the accumulated passes.

**What this does not do:** nothing checks which file a model actually read, whether the
header changed mid-call, or whether the lens sets were appended. This is instruction-backed
like the rest of §5; the detection is a reader comparing the pass against the story.

### Mechanics (reference)
- **Severity:** Blocker (wrong/unsafe/breaks invariant) · Major (design flaw →
rework) → both must resolve. Minor · Nit → collect, never iterate.
Expand All @@ -270,6 +378,11 @@ not all of `.context/`, which would strip the committed `codex-gate.on` adoption
follow-up commit for two reasons: a `WIP: …` commit left in history defeats the naming
convention it exists for, and a follow-up commit has nothing to commit when the review
produced no fixes.
**The closing message carries the validated evidence entry for every cited profiled
story** — one each, and none for a cited unprofiled story, which owes no entry. The
amend replaces the WIP message wholesale, so an entry written only into the WIP body is
destroyed exactly when the cycle closes. The final commit body is the durable record;
a PR shows commit messages, so there is no second home to keep in sync.
- **Timeout / abort:** a codex call that dies at the MCP tool-call timeout is retried
once before surfacing to the user, and that retry *is* the single shared recovery
attempt above — not a second one. An abort is an incomplete pass, so treat it as one:
Expand Down
24 changes: 20 additions & 4 deletions docs/coding-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ the actual skills, commands, agent definitions, and hook messages of this plugin
**1. Intake — from idea to story.** The front door turns a raw idea into a scoped
story that captures *what* and defers *how*: the problem, the desired outcome, the
acceptance criteria, which core invariants the change touches, the open questions,
and a rough size. The design ("how") is deliberately left out — it belongs to the
next stage. The value here is a shared, reviewable definition of done before
a rough size, and a **profile** — risk and security relevance, confirmed by the human,
with a validation mode derived from the two. The two axes **add** review lenses at the
gates for a risky or security-relevant change (they never subtract any: Gate A's floor and
the baseline questions are the same at every level), while the derived mode calibrates
what evidence the author owes before Gate B. The design ("how") is deliberately left out —
it belongs to the next stage. The value here is a shared, reviewable definition of done before
anyone argues about approach.

**2. Brainstorming to a spec.** Approaches are explored and decisions are settled
Expand Down Expand Up @@ -119,8 +123,20 @@ checks is not enforcement.
**8. Gate B on the code.** Before the change is committed, the independent
reviewer reads the actual *diff* and checks it against the invariants file. It is
re-run after every fix, because each fix changes the diff and invalidates the
prior review. Genuinely trivial changes may skip it; documentation-only changes
are considered covered by Gate A instead, since there is no code diff to review.
prior review. Trivial changes may skip it, on terms that depend on the story: an
unprofiled one keeps the judgement call, while a profiled one qualifies only at
effective level 0 — trivial risk *and* no security relevance — so a trivial-looking
change on security-relevant surface is not eligible. A skip removes the review, never
the evidence: the battery still runs, the reason is recorded in the commit body, and
so is one evidence entry per cited profiled story. **Explanatory**
documentation carries no gate at all — a wrong sentence there costs a confused reader
rather than broken behaviour. Prompt artifacts are not explanatory prose: in a project
whose product is prompts, the text *is* the behaviour, so the review policy requires Gate
B for them even though they are Markdown. Which paths count is spelled out in the policy
file, and a reminder hook classifies them independently; both err toward firing, and the
hook only reminds — it never blocks, and it is not what makes the review happen. When it
is unclear whether an artifact counts, review it: a redundant pass costs minutes, a
missed one costs the defect this loop exists to catch.

**9. Pull request and bot review.** Automated reviewers comment on the PR. Their
findings are processed *systematically*: pre-existing issues are tracked rather
Expand Down
27 changes: 22 additions & 5 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ answering questions, approving drafts, judging findings.
**1. Capture the idea.** Say "users want to export their invoices as CSV" (or paste
a voice transcript — German is fine). The `intake` skill turns it into a story:
problem, outcome, ≥3 checkable acceptance criteria, which `AGENTS.md` invariants it
touches. Too thin → it asks once and waits; it refuses to invent what you didn't
touches, and a **profile** — how risky this is (`trivial|standard|high`), how
security-relevant (`none|standard|high`), and the validation mode derived from the two.
It proposes both axes and the derived mode with a reason; you confirm or correct the
axes, and any change to the mode is an override that carries its own reason and is
logged. The two axes decide
which extra questions the review gates ask; the derived mode decides what evidence you
owe before Gate B, and the levels **accumulate**: a green battery, then a check that
fails without the change, then a named verification of the risk path on top of both. At
security `high` one more is added — a named abuse scenario and evidence that the control
rejects or contains it. Too thin → it asks once and waits; it refuses to invent what you didn't
say. You approve the draft (the criteria are what "done" will mean), and it lands
as a committed file under `docs/superpowers/stories/`.

Expand Down Expand Up @@ -68,8 +77,12 @@ workflow gets stricter exactly where your project actually fails.

The rhythm: minutes of questions and approval (1–2), two review loops where you
mostly arbitrate (3–4), hands-off implementation (5–6), one more loop (7), PR
close-out (8–9). Trivial changes skip the ceremony — the caution bias is for
non-trivial work, judgment is allowed. Two knobs: `.context/codex-gate.floor` (any
close-out (8–9). Trivial changes travel lighter, within limits: **Gate B** may be skipped
only when the change is behaviourally trivial **and** the story is eligible — a profiled
one at effective level 0 (risk `trivial` *and* security `none`), an unprofiled one by the
prior judgement call. The profile supplies eligibility, never the skip itself; the battery
is still owed and Gate A's floor is unchanged at every level. The caution bias is
for non-trivial work, judgment is allowed. Two knobs: `.context/codex-gate.floor` (any
positive integer) moves the 3-pass floor, and `touch .context/codex-gate.off`
silences the reminders in a scratch workspace (delete to re-enable; state keeps
tracking while off, so nothing goes stale).
Expand All @@ -86,8 +99,12 @@ smallest that matches your intent:

1. **Don't adopt:** never run `/workflow-init` in a project → the plugin does
nothing there.
2. **One trivial change:** just commit — the hook warns, it never blocks, and §5
explicitly leaves trivial changes to your judgment.
2. **One trivial change:** the hook warns, it never blocks. What §5 permits depends on
the story: an **unprofiled** one keeps the old judgement call, while a **profiled**
one may skip Gate B only at effective level 0 (risk `trivial` *and* security `none`),
still owes the battery, and records both the skip reason and its evidence entry in the
commit body. Gate A is not
skippable at any level.
3. **Pause a project:** `touch .context/codex-gate.off` (delete to re-enable;
state keeps tracking, so nothing goes stale).
4. **Leave for good:** remove §5 from the project's `CLAUDE.md` (and
Expand Down
Loading