Conversation
wp0 docs-only roadmap unit. The gate requires from/to before any other check (attest.ts:91-96); the skill table agents copy (pabcd/SKILL.md:91-98) names neither, nor planUnit, workPhaseId, or testReceiptPath. 50+ historical failures across four repos. Audited by an independent grok-4.6 lane: GO-WITH-FIXES, 4 blockers folded. Blocker 1 disproved this plan's own claim that the parser cannot name the edge - argv[0] is the verb and runOrchestrateCli already reads state on that path.
The refusal 'attest JSON missing valid from/to' has 50+ occurrences across opencodex, ima2-gen, cli-jaw and codexclaw since 2026-08-13, and the cause was not the gate. coerceAttest rejects an attest without from/to before any other check runs, while the table agents copy (pabcd/SKILL.md) listed neither those keys nor planUnit, workPhaseId, or testReceiptPath - so a bound P>A cascaded through three separate refusals, each costing a turn. Docs: the attest table now names every key each edge requires, with four copy-paste objects, under a citable ATTEST-SHAPE-01. The interview override examples and the doctrine's invalid-JSON snippet carry from/to. loopArmDirective and cxc orchestrate --help gained the P>A object, a B>C example, and testReceiptPath; PA_ATTEST_EXAMPLE is one constant so the win32 and posix branches cannot drift. Runtime: the null-coerce refusal now names the real edge. An audit disproved the plan's claim that the parser cannot know it - the verb IS 'to', resolved before the attest loop, and the error path already reads session state for 'from'. It forward-declares only the keys for that edge, not a menu, and a malformed-JSON error keeps its own diagnosis with no misleading example. Also fixes the same defect family found while inventorying: buildGoalIdleBlock emitted 'evidence' where the schema says 'did' (silently, since IDLE>P is ungated); review-round, plan, metric and divergence rejected --help; and cxc freeze --help fell through to the real run, writing freeze.json and exiting 0 with nothing to signal the mutation. The freeze test asserts the filesystem, not the wording, because a help text that still writes would pass a text check. npm test 1980 pass / 0 fail (was 1961). The new assertions were verified to FAIL against the pre-fix behavior - the first draft asserted the message 'contains from and to', which the original bare string already did.
…ghbours An independent review of 49d90e6 found the first pass had shipped a bug of the same family it was fixing. 1. The hint printed the current phase as 'from' even when the requested edge was illegal, so an agent at P asking for D was handed {"from":"P","to":"D"} - an object that clears the coerce gate and is then refused for adjacency. Two wrong refusals instead of one. An illegal edge now names its legal routes and deliberately shows no example, because every example would be rejected. 2. Renaming buildGoalIdleBlock's 'evidence' key to 'did' had replaced the closing backtick with a backslash, so both platform branches emitted an unterminated span and a trailing backslash. The test asserts balanced backticks and no trailing backslash, not the wording. 3. STOP_NEXT_COMMAND - the block agents copy verbatim - still omitted planUnit on P>A, workPhaseId on every gated edge, and testReceiptPath on C>D. Bound keys are shown with a marker rather than omitted: a key you must delete is cheaper than a key you never knew existed. 4. interview/SKILL.md:147 still taught {"override":true}. It is valid JSON, so it fails as missing from/to - the confusing case, at the exact moment a stuck agent reaches for the escape hatch. Also: the bound-session note no longer claims testReceiptPath on A/B/C, two weak assertions the reviewer flagged as passing pre-fix were made positive, and the Stop, goal-idle, and arming surfaces gained the coverage they never had. npm test 1985 pass / 0 fail.
…st drift Top-level help listed neither receipt, review-round, nor scan while telling agents to run '<cmd> --help', so the producer of a bound C>D's testReceiptPath was undiscoverable from the entry point. It now lists all three and states the attest shape in the agent notes. orchestrate-grammar's parser carried the old bare string. The chat surface discards attestError today, so this is not yet user-visible - but two parsers disagreeing is how the next reader concludes one of them is authoritative. loop/SKILL.md points at the pabcd table instead of paraphrasing it, per the canonical-owner rule the repo already applies to DEV-STACK-*. The drift test is the part that outlives this unit: it parses the attest table's KEYS cell out of pabcd/SKILL.md and asserts each gated row names what that edge's gate requires. Its first version read the whole row and passed against injected drift, because the Notes column happened to mention planUnit - so the capture was narrowed to the contract cell and re-verified by deleting planUnit from the P>A row and watching it fail. npm test 1987 pass / 0 fail.
DEVOPS-RELEASE-PROOF-01 governs the proof bundle for an artifact already published. It says nothing about the decision to publish, which is where the v2.32.1 hotfix train actually got into trouble: a freeze audit rejected the first GO report on three counts, and the operator-visibility train that followed added two more lessons of the same shape. New SKILL.md 2.8 (GO/NO-GO decisions, STRICT): FREEZE-SHA (pin the report to the code SHA its gates describe), GATE-WEAKEN (a red gate is never excused inside the report it failed), REVIEW-THREADS (unresolved threads on merged PRs block GO, counted after merge), GATE-OWNER (a gate with no implementing phase is a wish). ci-cd-deploy.md 6 (evidence mechanics): SUITE-PARTITION (replay CI's real partition; a one-process run is not the gate), BASELINE-DEFECT (a red test is a candidate defect until baseline + blast radius + CI job all agree), VERIFY-INSTRUMENT (do not change the instrument while certifying with it), EXACT-HEAD (re-read the head; a remembered pass is not evidence), FLAKE-STABILITY (N greens at one head; declare N). sre-foundations.md 7 (runtime evidence): STALE-PROCESS (prove a live process is the build under test - a canary once measured the reporter's own pre-fix proxy), OBS-SIGNAL (add the missing signal; never flip a true status bit to compensate). Each rule is defined in exactly one file, cited to the devlog that produced it, and FLAKE-STABILITY points at dev-testing for remediation rather than restating it - that policy is wp3's. npm test 1987 pass / 0 fail (docs-only; the assertion is that nothing moved).
The repo believed the right thing in seven places and the wrong thing in three. dev-testing/SKILL.md:77 said a flake is a bug and green-on-retry is unacceptable; :220 said never blind-retry; :218 then made the protocol 'detect -> quarantine if blocking'. An agent could not follow both. ci-pipeline.md repeated the quarantine protocol as its own section 5 heading, so the router and the deep reference both claimed to own it - with different strength, the router's being weaker (it had no removal deadline). ci-pipeline.md section 5 is now the canonical TEST-FLAKE-* policy, following the DEV-STACK-* pattern the repo already uses: - ELIMINATE-01 (STRICT): a flake is closed when the cause is named, not when the suite is green. The signal table now names causes to remove, not first-aid. - RERUN-01 (STRICT): re-running to green is not a fix and is never recorded as one; raising a timeout to pass is the same violation. A re-run may measure the failure RATE, and the measurement gets written down. - QUARANTINE-01 (DEFAULT): permitted only when the flake blocks unrelated delivery, and only with test name, owner, removal deadline, and suspected cause recorded together. The exception is deliberate - a policy with no usable hatch relocates the pressure into an untracked .skip(), which is worse. - ATTRIBUTION-01 (DEFAULT): 'environmental' needs the same triple DEVOPS-BASELINE- DEFECT-01 requires. This is the rule the repo did not have: every existing line said do not HIDE a flake, none said how to PROVE it is not your defect. dev-testing/SKILL.md 5.4 and dev-debugging Scenario D are now pointer stubs, skill-ownership.md gains the row whose absence let the policy drift into two files, and C10 in the contradiction register no longer offers 'an explicit timeout' as a candidate fix - RERUN-01 forbids exactly that. No test was touched. This repo's suite is 1987/0 green and the pabcd-state slice runs identically twice; there is no flake here to eliminate, and the policy is written for the repos this skill governs.
An independent review checked every historical claim in 3d5d0d3 against the opencodex devlogs. Three did not survive, and they were mine, not the sources': - STALE-PROCESS said a train 'ran a 100-call canary' whose numbers described the bug. The devlogs record the opposite: the canary was a GO criterion that got REJECTED as the wrong instrument once PID 922 was identified as the reporter's pre-fix proxy, and a deterministic mixed-sequence regression replaced it. The measurement never happened - which is the better version of the lesson, because the identity check came first. - FLAKE-STABILITY said 'run 1 was green, run 2 failed, run 3 produced the finding'. The recorded table is green, green, fail. And 'OpenCodex used three' greens was wrong twice over: three was the bar they SET, and they never collected it, which is why the PR was deferred. - SUITE-PARTITION said three files, each in its own job. It is three path patterns (seven files) covered by two jobs - storage policy runs six together, api usage runs one. That loose wording came from the source report; copying it into a STRICT rule made it load-bearing. Also: the router pointed at ci-cd-deploy.md 9 and sre-foundations.md 6, neither of which exists - the rules live at 6 and 7, so an agent following the pointer would have found Anti-Patterns and nothing else. Per-rule line citations added, the cli-jaw start-time-vs-dist-mtime precedent cross-referenced, /health corrected to /healthz, and the claim that partitioning 'produced a green result' narrowed: one api-usage failure remained and was waived on the baseline triple. Four AI-tell sentences removed ('Every rule here was paid for', 'reads as pedantic until it bites', and two more). npm test 1987 pass / 0 fail.
Three claims in the first dev-devops draft were fabricated detail around real lessons. The rules survived; the evidence did not. Recorded in 020 so the next reader sees the correction, not just the corrected text.
An independent review found no blocker that reopened C1-C6, but two real holes in how the new rules interact with the repo's own severity classes. QUARANTINE-01 was DEFAULT end to end, which meant the four required fields - the entire receipt - were waivable with a stated reason. The permission to defer stays DEFAULT; the four fields are now STRICT. And "blocks unrelated delivery" was unfalsifiable, since any red CI can be called blocking; it now requires naming which delivery and why it is independent of the code under test. ATTRIBUTION-01 (DEFAULT) mirrors DEVOPS-BASELINE-DEFECT-01 (STRICT) on the same triple, so an agent who loaded only dev-testing could state "no CI access", waive the DEFAULT rule, and skip the freeze-SHA check the STRICT one requires. The text now says a recorded gap is not a waiver, and that the STRICT rule governs when both apply. Also: ELIMINATE-01 is marked explicitly as a CLOSURE rule so a four-field quarantine is not read as violating it; the .skip() red flag now names the one quarantine form that is not a red flag; TEST-ANTI-FLAKE-01 got the pointer 030 promised; the dropped "passes locally, fails in CI" row is back as a cause; skill-ownership points at ci-cd-deploy 6.2/6.5 rather than dev-devops 6, which never mentions the family; and the router stub stopped restating all four payloads - restating canonical content is how the original contradiction drifted. Two test comments taught what the new policy forbids. mcp.test.ts justified 30s as absorbing jitter; it is now named as a hang detector, with the unfixed contention tracked as C10 and the honest fixes listed. hook-e2e.test.mjs said "skip rather than flake"; it now says the skip is a missing-fixture precondition, not flake avoidance. Neither behavior changed - the reasoning did, because a comment that teaches a forbidden move is guidance whether or not it is in a skill. npm test 1987 pass / 0 fail.
Zero blockers, but two severity-class holes: a DEFAULT rule wrapping a receipt that should be STRICT, and the same triple at two severities letting an agent reach the weaker class by choosing which skill to load. Also recorded that scoping test files OUT was wrong in one direction - two comments taught what the policy forbids.
3ae3847 used 'git add devlog' and swept in two untracked directories belonging to the user's own in-progress work: 260722_repo-governance-config and 260814_fix-main-ci-windows-worktree. The files are unchanged on disk; this only restores their untracked status. Staging by directory instead of by path is how it happened.
Four work-phases, twelve commits, three independent audits. 1961/0 to 1987/0. Records what each audit caught that self-review did not: a false claim about our own parser, a backtick I corrupted while fixing a neighbouring bug, three fabricated citations, and a severity class that made a receipt waivable.
The closeout quoted wp1's numbers. Re-run at wp4, neutering the hint fails 5 of 13 rather than 3, because coverage added in later phases depends on the same function. A number carried forward from an earlier phase is a remembered pass.
438ddd3 fixed this once and 260e2b4 reintroduced it, because I reached for 'git add devlog' a second time. The files were never modified on disk; only their untracked status was. Recorded rather than quietly repaired: a mistake that recurs after being fixed is a habit, and the fix is to stage explicit paths, never a directory that also contains someone else's work.
…rting
isInterviewReady demanded level "max" on all four dimensions and no shipped
writer could produce it: deriveLevel tops out at "high" and --dim <d>=max is
rejected by the parser. So every HITL interview either dead-ended or spent an
attested override - and once the hatch is the only door, its ledger row stops
distinguishing anything. It recorded "bypassed the gate" for the thorough
interview and the skipped one alike.
The naive fix is worse than the bug. Before writing it down I ran the writer:
cxc scan record --session s --known goal=x --known constraint=x \
--known success=x --known ontology=x
-> all four dimensions "high", scanRounds 1, in one command
--known is free text an agent types, so "accept high" would trade a gate nobody
can pass for a gate nobody can fail.
What distinguishes a real interview is not the level - it is where the level came
from. --derive reads the Q&A ledger written from real request_user_input traffic,
skips unmapped questions rather than guessing, and pins a dimension at "mid" while
any asked question is unanswered.
So provenance is the gate. isInterviewReady stays pure and becomes the SHAPE half
(high or max, contradictions empty, assumptions recorded, scanRounds >= 1).
evaluateInterviewGate composes it with evidence from dimensionsBackedByAnswers,
which re-reads the append-only ledger and returns dimensions holding an asked +
answered + mapped question. scan_completed events now carry their --map so a
later reader can resolve the attribution.
A tracker field would have been simpler and does not work: reconstructScore and
normalizeInterview whitelist four keys, so a derived flag is stripped on write -
measured, not assumed. Widening the fail-closed reconstruct would also make the
flag hand-editable, which is the objection the design exists to answer.
Not tamper-proof: whoever can write session state can append to the ledger. This
closes the accidental path and leaves forgery a deliberate act, which is the right
bar for a soft-gate whose honest bypass is one attested command away.
The human free-pass path keeps the shape-only check - it has no cwd, and a human
is the authority the provenance check approximates.
npm test 1995 pass / 0 fail (was 1987). The load-bearing test is the trivial-path
one: without it this change is indistinguishable from lowering the bar.
… and policy work Twelve version surfaces plus the inventory. check-versions.mjs 0.2.13 OK, inventory --check OK, gate.mjs OK, npm test 1995/0.
…old rule A release-readiness audit caught both of these before the tag, which is the point of running one: 'cxc release verify' compares the published badge count against the suite it measures, and would have failed closed with published tests=1961 but the measured suite reported 1995 The badge is the number the README promises, so drift there is a release claiming a suite it does not have. inventory --write --tests 1995 updates inventory.json and all three READMEs together. Second: the shipped interview skill still documented isInterviewReady as "all dimensions at max" - the rule 964669d replaced. An agent reading it would keep spending overrides for interviews that now pass honestly. It now describes both halves, shape and provenance, and says plainly that --known alone never opens I->P. Also from the audit: the CHANGELOG now says what upgrading does to an in-flight session. Not breaking - an interview that passes today still passes - but a session already at all-high becomes shape-ready, so flags.interview, freeze, and the human free-pass will treat it as ready. That unsticks stranded interviews rather than closing open ones, and a reader deserves to know which. Stale comments in interview.ts and scan-cli.test.ts corrected the same way. gate OK, inventory --check OK, check-versions 0.2.13 OK, npm test 1995/0.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cd342bf0b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (o.event === "answer_recorded" && typeof o.questionId === "string") { | ||
| if (Array.isArray(o.answers) && o.answers.some((a) => typeof a === "string" && a.trim().length > 0)) { | ||
| answered.add(o.questionId); |
There was a problem hiding this comment.
Pair answer provenance with the originating turn
When a questionId is reused across turns, these sets treat an answer from an earlier turn as the answer to a later question with the same ID. This reuse is explicitly supported in rescan-coordinator.ts, which matches (turnId, questionId) because the second question may still be pending. After an answered question is followed by an unanswered clarification with the same ID, scan --derive retains high, this function reports the dimension as backed, and the I→P gate returns ready despite the pending clarification. Key both asked/answered evidence by turn and question rather than questionId alone.
Useful? React with 👍 / 👎.
| " plan init <slug> [--phases N] scaffold the devlog/_plan unit the P>A gate verifies", | ||
| " receipt test -- <command> produce the test receipt a bound C>D requires", | ||
| " review-round open|show|abort the opt-in A-gate plan-audit round", | ||
| " scan record|show record interview coverage and contradiction scans", |
There was a problem hiding this comment.
Remove the nonexistent scan show verb from help
The new top-level help advertises cxc scan show, but the repository-wide command search finds no show handler and parseScanCliArgs accepts only record plus help aliases. Users following this entry therefore receive unknown scan action 'show'; either implement the read-only verb or list only the supported record command.
Useful? React with 👍 / 👎.
Promotes the 0.2.13 train from
dev. Head:cd342bf0, where CI and Packed install lifecycle are both green.What lands
The attest gate rejected what its own documentation taught.
coerceAttestrequiresfrom/tobefore any other check, and the "Required attest keys" table agents copy named neither — norplanUnit,workPhaseId, ortestReceiptPath. A goalplan-boundP>Acost three separate refusals, one turn each.attest JSON missing valid from/toappears 50+ times across four repos since 2026-08-13.The table now names every key per edge with copy-paste objects, and the refusal names the real edge:
tois the verb,fromis the session's phase, and only that edge's extra keys are listed. An illegal edge gets its legal routes and no example, because every example would be rejected.Interview readiness was unreachable.
isInterviewReadydemanded levelmaxon all four dimensions and no shipped writer could produce it —deriveLeveltops out athighand--dim <d>=maxis rejected. Every interview either dead-ended or spent an attested override, which made the override's ledger row meaningless.Accepting
highoutright would have been worse: four--knownflags reach all-highin one command, measured before the fix was written. So the gate asks the append-only Q&A ledger where a level came from. A dimension counts when a question was asked, answered, and attributed with--map.DEVOPS-*freeze-gate rules and an elimination-firstTEST-FLAKE-*policy with a single canonical owner, both harvested from opencodex's v2.32.1 train.Verification
npm test1995 pass / 0 fail (was 1961 at the branch point)gate.mjs,inventory.mjs --check,check-versions.mjs 0.2.13all OKcd342bf0Reviewed
Five independent audit rounds across the train. Three found things self-review did not: a false claim about our own parser, a backtick corrupted while fixing a neighbouring bug, three fabricated citations in the devops rules, a severity class that made a receipt waivable, and — on the release itself — badge drift that would have failed
cxc release verifyclosed at 1961 vs 1995.Note for tagging
Exact-head receipts are looked up on
GITHUB_SHA. The tag must land on a SHA where CI and Packed install lifecycle have both concluded success, so this merge commit needs its own green runs beforev0.2.13is pushed.