Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ jobs:
- name: Hook state-machine tests
run: sh plugins/dev-workflow/hooks/codex-gate.test.sh

# Invariants 5 and 6 mechanically, plus BOTH checkers' regression suites. The
# Invariants 5 and 6 plus two prompt-conformance checks, mechanically, and BOTH
# checkers' regression suites. The
# invariant-12 checker itself is not here — it needs a PR base and runs in the
# step below, so naming this step "version bump" would show a green version-bump
# label on a push that was never version-bump checked.
# Each rule was prose first and each was violated anyway — a floating action ref
# shipped in this very workflow, a duplicate hooks manifest key stopped the plugin
# loading in 0.2.1, and the plugin shipped changes without a bump twice.
- name: Invariant checks (pinning, manifest) + both checker suites
- name: Invariant checks (pinning, manifest, prompt conformance) + both checker suites
run: |
sh scripts/check-invariants.test.sh
sh scripts/check-invariants.sh
Expand Down
12 changes: 8 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ todos.md # backlog; `pending` ledger rows point here by
.mcp.json # the Codex reviewer, pinned
.claude-plugin/marketplace.json
.github/workflows/ci.yml # lint + hook tests + invariant checks + validate
scripts/check-invariants.sh # invariants 5 and 6, mechanically (rung 2)
scripts/check-invariants.sh # invariants 5, 6 + prompt conformance (rung 2)
scripts/check-invariants.test.sh # its regression suite — reject/accept pairs
scripts/check-version-bump.sh # invariant 12, mechanically — PR-only (rung 2)
scripts/check-version-bump.test.sh # its regression suite — policy/operational/accept
Expand Down Expand Up @@ -167,8 +167,12 @@ reader can judge whether it still holds.
`docs/hardening-taxonomy.md`, never into the `harden-finding` skill. Otherwise one
project leaks into every other.
11. **Prompt changes pass `docs/prompt-standards.md`** — all 12 checklist items, for
any skill, command, agent definition, hook message, or scaffolded template. The prompts are the
product and nothing mechanical checks them.
any skill, command, agent definition, hook message, or scaffolded template. The
prompts are the product, and **no comprehensive mechanical checker exists for them**:
review is the gate. Two narrow checks in `scripts/check-invariants.sh` cover one
spelling each — a `Target model:` line naming exactly one recognized model in files
claiming conformance, and a prose checklist-count claim matching the checklist — and
they are a floor, not coverage. Every other item is judged by a reader.

## Don'ts

Expand Down Expand Up @@ -231,7 +235,7 @@ Every command below was run in this session and observed to exit 0.
| typecheck | n/a — no typed sources (shell + markdown) |
| lint | `shellcheck --shell=sh plugins/dev-workflow/hooks/codex-gate.sh && shellcheck --shell=sh --exclude=SC2015 plugins/dev-workflow/hooks/codex-gate.test.sh && shellcheck --shell=sh scripts/check-invariants.sh && shellcheck --shell=sh --exclude=SC2015 scripts/check-invariants.test.sh && shellcheck --shell=sh scripts/check-version-bump.sh && shellcheck --shell=sh scripts/check-version-bump.test.sh` |
| test | `sh plugins/dev-workflow/hooks/codex-gate.test.sh` |
| invariant checks (5 pinning, 6 manifest) | `sh scripts/check-invariants.test.sh && sh scripts/check-invariants.sh` |
| invariant checks (5 pinning, 6 manifest, prompt conformance) | `sh scripts/check-invariants.test.sh && sh scripts/check-invariants.sh` |
| invariant check (12 version bump) | `sh scripts/check-version-bump.test.sh && sh scripts/check-version-bump.sh main` |
| build | n/a — nothing is compiled or bundled |

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ honest gap ([reasoning](docs/coding-workflow.md#adapting-it-to-another-project))
CI ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)) runs four checks on every
PR and push to main: `shellcheck --shell=sh` over all three executables and their test
files, the hook's test suite,
[`scripts/check-invariants.sh`](scripts/check-invariants.sh) (invariants 5 and 6) plus
[`scripts/check-invariants.sh`](scripts/check-invariants.sh) (invariants 5 and 6, plus two prompt-conformance checks) plus
both checkers' regression suites, and `claude plugin validate . --strict`.

