feat(gate): fail on stale launcher-standard refs (standards#960 AC4) - #983
Conversation
standards#960 acceptance criterion 4. launcher/launcher-standard.a2ml was deleted on 2026-09-22 (#952, be6c958) and replaced by launcher/launcher-standard_praxis.deed at :standard-version 0.4.0. Nothing told the downstream repos. A census today finds 21 distinct *.launcher.a2ml descriptors (36 on-disk copies) plus trigger/scripts/trigger-launcher.sh still declaring compliance with "launcher-standard.a2ml v0.3.0" -- a filename that is gone and a version that no longer exists. Both claims read as compliance; neither is checkable. That is the vacuous-gate pattern the estate rules against. The two defects fail INDEPENDENTLY: launcher-standard.a2ml any version -> FAIL (retired filename) launcher-standard_praxis.deed v0.3.0 -> FAIL (stale version) launcher-standard.a2ml v0.4.0 -> FAIL (filename only) launcher-standard_praxis.deed v0.4.0 -> PASS Three things this gate does deliberately: 1. The expected version is not a magic number. CURRENT_VERSION is a default for consumers, who do not carry the standard; the test asserts it equals :standard-version in the real deed, so bumping the standard without updating the gate turns standards' own CI red. A checker whose expected value can drift from the thing it checks is worse than no checker. 2. It reads :standard-version, never :schema-version. A deed carries two versions -- the grammar (1.0.0) and the document (0.4.0). Reading the first yields a number that looks like a NEWER spec, so the error reads as an upgrade rather than as drift. A fixture makes the two impossible to confuse. 3. AC1's "dated historical record" exemption is a PATH allowlist, not a content heuristic. A heuristic sparing lines that say "formerly" or "translated from" would spare the live defect too, because that is how a stale descriptor comment is worded. standards' own tree really does name the retired file in four places (the conversion mapping doc, two dated audits, the deed's own ;; provenance header); the allowlist absorbs exactly those. Proved, not assumed: - 19/19 in the fixture suite. - Real defect killed: run against metadatastician/stapeln it reports 4 defects, with both classes firing independently on line 5. - Anti-drift mutant killed: setting CURRENT_VERSION=0.3.0 turns the suite red (2 failures) rather than passing quietly. - Negative control: standards' own tree is clean under the allowlist. No workflow wiring is added. scripts/run-shell-test-suite.sh discovers by glob (find scripts/tests -maxdepth 1 -name '*.sh') and invokes via bash "$f", so the suite runs on every PR already and is immune to the exit-126 non-executable trap. Grepping .github/workflows for the filename finds nothing and is the wrong way to ask whether it runs. Wiring the gate into consumer repos is deliberately NOT done here: it would arm a new scan across 412 consumers on their next pin bump. That is an owner decision, recorded on #960. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo
All three were true when written and are false now. Each is withdrawn in place, dated, with the measurement that replaced it -- rather than silently edited -- because a spec that quietly changes its mind teaches the next reader to distrust the parts that did not change. 1. §7 item 1: "There is no Rust `.deed` parser in the estate." FALSE since D73-C part 2. `crates/launcher-common/src/deed.rs` is a purpose-built recursive-descent DEED parser, 37,039 B, exported as `pub mod deed;` (lib.rs:23), with `pub mod standard;` (lib.rs:30) on top of it. The same item's `[resolution]`-omission defect is closed too: the vendored copy is byte-identical to canon. What remains true is the reason `deed-ecosystem/rs` was not the starting point -- it is still the unmigrated A2ML crate, and still not to be touched (deed-ecosystem#67). 2. §7 out-of-scope: "10 downstream `*.launcher.a2ml` files." An undercount by more than 5x. Re-measured today with the vendored ripgrep (the only estate-wide sweep that completes), excluding both `.claude/worktrees/` and `developer/worktrees/` so the sweep does not count this session's own worktrees: 23 distinct descriptors across 52 on-disk paths, 39 of those paths citing the deleted file. Two of the 23 (`_DATABASE`, `_ESOTERIC_GROUP`) are set-level, not per-application, which is why an app-name census returns 21 -- #960's figure, and correct for the question it asked. The count is written as a DATED measurement, not a standing fact, because it moves every time a repo is cloned twice. 3. §8: the vendored launch-scaffolder copy is "still v0.2.0, still missing `[resolution]`, and still `.a2ml`." False in all three parts. `diff -q` against the canonical file reports no difference: 13,803 B, `:standard-version "0.4.0"`, `:standard-date "2026-09-22"`. Withdrawn rather than deleted, since the claim was quoted forward into this campaign's notes and a reader needs to see it retracted. This file is on the AC4 gate's path allowlist (`1-formats/deed/mappings/*`), so the retired filename quoted above does not trip it. That is the allowlist working as designed: a historical-record exemption has to be a path allowlist, because a content heuristic sparing lines that say "formerly" would spare the live defect too. Refs: #960, #837 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo
|
Warning Review limit reachedNext included review available in 20 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
…14) 19 citations in this repo named `launcher-standard.a2ml v0.3.0`. That file was **deleted upstream** on 2026-09-22 by hyperpolymath/standards#952 (`be6c9580`, owner ruling D73-C) and translated to `launcher/launcher-standard_praxis.deed`. Every one of these pointed at a path that no longer resolves. This is AC3 of hyperpolymath/standards#960. ## Why the v0.4.0 claim is earned, not assumed Rewriting `v0.3.0` → `v0.4.0` is a **compliance claim**, not a rename, so it had to be checked rather than swept. The deed states its own delta at lines 22–24: > Bumped 0.3.0 -> 0.4.0 because the resolution ladders below now name the .deed file, which is consumer-visible. That delta lands entirely in `(resolution (standard-search` — the ladder a consumer uses to **locate the standard at runtime**. This launcher never reads the standard at runtime: it inlines the `(resolution (desktop-tools-search` ladder, whose six priorities match the deed's in the same order and are untouched by 0.4.0. So nothing 0.4.0 added is unimplemented here. If that had not held, the honest move would have been to name 0.4.0 **and record the gap** — it did hold. ## Why this is safe Comments only, with one deliberate exception: the `--version` output prints a `Standards Compliance:` line, rewritten because a compliance claim has to name the standard that exists. The deed's `(version-output` clause constrains only `:first-line-format`, which is untouched and still conforms. `bash -n` passes. The launcher was **not executed** — it `source`s `keepopen.sh` unconditionally at top level. **No consumer breaks.** `launch-scaffolder`'s metadata parser keys on a literal `# @a2ml-metadata begin` delimiter (`metadata_block.rs:109`); this launcher has no such line and is not parseable by it today, before or after this change. All eleven fields the deed's `(metadata-block :required-fields` demands are present and untouched. ## Clause notation `§x` → `(x ...)`, the deed's s-expression heads. Three were not mechanical and were each verified against the deed rather than guessed: | was | now | why | |---|---|---| | `§a2ml-metadata-block` | `(metadata-block ...)` | the deed's only clause rename, authorised by its own comment: *"A2ML is a dead format name and the deed era does not carry it forward"* | | `§disinteg.remove` | `(disinteg :remove ...)` | `:remove` is a **key** on `(disinteg`, not a subclause — deed:228 | | "ladder from launcher-standard.a2ml" | `(resolution (desktop-tools-search ...))` | the deed has **two** ladders; this one resolves `.desktop-tools`, so it is the first, not `(fallback-ladder` | The old filename is deliberately **not** carried as a "formerly …" gloss. The #960 AC4 gate flags a retired filename at any version, by design — the history belongs in the commit message, not in the source. ## Proved The AC4 gate (`scripts/check-launcher-standard-currency.sh`, hyperpolymath/standards#983) run against this worktree: - **before:** 23 defect rows over 19 lines, rc=1 — four lines carry *both* a retired-filename and a stale-version defect, which is why 19 lines yield 23 rows - **after:** `No stale launcher-standard references.`, rc=0 This is also the gate's first run against a hand-written launcher rather than a generated descriptor. ## What is deliberately left alone `dev-notes/HANDOVER.adoc` keeps its two v0.3.0 citations. It carries `:revdate: 2026-08-13` on its face and is a historical record; the gate allowlists it by path for exactly that reason. Rewriting a handover to name a file that did not exist at handover time would falsify the record. Refs hyperpolymath/standards#960 · hyperpolymath/standards#952 · hyperpolymath/standards#983 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
⚠ Correction to point 2 of this PR's descriptionThis PR's description says:
That is wrong, and the parenthetical explaining away the difference from #960 was a rationalisation of a control that was correctly firing. The sweep behind it had been run from #960's figure of 21 was right. The 23 was mine and it was wrong. Corrected census, scoped to
Nothing merged here depends on the figure — the gate and its 19 controls are unaffected, and both re-run clean against 🤖 Generated with Claude Code |
⚠ Follow-up: the path counts in my comment above were also slightly wrongThe substantive claim stands — #960's 21 was right and my 23 was wrong — but the re-measurement I posted (36 paths / 29 citing / 71 lines) was itself made with a filter that silently did nothing. A ripgrep
Only the path counts moved. The distinct counts did not — which is exactly what removing duplicates should do, and is the reason the decision-relevant figures (21 descriptors, 17 citing, 18 repos) were sound all along. #984 carries both corrections. 🤖 Generated with Claude Code |
Corrects a number **I wrote and merged** in `edac0d6a` (#983, standards#960 AC4) — and then corrects that correction, because the first re-measurement was made with a silently-broken filter. ## What was wrong on `main` §7 of `1-formats/deed/mappings/launcher-standard-to-praxis-deed.adoc` recorded: > an undercount by more than 5×… **23 distinct descriptors across 52 on-disk paths**… **39 of those paths cite the deleted `launcher-standard.a2ml`** and explained the disagreement with `standards#960`'s own figure of 21 by asserting that two set-level directories (`_DATABASE`, `_ESOTERIC_GROUP`) inflate an app-name census. **All three numbers were wrong, the multiplier was wrong, and the explanation was a rationalisation of a control that was correctly firing.** #960's 21 was right; the 23 in this document was wrong. ## Why The sweep had been run from `developer/` with no scope restriction, and its worktree exclusion did not work. Three populations were counted that are not live repositories: | counted, not a live repo | paths | |---|---| | `archive/` quarantine snapshots | 9 | | `tools/opt/cargo/git/checkouts/` (`burble` ×5, `gossamer` ×2) | 7 | | nested `.claude/worktrees/` copies | 5 | 52 − 21 = **31**. And 10 → 21 is roughly **2×**, not "more than 5×". ## ⚠ The trap worth carrying: a `-g` exclude without `**/` fails silently `-g '!.claude/worktrees/**'` looks right, runs without error, and **excludes nothing** where worktrees are nested inside repos — a ripgrep glob only matches at the *search root*. It reads as scoping and supplies none, the same class of defect as a vacuous gate. The working form is `-g '!**/.claude/worktrees/**'`, with a positive control asserted on the filter's own output. ## The corrected census Scoped to `hyper-repos` and `meta-repos`, nested worktrees verified absent from the result: | metric | value | |---|---| | `*.launcher.a2ml` paths on disk | 31 | | **distinct descriptor basenames** | **21** (confirms #960) | | paths citing the deleted `launcher-standard.a2ml` | 26 | | distinct descriptors citing it | 17 | | **distinct upstream repositories affected** | **18** | | citing lines, all `#` comments, in six shapes | 66 | **The invariant that says which figures to trust:** fixing the exclusion moved the path counts (36→31, 29→26, 71→66) and left **21 / 17 / 18 unchanged** — exactly what removing duplicates should do. The distinct counts were sound throughout; only the path counts were ever inflated. The document now marks the path counts as dated and the distinct counts as standing. ## Shape of the fix Corrected **in place and dated**, not silently overwritten — the same shape as the two `⚠ WITHDRAWN 2026-09-22` blocks already in this document. ## Verification Gate and suite re-run after each commit, since the doc names the deleted filename and depends on the allowlist: ``` check-launcher-standard-currency: canonical=launcher-standard_praxis.deed expected=v0.4.0 No stale launcher-standard references. gate rc=0 === summary: 19 passed, 0 failed === ``` Docs-only, one file, two commits. Refs standards#960, #983. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
standards#960 AC4 was implemented and tested but never wired -- no workflow in any repository invoked it. This arms it in the `quality` job, in tiers. The gate is copied out inside the existing `Check documentation` step, before that step's `rm -rf .standards-checkout`, and run from $RUNNER_TEMP afterwards. That shape is forced, and it is this file's own established idiom (see validate-hypatia-baseline): the sparse checkout puts standards' scripts at .standards-checkout/scripts/, and the gate's allowlist entries for its own source carry no '*/' prefix, so run in place it reports 16 defects on itself and would red every consumer. Self-lint fallback, likewise copied from the neighbouring gates: prefer the caller's own scripts/check-launcher-standard-currency.sh when present, so standards validating itself runs the tree under test rather than main's copy. Without it this pull request's own CI would judge the fix by the version it replaces. Tiers, with the evidence recorded in standards#991: retired-filename BLOCKS. The predicate is stable -- launcher-standard.a2ml was deleted upstream (standards#952) and stays deleted, so a clean caller cannot become defective without editing the citation. Measured over 26 consumers: 3 carry defects, all archived or on the DO-NOT-MERGE list, so arming this reds zero live callers. stale-version WARNS. The predicate is time-dependent -- the gate compares against its own CURRENT_VERSION, so every correctly-citing caller flips to defect at the next bump having done nothing. A cutoff date does not cure that; each CURRENT_VERSION bump is a measure-then-arm event. The split greps the gate's typed stdout lines rather than its exit code, because both classes return 1. rc=2 (usage error, or a surviving self-test mutant) fails before the split, so a broken invocation can never read as a clean pass, and the gate's header is echoed unconditionally so a vacuous run is visible. Proven, not asserted: the wrapper was run under `bash -eo pipefail` against seeded gates emitting clean / retired-only / stale-only / mixed / rc=2 / rc=1-with-no-defect, and each branch returned the intended exit code -- stale-only exits 0 with a ::warning::, retired-only exits 1. The fixed gate returns rc=0 with zero defects on standards' own tree at origin/main, so the self-lint path does not red this pull request. actionlint reports the same 5 pre-existing findings before and after, and no `uses:` is added, so actions.lock is untouched. Refs: #960, #983, #990, #991, #952, #505 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
) Closes the last open half of **#960 AC4**. The gate merged in **#983** was `implemented` and `tested` but **never `wired`** — no workflow in any repository invoked it. This pull request does both halves, and they have to travel together: consumers fetch the gate from `ref: main`, so wiring before the cure would arm the false positives estate-wide, and curing without wiring leaves a gate nothing runs. --- ## Part 1 — the cure: three false positives Measured across 27 repositories, the gate reported **19** defects. Three were implementation defects in the gate itself. **G1 — version conflation.** The gate accepted any version number within 24 non-digit characters of the filename. A line reading `` `launcher-standard_praxis.deed` (DEED v1.0.0). Per-app config: `` captured the **grammar** version `1.0.0` and reported it as **document** drift. The gate's own header distinguishes `:schema-version` (grammar, 1.0.0) from `:standard-version` (document, 0.4.0) — this is the guard-asks-a-different-question trap inside the guard's own implementation. Cured by reading the gap between filename and number: `deed` / `schema` / `grammar` in the gap means a grammar version, not a conformance claim. **G2 — the allowlist was keyed to `standards`' own layout.** `launcher-standard_praxis.deed` was exempt at a repository root but not when **vendored at any depth** by a consumer. Cured with a `*/launcher-standard_praxis.deed` entry. **G3 — no exemption for dated ADR carriers.** `*/descriptiles/META.a2ml` and the deprecated `*/6a2/META.a2ml` spelling are dated architecture decision records; naming a retired file is precisely what they are for. Both are on disk today (measured 2026-09-22: 164 `descriptiles` directories, 770 deprecated). This is the repo-that-migrated-correctly-looks-worst-to-a-grep pattern — `launch-scaffolder` ranked worst on AC1 *because* it recorded its own migration. **Acceptance control, measured before and after:** | repository | before | after | |---|---|---| | `launch-scaffolder` | 4 | **0** | | `the-nash-equilibrium` | 4 | 4 | | `tma-mark2` | 7 | 7 | | `canonical-ums` | 4 | 4 | | **total over 27 repos** | **19** | **15** | Only genuine defects survive. The shell suite is `19 passed, 0 failed`, rc=0. --- ## Part 2 — the wiring, and the depth trap that forces its shape The gate is copied out **inside the existing `Check documentation` step**, before that step's `rm -rf .standards-checkout`, and run from `$RUNNER_TEMP` in a new step afterwards. That shape is not a preference — it is forced, and it is this file's own established idiom. `validate-hypatia-baseline` already carries the reasoning verbatim: > Move the baseline filter OUT of the scanned tree, then delete the standards > checkout, so `hypatia scan .` only ever sees the CALLER's own files. The docs-gate step sparse-checks `standards`' `scripts/` into `.standards-checkout/scripts/`. The gate's allowlist entries for **its own source** (`scripts/check-launcher-standard-currency.sh`) carry no `*/` prefix, so they stop matching at that depth. Run in place, the gate reports **16 defects on itself** — which would red every consumer. **Self-lint fallback**, copied from the neighbouring gates: prefer the caller's own `scripts/check-launcher-standard-currency.sh` when present, so `standards` validating itself runs the tree under test rather than `main`'s copy. Without it **this pull request's own CI would judge the fix by the version it replaces**. **No second `actions/checkout`** — a new `uses:` would force an `actions.lock` regeneration. The diff adds **zero** `uses:` lines; `git diff -U0 | grep -E "^[+-] *uses:"` is empty. --- ## The tiers, and why they differ Recorded with its evidence in **#991**. | class | predicate | tier | |---|---|---| | `retired-filename` | **stable** — `launcher-standard.a2ml` was deleted upstream (#952) and stays deleted, so a clean caller cannot become defective without editing the citation itself | **fails the job** | | `stale-version` | **time-dependent** — the gate compares against its own `CURRENT_VERSION`, so every correctly-citing caller flips to defect the moment the standard bumps, having done nothing | **`::warning::`, non-blocking** | A baked-in cutoff **date** does not cure `stale-version`. The #505 docs split above can use one because its missing-`CONTRIBUTING` population is **static** — it only shrinks. This population is **regenerated at every bump**. So each `CURRENT_VERSION` bump is a measure-then-arm event, not a date, and #991 records that rule plus the open question of whether the class should ever be promoted. **Arming `retired-filename` today reds zero live callers.** Measured over 26 consumers: 23 clean, 3 defective — `tma-mark2` (archived), `canonical-ums` (archived), `the-nash-equilibrium` (live but AC1-exempt and on the DO-NOT-MERGE list). All three pin a SHA, not `@main`; the 13 `@main`-pinned consumers carry none. The split greps the gate's **typed stdout lines**, not its exit code — both classes return 1, and `DEFECT` lines go to stdout, not stderr. `rc=2` (a usage error, or a seeded self-test mutant that survived) fails **before** the split, so a broken invocation can never read as a clean pass. The gate's `canonical=… expected=…` header is echoed unconditionally, so a vacuous run is visible rather than green. --- ## Proven, not asserted - **The wrapper's mutants die.** Run under `bash -eo pipefail` against seeded gates emitting clean / retired-only / stale-only / mixed / rc=2 / rc=1-with-no-defect: **6 of 6** branches returned the intended exit code. `stale-only` exits **0 with a `::warning::`**; `retired-only` exits **1**. `::warning::` cannot fail a job, so a tier split that is merely *written* proves nothing — this one was executed. - **⭐ The armed fail tier caught the patch that armed it.** This is the finding worth keeping, and it is stronger evidence than the mutant harness — that was simulated, this was live. Commit `418662fb` wired the gate and went **red on its own CI**: the new step's arming-policy comment and its `::error::` both named `launcher-standard.a2ml` literally, and `governance-reusable.yml` is part of every caller's scanned tree, so the gate read its own prose and reported two `retired-filename` defects on it. Correct behaviour, not a gate defect: the fail tier demonstrably reds a real tree. - **Cured in `013fa07d`** by naming the *concept*, not the literal. Nothing is lost — the step already `cat`s the gate's output, which prints the offending `file:line` **and** a fuller remedy than the `::error::` was restating. - **Rejected:** allowlisting `*/governance-reusable.yml`. A consumer workflow naming the retired file **is** a genuine defect, and the allowlist would hide it. - **Why the go/no-go missed it:** it ran against `origin/main`'s tree — *without* this patch — and returned rc=0. **A pre-patch clean run is not evidence the post-patch tree is clean.** Re-run on the patched tree: **rc=0, zero `DEFECT` lines.** This is the "run the tree under test, not `main`'s copy" rule that Part 2 invokes, firing against its own author. - **No new lint debt.** `actionlint` reports the same **5** pre-existing findings before and after the patch; zero introduced. - **The tested wrapper IS the shipped wrapper.** It is extracted from this file by `yq '.jobs.quality.steps[7].run'` rather than maintained as a parallel copy, so there is no second artefact that can drift out of step. The 6-of-6 mutant run above was re-executed against that extraction **after** the `013fa07d` fix, not only before it. ## After this lands **#991** carries the arming policy, the re-arm rule, and the one open owner question (`stale-version`: warn permanently, or warn-until-a-sweep-confirms-zero then promote). #960's AC4 line can be marked `wired`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo --------- Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Signed-off-by: Jonathan D.A. Jewell <jonathan.jewell@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>



