Repository navigation
Conversation
…ics, Themes A+B); certification cluster consolidated; leaked test epics removed; merges and re-lanes Removed alpha and from-caller (a test wrote them into the real record on 2026-09-21). suite-twin-and-certification-discipline declined (Rob). #226/#230/#229/#227 superseded into certification-record-redesign; #190 into #198; #223 into #213; parity-ledger-exemptions into hermes-platform-support. New: test-isolation-guard, emitted-invocations-copy-flake. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
Content-keyed, append-only certification record (#226); certify over an index snapshot via clone --shared (#230); functional trigger derived from what functional tests use (#229); Twin-Unchanged trailer checked by a commit-msg hook (#227). Baseline over the 0.50.0 build's 126 commits recorded in the change dir. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…, 5 rounds)
Whole-subject manifest key (mode+blob) replaces staged-path freshness; staged deletions demand their bucket; Twin-Unchanged parsed by git interpret-trailers --parse --no-divider; import observer with per-child tokens and a code-only NODE_OPTIONS guard over a shared regex-aware lexer (js-lexer.mjs); one indexManifest(root, bucket, {indexFile}) shared by drift, certify and the fixture seed; old record coexists (retirement deferred); sweeps subject widened to sweeps/*.mjs + js-lexer.mjs.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…easured on the day 0.1 ticked: Gate 1 passed, recorded against 48afa41. 0.2 ticked, not applicable at L1: release 0.51.0 holds one spec file (cross-spec-0.2.txt); re-run at 5.7 when a second lands. 0.3 baseline-before.md: measure.mjs matches every expected value (15 / 70 / 70 / 51 of 126, closure 132); certify sweeps 25-31 s, functional 190/412/345 s (1,227/1,227) with load recorded; bare export 0.10 s, shared-clone build 0.17 s; the bare export fails the same four files. 0.4 the four tracker items carry no comment newer than 2026-09-28. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…e index copy (1.1)
certification-record-redesign 1.1 (design D2). indexRunPlan({ indexFile, commonDir, headSha, tmp })
returns the ordered steps: copy the live index once; ls-files -s under GIT_INDEX_FILE = the copy;
clone --shared --no-checkout; update-ref --no-deref HEAD; install the copy as the clone's index;
checkout-index -a -f. unit/certify-index pins that the live index is read exactly once, both the
manifest and the export read the copy, and no step names a worktree, the stash, GIT_DIR or
GIT_WORK_TREE. RED/GREEN and the by-hand functional certify (1227/1227): red-1.1.txt.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ared clone (1.2) certification-record-redesign 1.2 (design D2, #230). certify.mjs executes indexRunPlan() in a pm-certify-run.* directory under the OS temp dir: one copy of the index, a clone --shared whose index is that copy, checkout-index -a -f, and the bucket run there. The old single-file entries are now hashed from the copy's blobs, so a partial stage certifies its staged half and an edit or git add made mid-run is not recorded. The bucket runs in its own process group, bounded at 60 minutes (#220); INT/TERM/HUP kill it and exit, and the run directory is removed on every exit (removeAtExit). Git's hook variables are scrubbed from every git call and from the bucket (cleanEnv). certify.mjs stays import-safe: nothing runs outside main(). triggerEntry() takes a readdir so the sweeps entry reads the copy too. functional/certify-index (new id; twin unit/certify-index): partial stage, mid-run edit, and pass/fail/SIGTERM leave the working tree, index, stash and worktree list byte-identical. RED/GREEN and the by-hand functional certify (1230/1230): red-1.2.txt. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…shared clone (1.3) certification-record-redesign 1.3 (design D2). A regression guard in functional/certify-index builds the run directory with certify.mjs's own prepareRun() (now exported) over this repository's index and runs the four files 0.3(d) found failing in a bare checkout-index export (conductor-13 "16.3", conductor-15, conductor-37, gate-artifact-evidence); they pass. Twin unit/certify-index pins the plan's half: the export lands inside the clone, never in a --prefix directory. Mutation (scratch copy, prepareRun building a bare --prefix export) turns the guard red naming "fatal: not a git repository"; reverted, green. By-hand functional certify 1231/1231: mutation-1.3.txt. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ure functions (2.1) certification.mjs gains the decision the manifest record is judged by (design D1, Gate 1 B1/B2): demandedPaths()/bucketDemanded() over lazy subject(index)/subject(HEAD) thunks with the subject-root skip, manifestOf() (subject ∩ index paths), manifestKey() over `path NUL mode SP blob NUL`, and recordFreshness() — a keyed lookup of one entry, never a combination. unit/drift-freshness.test.mjs (new): one named test per spec scenario. RED in red-2.1.txt (every case failed on the missing exports); functional certify run by hand over the staged commit (B9). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
certification.mjs gains the record directory of design D1: writeManifestEntry() names an entry by its manifest's sha256 under <common>/pm-suite-certification.d/<bucket>/ and creates it through a unique temp name plus a rename, refusing a manifest with no test file of its bucket; readEntry() reads one key (an absent directory or file is no entry); pruneRecord() keeps the newest 50 by ranAt and never the entry just written, and removes *.tmp older than 1 h and pm-certify-run.* older than 24 h (Gate 1 M6). The single-file readRecord/writeEntry stay until 2.4. assert/drift-script.test.mjs: five FILE-rung cases, including two writers interleaved through an injected io. RED in red-2.2.txt; functional certify run by hand over the staged commit (B9). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
… the formats coexist (2.3) certification.mjs gains freshnessRefusal(): the demand, then (only when demanded) the index manifest and the ONE entry its key names through readEntry(); and runForBucket(). A common dir holding only the single-file record yields no entry, the writer leaves that file byte-identical, and a clone with no record directory demands a run only when a subject path is staged (D5, B5). RED in red-2.3.txt: the two freshnessRefusal() cases; the byte-identical case is a guard, verified by a scratch-copy mutation (the writer removing the legacy file). Functional certify run by hand over the staged commit (B9). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…y over the index (2.4)
drift.mjs judges check 4 per bucket with freshnessRefusal(): a staged path in subject(index), or a
deleted one in subject(HEAD) (ls-tree -r -z HEAD / show HEAD:<path>; PERMITTED_SUBCOMMANDS gains
ls-tree), demands the bucket, and it is fresh only when the ONE entry keyed by the index manifest
passed and holds exactly it. indexManifest(root, bucket, { indexFile }) is the one manifest entry
point (drift, certify with its index copy, seedAgreeingEntry()); gitRead() is the only place
GIT_INDEX_FILE is set, and indexReaders() threads indexFile to its listing and every show (X1).
The interim subjects are path classes (bucketSubject()); certify writes manifests, prunes, and
leaves pm-suite-certification.json alone (D5).
Retired: recordRefusals (dangling-entry/dangling-covers), coversFor, conformanceRows, moduleEntry,
triggerEntry, readRecord, writeEntry, RECORD_NAME, contentHash, stagedHash, drift's hashStaged,
stagedReader and crypto import, ENGINE_SOURCE, certifiedSet, KIND_MODULE, KIND_TRIGGER,
CONFORMANCE_ID, runFor, sweepIds. Stale wording moved in drift.mjs, certify.mjs and the hook's
comments. Tests moved to the manifest record: assert/drift-script, functional/drift-script (plus
the deletion case and X1), unit+functional certify-index (not listed by the task: L1 created it),
conductor-09 (G-I3 and 1.3 seed; IX-j asserts both buckets) and its twin.
RED red-2.4.txt (the deletion passes under f663cbd's drift; X1 mutation). Both buckets certified
over the staged commit; verify-2.4.txt and evidence-2.4.txt hold the Verify output.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…er refuses the other (2.5) functional/drift-script reproduces #226 in two linked worktrees of one fixture, each running the real certify runner over its own index, B's content holding a functional test only B has, in both orders: A's drift accepts A's commit and B's stays fresh. The worktrees are removed and pruned in a finally, and the test asserts only the main tree is left. assert/drift-script gains the FILE-rung twin (both write orders into one common dir). mutation-2.5.txt: restoring "resolve the covers of every entry" in a scratch copy refuses A in both orders; reverted, both pass. Functional certify run over the staged commit (the gate demands it). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…lexer (3.1)
certification.mjs gains functionalSubject({ root, readFile, readdir, paths }): the import closure
(static from, export-from, bare side-effect and literal dynamic imports, relative only) of every
functional test file and of scripts/conductor.mjs; the functional files; every assertion-half file a
closure file under scripts/test/ spells in CODE as a quoted assert|unit/<name>.test.mjs (executed,
so a closure root); every tracked scripts/, .githooks/ or hooks/ file whose name a closure file
spells; the shipped roots a closure file spells, whole; README.md, CLAUDE.md and the parity ledger by
name. The record (openspec/, .conductor/, CHANGELOG.md, the rest of docs/) is reached by no rule.
Over this repository's index it yields 181 paths, measure.mjs's headSizes.widened. It is not yet the
bucket's subject: drift and certify switch to it in 3.3.
lex() and KEYWORDS_BEFORE_REGEX move from sweeps/output-interpolations.mjs to the new
scripts/test/js-lexer.mjs (the sweep imports it; its --all output is byte-identical). lex() gains
two additive results, comments and misparse; stripComments() throws on any misparse, naming the
file and line, so the executed-file match fails closed. Every fixture that copies certification.mjs
now copies js-lexer.mjs too: helpers.mjs (runHookAgainstFixture), IX-k's extraFiles, and the
certify-index and drift-script fixtures (the last two found by rg, not listed by the task). Twins
edited: unit/certify-index, unit/conductor-09, assert/drift-script. The functional twin case reads
every tracked scripts/ .mjs/.cjs/.js from the index with zero misparses.
RED red-3.1.txt (functionalSubject missing; the three lexer cases misread IN by a tokenizer with no
regex state). Also stages red-2.4-sweeps.txt (2.4's sweeps RED, captured after the fact). Both
buckets certified over the staged commit.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…3.2) certify.mjs functional now runs the half under NODE_OPTIONS=--import of the RUN TREE's scripts/test/fixtures/observe-reads.mjs (new; appended to the inherited value; configured by its own URL so a stacked observer keeps its own run). The observer records module resolutions (module.registerHooks), fs reads (readFile*, createReadStream, read-mode open, copy/cp sources) and child_process script paths under the run tree, one file per process; it patches child_process (+ syncBuiltinESMExports) so a direct Node child gets a token, arrives synchronously at load, and a failed spawn cancels its expectation. After a pass, certify refuses any observed tracked path outside functionalSubject() (the record excluded by rule: isRecordPath) and any unarrived child, naming them, and records nothing. Before the bucket, nodeOptionsRefusals() (certification.mjs, shared lex(), fails closed on a misparse) refuses a functional/fixture file whose code assigns NODE_OPTIONS a value not carrying process.env.NODE_OPTIONS. Tree edits before the report-only run: conformance.test.mjs:210 appends to the inherited NODE_OPTIONS; conductor-14 spells its three rules-0.26.0 baselines as literals. Twins edited: unit/conformance, unit/conductor-14, unit/certify-index, assert/drift-script. The certify-index and drift-script fixtures copy observe-reads.mjs. observer-report-3.2.txt: 0 derivation gaps, 0 unarrived children, 1236/1236; the out-of-subject reads are all the record (openspec/changes/archive, the live .conductor/state.json, CHANGELOG.md, and 7 docs/superpowers/plans files the live-record tests reach). RED red-3.2.txt (no nodeOptionsRefusals/observationRefusals; the unarmed certify records all five refusal cases). Functional certify over the staged commit passed under the armed observer. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…rves (3.3)
bucketSubject("functional") is functionalSubject(): drift's freshness check, certify's recorded
manifest and seedAgreeingEntry() all reach it through indexManifest(), so they move together.
certifiedModules() (the gitOps( scan and its ENGINE_ENTRY special case) and the interim MACHINERY
list retire; over this index the subject is 185 paths and holds archive-gate.mjs (#229).
Moved with it: assert/drift-script's subject test (now the observed shapes: an imported module with
no gateway call demands both buckets, an unimported gateway caller only sweeps) and its 6.1 test
(the derivation over this repository); IX-j asserts a sweeps demand naming zz-probe.mjs and NO
functional demand (twin unit/conductor-09 edited); the certify-index and drift-script fixtures'
functional test IMPORTS their module instead of naming it in a comment (twins edited). Stale
comments rewritten: drift.mjs indexReaders(), fixtures/helpers.mjs's "empty certified set".
X1's two-index case and the seeded G-I3 and 1.3 re-run green unedited.
verify-3.3.txt holds the Verify lines with drifted line numbers corrected, and the certify over the
staged commit.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
… is retired (3.4) scripts/lib/store.mjs's diskStore() comment existed only because the retired certifiedModules() scan counted comments, so a comment spelling the gateway call enrolled the module. It now says the scan is retired and the functional subject is what the half observes (functionalSubject()), which no comment moves. `rg -n "certifiedModules" scripts` returns nothing. Also appends to verify-3.3.txt the post-commit measure.mjs over 762d564 (HEAD~1..HEAD): the 3.3 commit is in the observed subject (B_widenedShippedSurface 1) and the retired scan would not have demanded it (A_certified_today 0). store.mjs is in both subjects; both certified over the staged commit: sweeps 25/25 (57s), functional 1245/1245 under the observer (586s, 185 subject paths, 80 record reads excluded by rule). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
… the real index (3.5) A functional/certify-index case derives the functional subject over this repository's own index (indexReaders(): git ls-files and git show :<path>, never an injected reader), takes b4ffe16's two changed paths (scripts/lib/archive-gate.mjs, scripts/lib/store.mjs) as staged against an empty record, and requires a functional freshness demand naming archive-gate.mjs — the module the half imports that never reaches git (#229). It reads the index, not `git ls-tree b4ffe16`, which only the presquash/pr-234 tag reaches. Twin unit/certify-index edited. mutation-3.5.txt: restoring the retired gitOps( derivation in a scratch shared clone turns it red ("b4ffe164's change demanded nothing") — neither module calls gitOps(, so #229 exactly — and green again when reverted. Functional certified over the staged commit (1246/1246, 619s). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…nged trailers (4.1)
certification.mjs gains parseTwinExemptions(parsedTrailers), over the OUTPUT of
`git interpret-trailers --parse --no-divider` (design D4, Gate 1 B3): git decides what is a trailer,
this reads only the Twin-Unchanged lines, the key matched case-insensitively as Gate 2's
%(trailers:key=) matches it. The id is the value's first token and only a spaced separator
(' — ', ' -- ', ' - ') begins the reason (round 2 I1), so `conductor-09` and a reason holding ' - '
are read whole; no separator is an empty reason, kept so 4.2 can refuse it.
New unit/drift-coupling.test.mjs (unit rung, pure values). RED red-4.1.txt: 8/8 failing on
"certification.mjs exports no parseTwinExemptions()".
Also folds the L3 bookkeeping into tasks.md: 3.2's expected out-of-subject record reads now name the
seven docs/superpowers/plans/*.md files the live-record tests reach through plansDir() — record by
the spec's docs/ rule (observer-report-3.2.txt), excluded, not a gap.
certification.mjs is in the functional subject: certified over the staged commit, 1246/1246 (second
run; the first hit the known emitted-invocations ENOENT flake, logged).
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…cks() (4.2)
couplingRefusals({ …, exemptions, isMerge }) (design D4): a declared id with a reason, whose
functional file is staged, passes without its twin; a declaration naming an id whose functional file
is NOT staged is refused as { id, declaration: "not-staged", functional }; an empty reason is refused
as { id, declaration: "no-reason" } and exempts nothing; an undeclared unpaired file is refused in
exactly today's shape; with isMerge (MERGE_HEAD present) nothing is judged.
phaseChecks(phase) with PHASES: pre-commit runs enrolment, twins and record; commit-msg runs coupling;
no phase runs all four (Gate 1 M5), and coupling with no message uses no exemptions. An unknown phase
is refused naming the two. drift.mjs does not use either yet (4.3 wires them).
RED red-4.2.txt: 5 of 6 new unit/drift-coupling cases failing (the undeclared case is today's
behaviour and passed as expected). Certified functional over the staged commit, 1246/1246.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ared exemption (4.3, L4)
.githooks/commit-msg (new, 100755) captures GIT_INDEX_FILE and makes $1 absolute before the scrub,
exports its own index snapshot, and runs the snapshot's drift.mjs (the working tree's only when the
index holds none) with --phase commit-msg --message <abs>. .githooks/pre-commit passes
--phase pre-commit and no longer claims coupling. So check 3 runs in exactly one hook (design D4).
drift.mjs: --phase/--message; checkAll(root, { phase, message }) runs phaseChecks(phase) only.
Coupling reads git's own parse of the message (interpret-trailers --parse --no-divider, added to
PERMITTED_SUBCOMMANDS, pin moved) and skips a merge (MERGE_HEAD through rev-parse
--path-format=absolute --git-path). An accepting run prints every declaration as
"drift: coupling exemption <id> — <reason>"; refusals name the id and the twin's path, or the
refused declaration. The ABORT closing line names only the phase's checks.
functional/conductor-09: 11 cases through BOTH real hooks with real git commits (hookedRepo(),
hookedGit() in fixtures/helpers.mjs, stdout+stderr one ordered stream), each seeded with
seedAgreeingEntry() over the index its commit is made from; every refusal asserts pre-commit's
success line THEN commit-msg's coupling line. Covered: plain, -a, <path>, linked worktree;
declared/not-staged/no-reason; --no-ff merge accepted (main and linked worktree), squash refused;
subject-only, prose-paragraph, after-scissors refused, above-scissors accepted; the --- divider both
ways, agreeing with %(trailers) in a hookless repo; the snapshot-vs-working-tree drift fallback.
Twin assert/conductor-09: the commit-msg hook's shape pinned, pre-commit's drift line and wording
moved; unit/conductor-09 omission note 8.
RED red-4.3.txt: 11/11 failing on the missing hook, and with a stub commit-msg the old pre-commit
refuses coupling itself so its success line never prints. Certified functional over the staged
commit, 1257/1257 (186 subject paths; .githooks/commit-msg is in the subject).
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
functional/conductor-09 gains the regression guard: with both hooks installed and an agreeing entry seeded, a staged functional file without its twin is refused, pre-commit's success line printed first, and the coupling line reported exactly once, by commit-msg. Twin assert/conductor-09: the PHASES table puts coupling in commit-msg only, the pre-commit phase runs the other three, no check runs in both, and the two phases together equal a bare run. mutation-4.4.txt (scratch copy of scripts/ and .githooks/): coupling re-enabled in the pre-commit phase fails the guard on "pre-commit's success line was not printed" with the coupling line printed once (git runs no commit-msg after pre-commit fails); coupling disabled in commit-msg fails it on "the commit must be refused" (the commit was made); reverted, green. It also records the L4 commit 0b2ad82's own output: pre-commit phase ok, pre-commit 1581/1581, commit-msg phase ok. Certified functional over the staged commit, 1258/1258. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…d (5.1) call-site-sweep-5.1.txt, every list rg-derived: no retired name keeps a caller; freshness, the subject derivation and the Twin-Unchanged exemption each hold in one function, with the places they do not hold (commit-msg: no freshness; pre-commit: no exemption; CI: no record) justified. Two findings routed: CONTRIBUTING's stale four-checks wording (6.1), and .githooks/commit-msg not chaining `git secrets --commit_msg_hook` (5.9 b). tasks.md: line citations L4 moved get their post-L4 value beside the c96240a one (pre-commit :146-159/:150-154/:155, drift.mjs :231). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ailer (5.2) data-references-5.2.txt: the retired single-file record's id-holding fields (entry ids, covers, conformanceRows) — written by writeEntry(), read by recordRefusals(), removed by nothing (#226's second failure mode); the manifest record, whose fields are content (paths, modes, blob ids) and informational provenance, removed only by pruning; and the Twin-Unchanged trailer, which lives in the commit object and is stored by nothing pm owns. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…5.3) inverses-5.3.txt: entry write/prune, temp-file rename/prune, the run directory's build and its removal on exit, signal and (after SIGKILL) a 24 h prune, the observer's files and tokens, the declared exemption (amend before, Gate 2's audit after), the hook install, the phase split, fixture seeding — each shipped or existing; the derived subject has no inverse by design (D3); the old record file's removal is deferred to the epic 8.2 registers (D5). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…e tree (5.4) commit-verification-5.4.txt: for 1.1-4.4 and 5.1-5.3, `git show --stat` and each claimed file (code, tests, evidence file, tasks.md, each functional test's twin or its Twin-Unchanged trailer) matched against the commit's own name list. 20 of 20 pass. 3.3's claimed certify.mjs is absent from 762d564 and justified: 2.4 had moved certify onto drift's indexManifest(), so 3.3's bucketSubject() edit in certification.mjs moved certify with it. .githooks/commit-msg is 100755 in 0b2ad82 and at HEAD. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…8.3 (5.5) `rg -n "pm:lifecycle"` over tasks.md hits the 8.2 and 8.3 task lines and 5.5's own continuation line, which names the marker inside a code span; the engine's countCheckboxes() reads checkbox lines only and strips code spans first, so exactly those two tasks are excluded as lifecycle. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ot run (5.8) disposition-5.8.txt maps design.md's five non-goals, its open question and its one deferral onto 8.2: four declined deferrals, one deferral to the planned retire-single-file-certification-record epic, and two non-goals (CI's buckets, the engine) justified as not deferrals. The add-epic and archive commands are written out with flags checked against `--help`; 8.2 runs them after Gate 2. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…me the mechanism (5.9) PROCESS: an-uncertified-module-change-skips-the-functional-half moves from "habit — no mechanism" to drift check 4 over functionalSubject() (3.3), certify's observer (3.2) and the 3.5 guard, with its trigger and rule rewritten for the observed subject and certify-over-the-index; a-one-off-sweep's enforced_in, record path and quoted refusal now describe the manifest directory and today's describeRefusal() text; the README index rows follow. routing-5.9.txt names each item's kind. The certify-then-plain-commit PRACTICE is not registered: the gate enforces it from L4. The openspec "no new change verb" premise is wrong: 1.13.2 has `openspec new change <name>`, and it makes the same .openspec.yaml, so there is nothing to file. The ENOENT flake's three occurrences went to its epic's notes. commit-msg's missing git-secrets chain is drafted as feedback, not filed. One process lesson is drafted for the orchestrator; the other gets no lesson, because its trigger is only recognisable after the fact. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
… index, parallel worktrees (6.1) "Pre-commit hook" now says the pre-commit run checks enrolment, twin coverage and freshness (against a whole-subject manifest), and the commit-msg run checks diff coupling. It covers the `Twin-Unchanged: <id> — <reason>` trailer (the committer declares it, git parses it, Gate 2 audits it) and the order: stage exactly, certify, then a plain `git commit`. The triggered-bucket paragraph gains the two derived subjects and how certify runs (index copy, shared clone, one manifest entry, the observer). A new "Parallel worktrees" section: no lock, pm-suite.lock kept for load only, a hand-rolled pm-certify.lock is obsolete. CONTRIBUTING has no "The triggered buckets" heading, which task 6.1 names. Its content went into the paragraph that already covers the triggered buckets. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…rved subject (6.2)
The pre-commit hook runs drift's pre-commit phase (enrolment, twin coverage, record freshness) and
then the assertion half. The commit-msg hook runs diff coupling, and a `Twin-Unchanged: <id> —
<reason>` git trailer exempts a subject-free change there, which Gate 2 audits. A bare drift run
still runs all four checks. The functional demand fires for a staged path in what the half observes,
and certify runs over a copy of the index, so the order is: stage, certify, plain commit.
CLAUDE.md is in the functional subject, so the commit was certified first, over the staged commit:
`node scripts/test/certify.mjs functional`, exit 0, 574 s, load { 136.04 66.02 63.68 } ->
{ 182.71 202.51 145.96 }: 1258/1258, observer saw 2427 Node processes, 186 subject paths recorded
as 195d7599…b982.
Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…elease-0-51-0-cut flaky-test-quarantine-and-targeted-rerun, hook-friction-0-51 and lean-subagent-bootstrap archived delivered after one converged review round (1 Critical + 3 Important fixed in 9b57a8e, a100466). Known flakes now name owning epics; four follow-up epics registered. A Theme B epic is active so the live-record tests do not read 0.51.0 as delivered (hook-friction item 5). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…on profile (sonnet implement/test, opus review) Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
… 1 digests, write-time refusals One commit for six epics (gh#216 #237 #233 #232 #198 #205); the files overlap and each epic would otherwise need its own functional + sweeps certify run. - 237: a commit already attributed (or repeated in one call) is a no-op, said on stderr - 216: staleness already read the set; fix the position-readers (stale-Gate-2 remedy wording, integrity's merge-commit date uses the latest-dated commit) - 205: attributing past a passing Gate 2 says it went stale and names --withdraw-commit; the ordering rule is documented in the attribution task item - 198: Gate 1 records artifactDigests (sha-256, change-relative via the one archive resolver); amending a reviewed artifact reads stale, absence reads unverifiable - 233: --no-deferrals with --deferral/--declined-deferral is refused - 232: --plan/--spec refuse a trailing slash or an existing non-file (update-epic, add-epic) Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM Twin-Unchanged: conductor-36 — the I3 fixture now seeds a legacy duplicate the verb no longer writes; the asserted behaviour is unchanged
…gest, add-many #232, #205 advisory, wording - Gate 1: a live change's tasks.md is a progress ledger, listed but never digested/compared - add-many: planPath/specPath use the shared #232 refusal - update-epic: #205 advisory also fires from none-attributed/attribution-withdrawn - spec/changeset/docs wording; stale test file pointer Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ocs carried to release-0-51-0-cut Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…arker, truthful archive and status reporting One commit for nine epics because they share scripts/lib/integrity.mjs and its test registry: gh-200 (--plan/--spec names an OpenSpec change), gh-201 (late-failing-gate-review), gh-231 (tracker-item-held-by-two-epics), gh-215 (archived-change-also-live), archived-delivered-fails-delivered-obligation, update-epic --status undone by the heal, dispositionInvocation() deferral placeholder, set-aside archive dirs in integrity, release --deliver/--undeliver marker read by delivered-release-epic-left-open. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM Twin-Unchanged: conductor-30 — only the closed list of valueless flags gained deliver/undeliver; the assertion twin does not assert that list Twin-Unchanged: emitted-invocations — new Layer B builders only; the twin's registry check reads that file's source and passes, and the new checks are asserted per commit in assert/theme-b2.test.mjs
…ceholder, not a bare --no-deferrals Covers deliveredArchiveInvocation() and the superseded-epic remedy; the source scan now covers every printer file. The markerless delivered-release finding states the mid-flight way out. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM Twin-Unchanged: emitted-invocations — fixture regexes updated to the printed placeholder only; what the test observes (remedies clear what printed them) is unchanged
…earliest-commit recovery, verb-table guard, planning-completeness rule One commit for five epics: they share constants.mjs, subcommands.mjs, the command docs and the functional baselines. - gh#167 sync --dry-run (writes nothing) and repeatable --only <id>; dry run skips the detached-tree warning - gh#206 assertion-half guard naming every missing per-verb table row in one run; CONTRIBUTING documents the seed hook - spec-sync-waive-for-skip-specs: update-epic --spec-deltas-waived "<why>", inverse --clear spec-deltas-waived - created-at-recovery-dates-too-late: full-history pickaxe, earliest match by date - openspec-planning-completeness-instruction: obligation paragraph in the emitted rules, no command named Twin-Unchanged: conductor-13 — functional-only exercise-table row for the new update-epic flag; the twin's subject is unchanged Twin-Unchanged: conductor-31 — functional-only baseline row and closed-list entry for sync's new flags; the twin's subject is unchanged Twin-Unchanged: output-text-integrity — functional-only poison recipes for the two new value-bearing flags; the twin's subject is unchanged Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
… spec-deltas waiver, review minors - recover-created-at prints the AUTHOR date (%aI); the real knowledge-store cause was the rewritten committer date, not history simplification. Functional fixture rewrites only the committer date. - --spec-deltas-waived is refused outside the check's scope (naming it); the briefing lists waived epics. - sync --only: flip lines print only after the unmatched-id check passes. - rules paragraph names the artifacts the OpenSpec schema requires; commands/sync.md passes --dry-run/--only. - strengthen the inSpecSyncScope test (in-memory resolver) and replace the constant-only dry-run test with a detached-tree functional test. Twin-Unchanged: detached-suppression — the new case needs a real detached checkout, which only the functional rung can make; the unit twin's roots are all unanswerable trees Twin-Unchanged: conductor-13 — fixture setup only: the exercised epic is put in the waiver's scope; what the file tests is unchanged Twin-Unchanged: output-text-integrity — fixture setup only: a new in-scope epic for the waiver recipe; what the file tests is unchanged Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…Gate 2 re-recorded for conductor-tells-the-truth B3 epics archived delivered (docs carried to release-0-51-0-cut); planning-completeness remainder held by planning-completeness-orient-and-autonomy-boundary. conductor-tells-the-truth Gate 2 extended to eb787d9 after an Opus review of bd2b1e6..eb787d9. store-owns-claude-md-managed-block active so 0.51.0 stays in flight. Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…0 (no quiet-machine measurement taken) Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…); 0.53.0 token analysis; defer gh-114, rules-block-cli-fallback, codex Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
….14 evaluation epic Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…not Date.now() The +400-day CI job moves Date.now() but not the filesystem, so the start read 'before'. Also rewords gh-172's description so TruffleHog stops flagging the quoted test name as a verified Lob key (the false positive gh-172 tracks). Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
…ce's commits; 5.9 probe accepts any non-zero The certify run directory (clone --shared) copies only local branches and tags, so a detached CI checkout left the attributed commits unreachable and 9.14 failed inside 1.3. Fetch the source's refs into refs/certify-source/*. The 5.9 fixture asserted exit 1 for a missing command; dash exits 127. Twin-Unchanged: conductor-09 — the change loosens a fixture precondition (exit 1 -> any non-zero); what the test asserts, runs and imports is unchanged Claude-Session: https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM
This was referenced Oct 7, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cuts 0.51.0: 30 delivered epics (Theme A test infrastructure, Theme B gate/record integrity, execution profile, release-candidate review); store-owns-claude-md-managed-block deferred. Version bump, CHANGELOG, README/SKILL/CONTRIBUTING currency. Full suite 3170/3170 green; functional certify 1330/1330. Docs site PR (held until this merges): cfdude/pm-docs#58
https://claude.ai/code/session_01BoqzgrFwRC6QTUKuBkw8kM