A fifth check runs **on pull requests only**:
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ README.md, MANIFEST.md, AGENTS.md, CLAUDE.md, todos.md
.mcp.json # the Codex reviewer, pinned
.claude-plugin/marketplace.json
.github/workflows/ci.yml # lint + hook tests + invariant checks + validate
scripts/check-invariants.sh # invariants 5 and 6, mechanically (+ .test.sh)
scripts/check-invariants.sh # invariants 5, 6 + prompt conformance (+ .test.sh)
scripts/check-version-bump.sh # invariant 12, PR-only, mechanically (+ .test.sh)
plugins/dev-workflow/
.claude-plugin/plugin.json
Expand Down
2 changes: 2 additions & 0 deletions docs/hardening-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ escape `\|`, one line), `source` (gate-a|gate-b|bot|manual),
| 2026-07-20 | truncated-tool-output-read-as-complete | Codex Gate A responses arrived cut off on long finding lists — on effectively every substantial pass in real project use — and a cut landing between findings is indistinguishable from a short list, so dropped findings read as a clean review; field agents were improvising a write-to-file workaround per session, which means the failure was handled only when someone happened to notice | manual | major | P std | CLAUDE.md §5 "Findings go to a FILE, not the response" + the same block in the workflow-init inline template: Codex writes the full list to `.context/codex-reviews/<slot>.md` ending `END OF FINDINGS (<n> total)`, replies with one line, and the reader accepts only on terminator-present AND count-matching AND nothing-but-finding-lines AND (for Gate-B `full`) both branch files. Gate B needs one file per branch because `reviewType: full` runs two reviewers in parallel off one additionalContext — a shared path lets the second overwrite the first and still pass every check. What it does NOT do: nothing checks the terminator mechanically (instruction-backed by design; a recurrence is the trigger to build the checker); the hook counts on `PostToolUse` and never sees the file, so an incomplete pass still increments the counter — including a FAILED review, because the pinned `mcp-codex-dev@1.0.1` catches its own errors, executor timeouts and aborts included, and returns `{success: false}` as a normal result rather than throwing, so Claude Code reads it as a successful tool call (an earlier draft of this row inferred from the documented `PostToolUseFailure` split that errors increment nothing — Gate B caught it by reading the server; the rule is now stated without reference to event routing: discount every incomplete pass whatever the counter says); and detection misses a model writing a wrong count with matching lines, or a stale file if the pre-call delete is skipped. Secondary mitigation only, in README: `MAX_MCP_OUTPUT_TOKENS` (25,000 default) moves the ceiling, does not remove it, and does not apply to tools declaring `anthropic/maxResultSizeChars`. Which documented mechanism (token limit vs persist-to-disk threshold) caused the field loss was NOT established; the protocol is correct under either. Fingerprint minted rather than filed under `verification-masks-failure`: that would make this a recurrence on a `1 prose` row, and the skill's recurrence rule then demands a mechanical rung or sharpened AGENTS.md wording, neither of which is P — three Gate-A passes each rejected a different attempt to narrate that gap, which is the class being bent to fit the ladder rather than the defect |
| 2026-07-25 | docs-drift | docs/prompt-standards.md said ad-hoc briefs are not reviewed against "all ten items" while its own checklist runs 1-12 and AGENTS.md invariant 11 independently says 12 — a hard-coded count contradicting the list it counts, in the same file | bot | minor | pending | todos.md § Tooling revalidation, "Prompt-standards conformance checker — resolves two `pending` ledger rows (2026-07-25)". THIRD occurrence of this class, after 2026-07-18 `1 prose` (manifest-claims rule) and 2026-07-18 `P std` (spec-updated-with-fix rule); neither prior rung could reach a stale count, and the ladder's escalation from those is mechanical. The FIX landed in 4f31df2 (PR #12) — what is pending is the HARDENING, not the defect. Deferred by explicit decision: the checker is ~8 lines of shell plus tests, and writing it into a docs-only PR would fire full Gate B on new shell code; it rides the upcoming canvas-findings hardening round instead, which pays that cost anyway. Resolve by appending a rung-2 row referencing this one, never by editing it |
| 2026-07-25 | unverified-enforcement-claim | docs/sparring-briefing.md asserted "This is a prompt artifact and follows docs/prompt-standards.md" while giving its target model as "any capable chat model" — checklist item 1 requires a NAMED executing model plus the author having checked that model's prompting page, and a model class satisfies neither half (there is no single page to check), so the document contradicted its own conformance claim | bot | major | pending | todos.md § Tooling revalidation, "Prompt-standards conformance checker — resolves two `pending` ledger rows (2026-07-25)". THIRD occurrence, after 2026-07-18 `P std` (prompt-standards item 11) and 2026-07-19 `1 prose` (the "never describe what a gate proves" rule, whose own ref states it is human-run, not CI-run, and "raises the floor; it does not close the class"). The class has now cycled P std → 1 prose → recurrence without ever reaching a deterministic rung, and this instance IS tool-decidable — a file claiming to follow prompt-standards must carry a `Target model:` line — which is why the escalation is mechanical rather than a fourth prose rule. The FIX landed in 4f31df2 (PR #12); the HARDENING is what is pending, deferred to the canvas-findings round on the same scope reasoning as the sibling row. Resolve by appending a rung-2 row referencing this one, never by editing it |
| 2026-07-26 | unverified-enforcement-claim | third occurrence, resolved: a prompt asserting it follows docs/prompt-standards.md while naming no executing model — the PR #12 sparring-briefing said `Target model: any capable chat model` | bot | major | 2 lint | scripts/check-invariants.sh check 4a + fixtures in .test.sh. **Resolves the 2026-07-25 `pending` row** (same fingerprint, appended not edited). GUARDED SPELLING, exactly: in a `*.md` file containing the literal `prompt artifact and follows`, the column-zero `^Target model:` line must appear exactly once, its value must BEGIN with a tested token (`Claude\|Codex\|GPT`, portable ERE boundary — token-anywhere is not enough, since the real defect line contained "Claude" as provenance), and it must name exactly one DISTINCT token. STILL INSTRUCTION-BACKED: a bare `Target model: Claude` naming no execution surface passes; a value whose prose is wrong in a way no token test sees passes; a column-zero declaration inside a fenced block counts (no fence awareness in POSIX grep); an unknown future model fails until the token list is extended. BLIND SPOT, stated because it is structural: this ledger is EXCLUDED from the check it records — a ledger that quotes defects self-rejects the checks that detect them, and scanning it would fail the repo forever on rows like this one. OVER-ESCALATION WARNING: `harden-finding` compares fingerprints only, so a later in-class defect OUTSIDE the guarded spelling will be proposed for a stronger rung than anything justifies; that is a proposal a human validates, and this row names the guard so they can judge it. The skill's scope-blind recurrence rule is parked in todos.md |
| 2026-07-26 | docs-drift | third occurrence, resolved: a prose count contradicting the checklist it counts — PR #12's `docs/prompt-standards.md` said "all ten items" while its own checklist ran 1-12 | bot | minor | 2 lint | scripts/check-invariants.sh check 4b + fixtures in .test.sh. **Resolves the 2026-07-25 `pending` row** (same fingerprint, appended not edited). GUARDED SPELLING, exactly: two-stage claim recognition over `*.md` — stage 1 matches `all <digits\|one..twenty>( checklist)? items` with outer word boundaries, stage 2 requires canonical decimal, so `all 012 items` fires as malformed rather than being invisible; every recognised claim must equal N, where N comes from exactly one `^## Checklist([[:space:]].*)?$` heading whose body holds labels forming the contiguous canonical sequence 1..N, in BOTH docs/prompt-standards.md and the workflow-init template, which must agree. Word forms are in scope BECAUSE the motivating occurrence was one — a digit-only check would have sailed past the very defect this row claims to harden. STILL INSTRUCTION-BACKED: counts above twenty in word form, ordinals, hyphenated compounds (`all twenty-one items`), split-line claims, and any count of something other than this checklist. Same ledger blind spot and over-escalation warning as the row above |
Loading