Closes two of the four acceptance criteria on #960, and corrects three claims in the mapping spec that measurement has since falsified.
AC4 — the check (
815531de)scripts/check-launcher-standard-currency.sh(100755, 9,987 B) fails a repo that claims launcher-standard compliance while naming a filename or version that no longer exists upstream. #952 (be6c9580, 2026-09-22) deletedlauncher/launcher-standard.a2mland replaced it withlauncher/launcher-standard_praxis.deedat v0.4.0; every downstream citation became dangling, not merely stale.The two defect classes fail independently, which is the point — a repo that updated the version but not the filename is still broken:
launcher-standard.a2mllauncher-standard.a2mllauncher-standard_praxis.deedlauncher-standard_praxis.deedThree design choices worth stating, because each has a tempting wrong answer:
CURRENT_VERSION="0.4.0"is a named constant, and the test suite asserts it equals the:standard-versionin the real deed. A built-in default is fine for a consumer; this repo owns the standard, so its own test has to close the drift loop.:standard-version, never:schema-version. A deed carries two versions — the DEED grammar (1.0.0) and the document (0.4.0). Reading the first yields a number that looks like a newer spec, so the error would read as an upgrade rather than as drift.Proof: 19 assertions across 7 sections, 19/19 passing. Run against
metadatastician/stapelnit finds 4 real defects; against a clean tree, zero. The anti-drift mutant (loweringCURRENT_VERSIONto 0.3.0) produces 2 failures, not 1 — it trips both the anti-drift assertion and the gate's own--self-test, whose stale-version fixture then reads as current. Both are coherent and expected.The mapping-spec corrections (
66eb76b9)Three claims in
1-formats/deed/mappings/launcher-standard-to-praxis-deed.adocwere true when written and are false now. Each is withdrawn in place and dated, rather than silently edited — a spec that quietly changes its mind teaches the next reader to distrust the parts that did not change..deedparser in the estate" — false since D73-C part 2.launcher-common/src/deed.rsis a purpose-built recursive-descent DEED parser, 37,039 B,pub mod deed;atlib.rs:23. This claim had propagated into a memory file and into this campaign's notes; both are corrected.*.launcher.a2mlfiles" — an undercount by more than 5×. Re-measured today: 23 distinct descriptors across 52 on-disk paths, 39 of those paths citing the deleted file. Written as a dated measurement, not a standing fact, because it moves every time a repo is cloned twice. (D73-C downstream: 21 launcher descriptors + trigger/ still name the deleted launcher-standard.a2ml #960's "21" is correct for the question it asked — it counted app names; two of the 23 are set-level.)launch-scaffoldercopy is still v0.2.0, still missing[resolution], still.a2ml" — false in all three parts.diff -qagainst canon reports no difference: 13,803 B at:standard-version "0.4.0".Status, stated honestly (AGENTS.md §6)
The gate is
implementedandtested. It is notwired: no workflow names it. It is executed on every PR here, becausescripts/run-shell-test-suite.shdiscoversscripts/tests/*.shby glob and invokesbash "$f"— which also makes the test file's 100644 mode safe, rather than an exit-126 trap waiting in CI.No consumer repo invokes it, deliberately. Wiring it into the 412 consumers would arm a new scan across all of them on their next pin bump. That is an owner decision, and it is recorded on #960 rather than smuggled in here.
Not in scope
docs/UX-standards/launcher-standard.adocdeclares no version, yet two files cite it at v0.2.0 (docs/audits/launcher-standard-review-2026-05-26.adoc:33,docs/UX-standards/LM-LA-LIFECYCLE-STANDARD.adoc:61). A separate defect, deliberately outside this gate.Refs #960 · #952 · #837 · D73-C in #787
🤖 Generated with Claude Code
https://claude.ai/code/session_01WPSJ7fBhVAMcpSffCBWUDo