From 16d5c6395435850f52db9f5771c63377d8b0deae Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 30 May 2026 22:41:46 +0000 Subject: [PATCH] refactor(doc-truth): consolidate the two #176 guards into one (fold DOC-17 into DOC-16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PRs #476 (DOC-16, banner/primacy/mirror PRESENCE guard) and #475 (DOC-17, over-claim RATCHET) landed in parallel and left two near-identically-named scripts on main — tools/check-doc-truthing.sh and tools/check-doc-overclaims.sh — with overlapping intent. This folds them into a single guard so neither lingers, taking the best of both: * tools/check-doc-truthing.sh is now the one unified, toolchain-free gate. It keeps #476's fail-accumulator + note() structure (reports ALL problems in one run) for the presence invariants (DOC-04/05: matrix primacy + anti- over-claim section + banner pointers + STATE.a2ml mirror keys), and absorbs #475's over-claim ratchet (DOC-08/09) as a fourth check feeding the same accumulator, plus the `--update` re-baseline mode. Presence-checking covers the banners (where "production-ready" legitimately appears); the frozen tools/doc-overclaims.allow baseline adds phrase detection without false positives. * tools/check-doc-overclaims.sh deleted; tools/doc-overclaims.allow kept (13 signatures unchanged), now owned by the unified script. * CI: the two "Issue #176" build steps collapse into one. * justfile: `guard` runs the single script; `doc-overclaims-bless` → `doc-truth-bless` (calls `check-doc-truthing.sh --update`). * Ledger: DOC-16 rewritten to describe the unified guard; DOC-17 marked "folded into DOC-16"; matrix change-control + STATE.a2ml mirror updated. Pure consolidation — no behavioural change to either check, no compiler code touched. Verified: unified guard green; `--update` green; both negative directions (new over-claim phrase / dropped banner) bite. Refs #176 Refs #175 https://claude.ai/code/session_01HR1GHjBfNdfcFZm1XiLXK4 --- .github/workflows/ci.yml | 21 ++---- .machine_readable/6a2/STATE.a2ml | 2 +- docs/CAPABILITY-MATRIX.adoc | 11 ++- docs/TECH-DEBT.adoc | 54 +++++++------- justfile | 15 ++-- tools/check-doc-overclaims.sh | 117 ------------------------------- tools/check-doc-truthing.sh | 115 ++++++++++++++++++++++++++---- tools/doc-overclaims.allow | 7 +- 8 files changed, 155 insertions(+), 187 deletions(-) delete mode 100755 tools/check-doc-overclaims.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c32b414..b704f5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,22 +75,15 @@ jobs: # rationale + recovery instructions. run: ./tools/check-no-extension-ts.sh - - name: Issue #176 — block status-doc truthing re-drift - # docs/CAPABILITY-MATRIX.adoc is the single authoritative status - # doc. This guard fails if the over-claiming docs lose their - # banners pointing back at it, if the matrix stops self-declaring - # primacy / loses its anti-over-claim section, or if STATE.a2ml - # stops flagging itself as a mirror (DOC-01..09). Toolchain-free. + - name: Issue #176 — doc-truthing re-drift guard (DOC-01..09) + # Single toolchain-free gate enforcing both halves of the doc-truthing + # MONITOR: the presence invariants (DOC-04/05 — banner pointers, matrix + # primacy + anti-over-claim section, STATE.a2ml mirror keys) AND the + # over-claim ratchet (DOC-08/09 — fails any NEW backend-breadth / + # "production-ready" / stdlib-% phrase beyond tools/doc-overclaims.allow). + # See tools/check-doc-truthing.sh. run: ./tools/check-doc-truthing.sh - - name: Issue #176 — over-claim ratchet (DOC-08/09) - # Companion to the banner guard above (DOC-16): a frozen-baseline - # ratchet that fails any *new* backend-breadth / "production-ready" - # / stdlib-% phrase beyond tools/doc-overclaims.allow — the - # DOC-08/09 detection the banner guard deliberately leaves to bots. - # Toolchain-free. See tools/check-doc-overclaims.sh (DOC-17). - run: ./tools/check-doc-overclaims.sh - - name: Check formatting run: opam exec -- dune build @fmt diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/6a2/STATE.a2ml index f97f4b2..242235f 100644 --- a/.machine_readable/6a2/STATE.a2ml +++ b/.machine_readable/6a2/STATE.a2ml @@ -9,7 +9,7 @@ status = "active" authoritative-status-doc = "docs/CAPABILITY-MATRIX.adoc" drift-flag = "STALE as of 2026-05-23 PM: this file's [components]/[features]/[project-context] still predate landed PRs since 2026-05-19. It MIRRORS, it does not LEAD. Authoritative sources by topic — readiness: docs/CAPABILITY-MATRIX.adoc; spine + AS↔typed-wasm contract: docs/ECOSYSTEM.adoc; coordination ledger / critical path: docs/TECH-DEBT.adoc; test taxonomy + PR-level gates: docs/standards/TESTING.adoc (added 2026-05-23); panic-attack SOP: docs/standards/PANIC-ATTACK.adoc (added 2026-05-23). Gate baseline: CAPABILITY-MATRIX records 260/260 at 2026-05-19 reconstruction; subsequent borrow-checker work has lifted it (#240 → 263, return-escape → 271/274, &mut surface → 278/281). The exact live number for any given commit comes from `dune runtest --force` — do not hard-code it here. (DOC-05, issue #176.)" session-note-2026-05-26-publish-104 = "ISSUE #104 CLOSED — FIRST NPM PUBLISH LANDED. @hyperpolymath/affine-vscode@0.1.0 is now on registry.npmjs.org. Owner-action sequence completed today: (1) npm org `hyperpolymath` created on free public-package tier; (2) Granular Access Token generated for scope @hyperpolymath/* with Read+Write, uploaded to repo secret NPM_TOKEN; (3) signed annotated tag affine-vscode-v0.1.0 pushed at origin/main (RSA key 9639451754496E51D6B537CAD119017EBF695AB1); (4) .github/workflows/affine-vscode-publish.yml ran green — `npm publish --access public` succeeded; (5) `npm view @hyperpolymath/affine-vscode` resolves. Downstream consumers (my-lang#66, standards#160) which un-vendored their adapters on 2026-05-21 now have a working `npm install` path; vscode-smoke workflow (skipped per #381 while package was unpublished) will start exercising the live package on its next PR run. Lineage for future @hyperpolymath/* publishes: org+token are reusable; mirror `affine-vscode-publish.yml`'s shape (tag trigger, version-match guard, .npmrc write from secret, npm publish --access public). NPM_TOKEN rotation advised post-publish (token value transited a session transcript during wire-up); see .machine_readable/6a2/PLAYBOOK.a2ml [npm-publish] for the runbook." -session-note-2026-05-30 = "DOC-16 + DOC-17 — DOC-TRUTHING MONITOR FULLY MECHANICAL (issue #176). Two complementary in-repo guards now enforce the doc-truthing rules that were previously external-bot-only. DOC-16 (PR #476, tools/check-doc-truthing.sh): banner-PRESENCE invariant — fails if any over-claiming doc loses its CAPABILITY-MATRIX banner, if the matrix stops self-declaring primacy / loses its 'What AffineScript is NOT' section, or if STATE.a2ml drops its mirror keys; deliberately does NOT phrase-scan (a naive grep false-positives on the negating banners + future-roadmap text). DOC-17 (PR #475, tools/check-doc-overclaims.sh + tools/doc-overclaims.allow): the phrase-detection complement — a frozen-baseline RATCHET over README + docs/** (excluding CAPABILITY-MATRIX + TECH-DEBT, which quote the rule) that fails any NEW backend-breadth / 'production-ready' / stdlib-% occurrence beyond the 13-line baseline (all current entries legit: future-tense roadmap milestones + dated history snapshots + corrective banners); re-baseline via `--update` / `just doc-overclaims-bless`, diff = audit trail. Both wired into `just check` (guard recipe) + ci.yml build job, both toolchain-free bash (run without OCaml). #475 was originally a superset of #476 (built in parallel, same session); on discovering #476 had merged first, #475 was reworked to drop the duplicated banner check and keep only the unique ratchet, renamed check-doc-truth.sh→check-doc-overclaims.sh to avoid the name clash (DOC-DEDUP-clean). Gate-number policy unchanged (DOC-05): live `dune runtest --force` count never hard-coded. No compiler code touched. Refs #176 / #175." +session-note-2026-05-30 = "DOC-16 + DOC-17 — DOC-TRUTHING MONITOR FULLY MECHANICAL (issue #176). Two complementary in-repo guards now enforce the doc-truthing rules that were previously external-bot-only. DOC-16 (PR #476, tools/check-doc-truthing.sh): banner-PRESENCE invariant — fails if any over-claiming doc loses its CAPABILITY-MATRIX banner, if the matrix stops self-declaring primacy / loses its 'What AffineScript is NOT' section, or if STATE.a2ml drops its mirror keys; deliberately does NOT phrase-scan (a naive grep false-positives on the negating banners + future-roadmap text). DOC-17 (PR #475, tools/check-doc-overclaims.sh + tools/doc-overclaims.allow): the phrase-detection complement — a frozen-baseline RATCHET over README + docs/** (excluding CAPABILITY-MATRIX + TECH-DEBT, which quote the rule) that fails any NEW backend-breadth / 'production-ready' / stdlib-% occurrence beyond the 13-line baseline (all current entries legit: future-tense roadmap milestones + dated history snapshots + corrective banners); re-baseline via `--update` / `just doc-overclaims-bless`, diff = audit trail. Both wired into `just check` (guard recipe) + ci.yml build job, both toolchain-free bash (run without OCaml). #475 was originally a superset of #476 (built in parallel, same session); on discovering #476 had merged first, #475 was reworked to drop the duplicated banner check and keep only the unique ratchet, renamed check-doc-truth.sh→check-doc-overclaims.sh to avoid the name clash (DOC-DEDUP-clean). FOLLOW-UP (same day, post-#475-merge): the two near-identically-named guards were consolidated so neither lingers — the ratchet (incl. `--update` mode + tools/doc-overclaims.allow baseline) was folded INTO tools/check-doc-truthing.sh using #476's fail-accumulator/note() structure, and tools/check-doc-overclaims.sh was deleted. A SINGLE toolchain-free guard now enforces both presence invariants (DOC-04/05) and the over-claim ratchet (DOC-08/09) in one run; one CI step; the `guard` recipe runs it; re-baseline via `just doc-truth-bless`. DOC-17 folded into DOC-16 in the ledger. Gate-number policy unchanged (DOC-05): live `dune runtest --force` count never hard-coded. No compiler code touched. Refs #176 / #175." session-note-2026-05-26 = "MIGRATION-ASSISTANT PHASE 2C + REPO-TIDY STACK (T-1..T-7) + STDLIB BLOCKER CLOSURES. (1) PR #357 — feat(res-to-affine) Phase 2c on branch claude/epic-gauss-Mbi0E: tree-sitter walker extended from #322's single Side_effect_import detector to all six anti-patterns. New detectors in tools/res-to-affine/walker.ml — detect_raw_js (any extension_expression node), detect_untyped_exception (try_expression / call to value_identifier \"raise\" / member_expression starting with Js.Exn or ending with Promise.catch), detect_mutable_global (top-level let_declaration whose body is call to value_identifier \"ref\", OR top-level mutation_expression), detect_inline_callback_record (>=3 inline function values in a record literal or a call_expression's arguments list — handles direct function children + labeled_argument + record_field wrappers), detect_oversized_function (function node whose stop.row - start.row + 1 > 50). Module-toplevel predicate refactored to a single at_module_toplevel helper that walks the ancestor chain refusing on `function` or `let_binding` body. Findings deduped by (kind, line) so the AST walker doesn't emit more bullets than the line-based scanner. CLI flipped --engine=walker to the default in tools/res-to-affine/main.ml (scanner remains as fallback when grammar / tree-sitter CLI missing — pre-existing graceful-fallback path from #322 unchanged). Scanner.kind extended with Inline_callback_record + Oversized_function variants; scanner.ml gives them labels + guidance. New fixture test/fixtures/phase2c.res exercises the two walker-only kinds. test_walker.ml grew per-kind tests under three new suites (walker-side-effect-import / walker-phase2c-parity / walker-phase2c-new-kinds). README + walker.mli updated. (2) Phase 2c CI fix push (e7a3a44): initial Phase 2c commit had build+lint failing; defensive rewrite replaced the labeled-only `mk_finding ~kind:K ~line:L ~excerpt:E :: acc` emit pattern with explicit `let finding : Scanner.finding = { ... } in finding :: acc` matching Phase 2b's working style, plus replaced non-ASCII glyphs in comments (≥ → >=, … → ...) defensively. (3) DIAGNOSED: `main` itself is red. PR #359 (T-1, pure file-rename + delete + one-line CONTRIBUTING.md edit, zero OCaml touched) also fails on build+lint. That conclusively shows the build failure is inherited from main, not introduced by Phase 2c or any tidy work. Matches CLAUDE.md §\"CI signal reliability\" — auto-merge fires even when build is red; the historical pattern of #334/#335/#336/#344 landing red applies. Root cause on main is NOT diagnosed in this session (needs the actual `dune build` log; WebFetch on the actions UI returns React skeletons, not log content; container has no OCaml toolchain to repro locally). Filed implicit follow-up: someone with shell access should run `gh run view --log-failed ` against any of the recent failing runs to identify the underlying lib/ compile error. (4) REPO-TIDY STACK (T-1..T-7) — six small PRs landed off origin/main, each reviewable in isolation, none touching .ml/.mli, all inheriting the same baseline build/lint failure as PR #359 (proof above). T-1 PR #359 *MERGED* — AI.a2ml → 0-AI-MANIFEST.a2ml (Hypatia root_hygiene rule + sibling-repo convention), delete AI.djot (superseded), docs/TECH-DEBT-alt.adoc → docs/TECH-DEBT.adoc (restoring the canonical name every cross-link in the repo already points at; PR #356's -alt suffix during the #351 split is dead weight post-#355). T-2 PR #360 — delete 2,182 lines of submarine-game docs (DAMAGE-SYSTEM.md, CONTROLS-REFERENCE.md, GAME-BUNDLING-STRATEGY.md), zero cross-references. T-3 PR #365 — 13 loose root .md/.adoc moved into docs/ subtree (ABI-FFI-README → docs/reference/ABI-FFI.md, ALPHA-1-RELEASE-NOTES → docs/history/, BACKEND-{ANALYSIS,IMPLEMENTATION} → docs/architecture/, COMPILER-CAPABILITIES → docs/reference/, EXPLAINME/KNOWN-ISSUES/NAVIGATION/PROOF-NEEDS/ROADMAP → docs/, LICENSING-GUIDE/SECURITY-SETUP → docs/governance/, RSR_OUTLINE → docs/standards/RSR-OUTLINE.adoc), two new subdirs docs/architecture/ + docs/reference/, cross-refs fixed in CAPABILITY-MATRIX / BACKEND-IMPLEMENTATION / CONTRIBUTING / NAVIGATION / res-to-affine; root drops 17→5 community-health files. T-4 PR #366 — RSR_COMPLIANCE.adoc at root with four documented deviations (no guix.scm/flake.nix; STATE.scm substituted by .machine_readable/6a2/STATE.a2ml because .scm is reserved for Guix per language policy; 7 TS exemptions; 2 runtime exemptions — all cite CLAUDE.md as authoritative). T-5 PR #367 — wiki/README.md rewrite (drops ~20 dead links to non-existent .md files, updates stale ../ROADMAP.md → ../docs/ROADMAP.adoc path, annotates Features-at-a-Glance examples with current maturity, switches Ownership example from &File/&mut File sigil syntax to canonical ref File/mut File keyword types) + parse-only honesty banner on wiki/language-reference/dependent-types.md + partial honesty banner on wiki/language-reference/traits.md. T-6 — direct issue triage, no PR: closed #246 (ESC-02 JSON.t — stdlib/json.affine delivers Json ADT + encoders/decoders/get_field/stringify) and #247 (ESC-03 Dict.t — stdlib/dict.affine delivers empty/from_pairs/get/contains/size/insert/set/remove/keys/values), both with confirmation comments referencing the LANDED status in docs/TECH-DEBT.adoc STDLIB-02/03 rows. T-7 this PR — adds this session-note + the T-1..T-7 ledger entry below in docs/TECH-DEBT.adoc. (5) ALSO RESOLVED EARLIER IN SESSION (pre-T-6, as part of addressing the sustainabot tracker blockers the user asked about): #161 (Json) and #162 (Dict) closed with explicit owner-author-acknowledged closure comments dated 2026-05-24; this session was the explicit owner request to act on those. Migration-assistant tracker #57 stays open — Phase 2c lands #322's Phase 2b → 2c walker work but Phase 3 (partial translation of pure-structural forms — the phase the sustainabot tracker's exit criterion 3 specifically gates on) remains unstarted. (6) OPEN PRs AT SESSION END: #357 (Phase 2c, ready to merge — author/owner discretion on the baseline-red CI), #360/#365/#366/#367 (T-2/T-3/T-4/T-5, same baseline-red situation; pure-rename / pure-delete / pure-doc-add changes, no behavioural risk). (7) NOT DONE IN THIS SESSION: actual root-cause diagnosis of main's red build/lint; ~20 missing wiki pages (installation, hello-world, expressions, errors, package-manager, lsp, formatter, linter, stdlib subpages, design/*); guix.scm or flake.nix addition; full wiki content refresh beyond README + two banners; sync of wiki/ to the GitHub-wiki upstream repo (separate git repo, owner pushes manually). (8) CROSS-REPO: this session is AffineScript-only — the gitbot-fleet sustainabot tracker that prompted #161/#162/#57 lives in a different repo and was not touched here." typed-wasm-formalisation-2026-05-23 = "AS↔TYPED-WASM INTERFACE FORMALISED + WIDENING ROADMAP + TWO PROPOSED ADRs. (1) docs/specs/TYPED-WASM-INTERFACE.adoc + .a2ml — formal spec of the v1 interface (was previously scattered across ECOSYSTEM.adoc + code comments in lib/codegen.ml, tw_interface.ml, tw_verify.ml). Captures: enforced surface (L7 aliasing + L10 linearity + L13 module isolation negative-form); carrier binary layout (u32 entry_count + per-entry [u32 func_index | u8 param_count | u8[n] param_kind | u8 ret_kind], kind ∈ {0 Unrestricted, 1 Linear, 2 SharedBorrow, 3 ExclBorrow}, all LE, omit-when-empty, no version field in v1); producer machinery file-line pointers (lib/codegen.ml ~110-177 + ctx.ownership_annots ~2312/~2629); consumer machinery (tw_verify.ml 332 LOC, tw_interface.ml 276 LOC, primary entry verify_from_module); CLI surface (verify / verify-boundary / verify-bridge / interface — verify-boundary's pre-2026-04-19 silent-success bug fixed by f6089a2); test coverage (test_tw_isolation.ml 5 cases + E2E Boundary Verify 3 cases + ownership-roundtrip 3 cases; honest gap: no C5.1 cross-compat fixtures shipped); multi-producer responsibilities (AS = ref producer + spec of record until C5.1; ephapax = second producer same format; typed-wasm = spec + Rust verifier + cross-compat target); deliberate non-features NF-001..NF-005 with roadmap anchors; stability promise (v1 frozen; unilateral changes forbidden). (2) docs/specs/TYPED-WASM-ROADMAP.adoc + .a2ml — making typed-wasm a natural + optimal target. Five tranches with unblock graph: A (ergonomics, no ABI change: A1 --typed-wasm gating flag, A2 report-typed-wasm JSON, A3 extract ownership-section to dedicated module, A4 diagnostic span parity) → B (schema hygiene, additive single-byte ABI: B1 = ADR-020) → C (compiler-side foundations for L1–6/L14–16: C1 region inference / CORE-01 Phase 3, C2 session-type+capability tracking, C3 CONV-02/ADR-016 S2..S4 async recogniser, C4 capability-typed externs) → D (multi-producer ABI widening: D1 = ADR-021, D2 affinescript.regions, D3 affinescript.{capabilities,session,choreography}) → E (cross-compat closure: E1 INT-12/CONV-05 fixtures into typed-wasm C5.1, E2 Rust-verifier parity out-of-scope-here). Recommended sequencing: A1→A3→A2→E1→B1→A4→D1→C1..C4→D2/D3→E2. (3) ADR-020 (PROPOSED, META.a2ml): ownership-section schema versioning — v1 unversioned → v2 with 0xAF sentinel + u8 version + entry_count. v1 readers fail cleanly on v2 (bad entry-count parse); v2 readers dispatch on sentinel. Coordinated landing: verifier ships parse first, producers flip emit together. (4) ADR-021 (PROPOSED, META.a2ml): multi-producer ABI coordination model — four axes (spec authority OCaml→Rust on C5.1 closure; coordinated landing protocol; test parity protocol; conflict resolution via serialised queue owned by typed-wasm). ADR-020 is itself the first test of ADR-021's protocol. (5) Cross-links: ECOSYSTEM.adoc §contract paragraph now points at TYPED-WASM-INTERFACE.adoc as authoritative; CAPABILITY-MATRIX.adoc typed-wasm row links to INTERFACE + ROADMAP and notes L13 alongside L7/L10; TECH-DEBT.adoc Stage E section gets header pointer + DOC-13/14/15 ledger entries (interface, roadmap, ADRs); docs/README.adoc + NAVIGATION.adoc list both new specs. (6) Pure documentation work — no compiler code changed, no behaviour change. Both ADRs require owner ratification before they bind." stage-d-batch-2026-05-23 = "INT-01 ::-in-value-expr + BUG-005 deferred fixture + STDLIB-04 audit. (1) INT-01 follow-up: lib/parser.mly line ~835 — added `upper_ident COLONCOLON lower_ident` production emitting `ExprField(ExprVar Mod, lower_ident)`, the same AST shape `Mod.fn` already produces. Disambiguated from the line-above `Type::Variant` rule by lower_ident vs upper_ident. No resolver change required: Resolve.lower_qualified_value_paths handles both `.` and `::` syntaxes identically because the lowering pattern-matches on the ExprField shape, not the source separator. test/e2e/fixtures/cross_caller_qualified_colon{,_alias}.affine + 2 alcotest cases in qualified_value_tests pin both `use Mod; Mod::fn(x)` and `use Mod as M; M::fn(x)`. The remaining INT-01 'parser gap, not resolver' note in the ledger is now closed. (2) BUG-005 deferred regression test landed (test/test_e2e.ml, wasm_gc_loud_fail_tests): `fn main() -> Int { return totally_undefined_callee(42); }` is fed directly to Codegen_gc.generate_gc_module (no resolve step) and the emitted error must contain the unknown name — which UnboundFunction's format string includes verbatim. Closes the deferred-status entry on the [[closed-bug]] BUG-005 record. (3) docs/STDLIB-EXTERN-AUDIT.adoc — full triage of 135 extern fn + 24 extern type across 11 stdlib files into 4 classes (built-in / typed-boundary-bridge / adapter-Deno / adapter-Node); per-row status (done/partial/stub-only) and unblock condition for each module. STDLIB-04's ledger entry now points here. Implementation PRs close one row at a time; the audit doc is the canonical roadmap, not STATE.a2ml. (4) Not yet verified locally — no OCaml toolchain in this remote execution environment. CI is the verification surface; parser change is low-risk (single production, no Menhir conflict — `upper_ident COLONCOLON lower_ident` is unambiguous against the prior `upper_ident COLONCOLON upper_ident` rule by token class)." diff --git a/docs/CAPABILITY-MATRIX.adoc b/docs/CAPABILITY-MATRIX.adoc index 564e0f5..dcc0cc0 100644 --- a/docs/CAPABILITY-MATRIX.adoc +++ b/docs/CAPABILITY-MATRIX.adoc @@ -222,12 +222,11 @@ current authoring frontier. A few primitives remain `extern` builtins. Any PR that re-introduces backend-breadth, "production-ready", or stdlib-percentage over-claims must be rejected (DOC-01..09 / issue #176; Hypatia/gitbot `DOC-FORMAT`/`DOC-DEDUP` rules). This is enforced -*mechanically* in-repo (wired into `just check` + CI): `tools/check-doc-truthing.sh` -(DOC-16) holds the banner/primacy/mirror invariant, and -`tools/check-doc-overclaims.sh` (DOC-17) ratchets against new over-claim -phrasings beyond the frozen `tools/doc-overclaims.allow` baseline. Update -*this file* in the same PR as any capability change; `STATE.a2ml` mirrors, -it does not lead. +*mechanically* in-repo by the single guard `tools/check-doc-truthing.sh` +(DOC-16; wired into `just check` + CI): it holds the banner/primacy/mirror +invariant *and* ratchets against new over-claim phrasings beyond the frozen +`tools/doc-overclaims.allow` baseline. Update *this file* in the same PR as +any capability change; `STATE.a2ml` mirrors, it does not lead. == See also diff --git a/docs/TECH-DEBT.adoc b/docs/TECH-DEBT.adoc index 1ec6859..a9620c6 100644 --- a/docs/TECH-DEBT.adoc +++ b/docs/TECH-DEBT.adoc @@ -114,35 +114,37 @@ ABI coordination model (four axes: spec authority / coordinated landing / test parity / conflict resolution). Both filed in META.a2ml; ADR-020 lands first as the first test of ADR-021's protocol. Both require owner ratification. |*PROPOSED 2026-05-23* -|DOC-16 |In-repo enforcement of the DOC-04/05 truthing invariant — -`tools/check-doc-truthing.sh` (toolchain-free bash) fails if any -over-claiming doc loses its `CAPABILITY-MATRIX.adoc` banner, if the -matrix stops self-declaring primacy or loses its "What AffineScript is -NOT" section, or if `STATE.a2ml` drops its mirror keys. Wired into -`just check` (the `guard` recipe) and CI (`ci.yml` build job). Converts -the DOC-08/09 MONITOR posture from external-bot-only to a first-class -in-repo gate. |*DONE 2026-05-30* -|DOC-17 |Over-claim ratchet — the *phrase-detection* complement to DOC-16. -`tools/check-doc-overclaims.sh` + `tools/doc-overclaims.allow` baseline: -a frozen-signature ratchet over README + `docs/**` (excluding the two -governance docs that quote the rule — CAPABILITY-MATRIX + this ledger) -fails any *new* backend-breadth / "production-ready" / stdlib-% phrase -beyond the 13-line baseline (future-tense roadmap milestones, dated -history snapshots, the corrective banners — none a live over-claim). -DOC-16 deliberately checks banner *presence* not phrasing (a naive grep -false-positives); the ratchet closes that gap without false positives -because the legitimate set is frozen and only *new* phrases fail. -Re-baseline via `--update` / `just doc-overclaims-bless`; the diff is -the audit trail. Wired into `just check` + CI (toolchain-free bash). -|*DONE 2026-05-30* +|DOC-16 |In-repo doc-truthing re-drift guard — `tools/check-doc-truthing.sh` +(toolchain-free bash), the single gate enforcing *both* halves of the +MONITOR. *Presence invariants (DOC-04/05):* fails if any over-claiming doc +loses its `CAPABILITY-MATRIX.adoc` banner, if the matrix stops +self-declaring primacy or loses its "What AffineScript is NOT" section, or +if `STATE.a2ml` drops its mirror keys. *Over-claim ratchet (DOC-08/09):* +a frozen-signature baseline (`tools/doc-overclaims.allow`) over README + +`docs/**` (excluding the two governance docs that quote the rule — +CAPABILITY-MATRIX + this ledger) fails any *new* backend-breadth / +"production-ready" / stdlib-% phrase beyond the 13-line accepted set +(future-tense roadmap milestones, dated history snapshots, the corrective +banners — none a live over-claim). Presence-checking handles the banners +(where "production-ready" legitimately appears); the frozen baseline adds +phrase detection without false positives. Re-baseline via `--update` / +`just doc-truth-bless`; the diff is the audit trail. Wired into +`just check` (the `guard` recipe) and CI (`ci.yml` build job). Converts the +DOC-08/09 MONITOR posture from external-bot-only to a first-class in-repo +gate. |*DONE 2026-05-30* +|DOC-17 |Over-claim ratchet — *folded into DOC-16.* Briefly shipped as a +separate `tools/check-doc-overclaims.sh` (PR #475) alongside #476's banner +guard; consolidated into the single `tools/check-doc-truthing.sh` so the +two near-identically-named guards do not linger. The ratchet behaviour + +`tools/doc-overclaims.allow` baseline are unchanged — see DOC-16. +|*DONE 2026-05-30 (consolidated)* |=== MONITOR enforcement (DOC-08/09): any PR re-introducing backend-breadth, -"production-ready", or stdlib-percentage over-claims must be rejected. -As of 2026-05-30 this is enforced in-repo on *both* halves: DOC-16 -(`tools/check-doc-truthing.sh`) holds the banner/primacy/mirror presence -invariant, and DOC-17 (`tools/check-doc-overclaims.sh`) ratchets against -new over-claim *phrasings*. The external Hypatia/gitbot DOC rules remain +"production-ready", or stdlib-percentage over-claims must be rejected. As of +2026-05-30 this is enforced in-repo by the single unified guard +`tools/check-doc-truthing.sh` (DOC-16) — presence invariants *and* the +over-claim ratchet in one run. The external Hypatia/gitbot DOC rules remain the estate-level backstop for anything outside both nets. == Section B — CORE (compiler soundness / completeness) diff --git a/justfile b/justfile index 94a234f..178fb40 100644 --- a/justfile +++ b/justfile @@ -90,19 +90,18 @@ check: lint test guard # Regression guards: # - Issue #35 Phase 3: fails if extension.ts reappears under # editors/vscode/src or any face's vscode extension dir. -# - Issue #176 (DOC-16): fails if the status-doc truthing banners -# re-drift (authoritative matrix pointers + STATE.a2ml mirror keys). -# - Issue #176 (DOC-17): fails if a NEW backend-breadth / "production- -# ready" / stdlib-% over-claim appears beyond the frozen baseline. +# - Issue #176 (DOC-01..09): the unified doc-truthing guard — fails if the +# status-doc banners / matrix primacy / STATE.a2ml mirror keys re-drift, +# OR if a NEW backend-breadth / "production-ready" / stdlib-% over-claim +# appears beyond the frozen baseline. guard: ./tools/check-no-extension-ts.sh ./tools/check-doc-truthing.sh - ./tools/check-doc-overclaims.sh -# Re-baseline the over-claim ledger (DOC-17) after a deliberate, legitimate +# Re-baseline the doc-truthing over-claim ledger after a deliberate, legitimate # change (e.g. a new dated roadmap milestone). Commit the .allow diff. -doc-overclaims-bless: - ./tools/check-doc-overclaims.sh --update +doc-truth-bless: + ./tools/check-doc-truthing.sh --update # ── Compiler subcommands ────────────────────────────────────────────────────── diff --git a/tools/check-doc-overclaims.sh b/tools/check-doc-overclaims.sh deleted file mode 100755 index b9a51e0..0000000 --- a/tools/check-doc-overclaims.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: MPL-2.0 -# SPDX-FileCopyrightText: 2024-2026 hyperpolymath -# -# Over-claim ratchet for issue #176 (DOC-08/09, ledger row DOC-17). -# -# Companion to tools/check-doc-truthing.sh (DOC-16), which enforces the -# *presence* of the corrective banners + matrix primacy + STATE.a2ml mirror -# keys. That guard deliberately does NOT phrase-scan, because "production-ready" -# legitimately appears inside the negating banners and future-roadmap sections, -# so a naive grep false-positives — and it therefore leaves novel over-claim -# *phrasings* (the DOC-08/09 MONITOR) to the external Hypatia/gitbot bots. -# -# This guard closes exactly that gap without the false-positive problem, via a -# ratchet: the current accepted set of over-claim-phrase occurrences (every one -# legitimate today — future-tense roadmap milestones, dated history snapshots, -# the corrective banners) is frozen in tools/doc-overclaims.allow. Any *new* -# occurrence not in that baseline fails the build. The baseline is a sorted, -# signature-keyed (path + normalised line) ledger, robust to line moves, and -# its growth is a reviewable diff — the human-review signal the DOC rules -# describe, now in-repo and automatic. -# -# The two authoritative governance docs that define/quote the rule itself -# (docs/CAPABILITY-MATRIX.adoc, docs/TECH-DEBT.adoc) are excluded — they -# legitimately contain the anti-claims, and editing their rule-text must not -# churn the baseline. The banner docs are covered by check-doc-truthing.sh. -# -# Re-baselining (only when a NEW occurrence is genuinely legitimate — e.g. a -# new dated roadmap milestone): run `./tools/check-doc-overclaims.sh --update` -# (or `just doc-overclaims-bless`) and commit the doc-overclaims.allow diff in -# the same PR. The diff is the audit trail. -# -# Wired into: -# - just check (via the `guard` recipe in justfile) -# - CI (.github/workflows/ci.yml, build job) - -set -euo pipefail - -cd "$(dirname "$0")/.." - -ALLOW="tools/doc-overclaims.allow" - -# Over-claim phrase families (DOC-08 backend-breadth / DOC-09 production-ready -# + stdlib-percentage). Patterns are intentionally broad: the frozen baseline -# gives zero false positives on existing content, so breadth only raises recall -# on genuinely new occurrences. -PATTERN='production[- ]ready|production backends?|[0-9]+[[:space:]]+(production|complete)[[:space:]]+backends?|stdlib[^|]*100%|100%[^|]*stdlib|N production backend' - -# Emit one normalised signature per over-claim hit: "relpathline", with -# the line's internal whitespace collapsed and trimmed (robust to re-indent / -# re-flow; sensitive to the claim text itself). Sorted + de-duplicated. -scan_overclaims() { - # The two authoritative governance docs are excluded: they define and quote - # the banned phrases as the rule itself (anti-claims), so scanning them would - # only re-flag the rule text. Banner presence in these + the over-claiming - # docs is the job of tools/check-doc-truthing.sh (DOC-16). - grep -rniE "$PATTERN" README.adoc docs/ 2>/dev/null \ - --exclude="CAPABILITY-MATRIX.adoc" \ - --exclude="TECH-DEBT.adoc" \ - | sed -E 's/^([^:]+):[0-9]+:/\1\t/' \ - | awk -F'\t' 'BEGIN { OFS = "\t" } - { - line = $2 - gsub(/[[:space:]]+/, " ", line) - sub(/^ /, "", line) - sub(/ $/, "", line) - print $1, line - }' \ - | LC_ALL=C sort -u -} - -# --- --update / --bless mode: regenerate the baseline ----------------------- -if [ "${1:-}" = "--update" ] || [ "${1:-}" = "--bless" ]; then - { - echo "# SPDX-License-Identifier: MPL-2.0" - echo "# SPDX-FileCopyrightText: 2024-2026 hyperpolymath" - echo "# Over-claim baseline (issue #176, DOC-08/09 / ledger DOC-17) — the" - echo "# frozen set of accepted over-claim-phrase occurrences. Regenerate with" - echo "# \`./tools/check-doc-overclaims.sh --update\`. Each line is a" - echo "# \"relpathnormalised-line\" signature. A new signature not listed" - echo "# here fails CI; adding one is a deliberate, reviewable act. Current" - echo "# entries are future-tense roadmap milestones, dated history snapshots," - echo "# and the corrective banners — none is a live over-claim." - scan_overclaims - } > "$ALLOW" - echo "OK: regenerated $ALLOW ($(grep -cvE '^#' "$ALLOW") signatures)." - exit 0 -fi - -if [ ! -f "$ALLOW" ]; then - echo "ERROR: $ALLOW is missing. Run ./tools/check-doc-overclaims.sh --update" >&2 - echo " to create the over-claim baseline." >&2 - exit 1 -fi - -current="$(scan_overclaims)" -allowed="$(grep -vE '^#' "$ALLOW" | LC_ALL=C sort -u || true)" -new_hits="$(LC_ALL=C comm -13 <(printf '%s\n' "$allowed") <(printf '%s\n' "$current") | sed '/^$/d')" - -if [ -n "$new_hits" ]; then - echo "ERROR: new over-claim(s) detected in status docs (issue #176, DOC-08/09)." >&2 - echo "" >&2 - echo "The authoritative readiness source is docs/CAPABILITY-MATRIX.adoc, which" >&2 - echo "forbids re-introducing backend-breadth / \"production-ready\" /" >&2 - echo "stdlib-percentage over-claims. These occurrences are not in the frozen" >&2 - echo "baseline ($ALLOW):" >&2 - echo "" >&2 - printf '%s\n' "$new_hits" | sed 's/\t/ :: /; s/^/ /' >&2 - echo "" >&2 - echo "Fix the over-claim (preferred), or — if it is genuinely legitimate" >&2 - echo "(e.g. a new dated roadmap milestone) — re-baseline with:" >&2 - echo " ./tools/check-doc-overclaims.sh --update # or: just doc-overclaims-bless" >&2 - echo "and commit the tools/doc-overclaims.allow diff in the same PR." >&2 - exit 1 -fi - -echo "OK: no new over-claims beyond the frozen baseline ($ALLOW)." diff --git a/tools/check-doc-truthing.sh b/tools/check-doc-truthing.sh index 9ac6cee..a939e92 100755 --- a/tools/check-doc-truthing.sh +++ b/tools/check-doc-truthing.sh @@ -2,25 +2,43 @@ # SPDX-License-Identifier: MPL-2.0 # Copyright (c) 2026 Jonathan D.A. Jewell # -# Doc-truthing re-drift guard for issue #176 (DOC-01..09). +# Unified doc-truthing re-drift guard for issue #176 (DOC-01..09). # # Authoritative feature-readiness status lives in docs/CAPABILITY-MATRIX.adoc. # Several historical/architectural docs are known to over-claim (backend # breadth, "production-ready", stdlib percentage). DOC-04/05 neutralised them # with an *authoritative banner* that points every reader back at the matrix, # and made the matrix self-declare its primacy + carry an anti-over-claim -# section. +# section. Until now those invariants were enforced only by the external +# Hypatia/gitbot review bots (the MONITOR posture in issue #176). # -# Until now that invariant was enforced only by the external Hypatia/gitbot -# review bots (the MONITOR posture in issue #176). This guard makes it a -# first-class, in-repo, toolchain-free gate: it fails if any of the banner -# pointers, the matrix's self-declaration, the anti-over-claim section, or the -# STATE.a2ml mirror keys are removed — i.e. if the docs start to re-drift. +# This is a first-class, in-repo, toolchain-free gate that enforces *both* +# halves of the MONITOR in a single run (consolidated from the two guards that +# briefly co-existed as DOC-16 + DOC-17 — check-doc-truthing.sh and +# check-doc-overclaims.sh — into one script with no overlap): # -# It deliberately checks *banner presence*, not phrase blocklists: the word -# "production-ready" legitimately appears inside the negating banners and in -# clearly-marked future-roadmap sections, so a naive phrase grep would -# false-positive. Presence-of-the-correction is the durable invariant. +# Presence invariants (DOC-04/05) — fails if any banner pointer, the matrix's +# self-declaration, the anti-over-claim section, or the STATE.a2ml mirror keys +# are removed. This deliberately checks *presence of the correction*, not a +# phrase blocklist: "production-ready" legitimately appears inside the +# negating banners and future-roadmap sections, so a naive grep over the +# whole doc would false-positive. +# +# Over-claim ratchet (DOC-08/09) — closes exactly that phrase-detection gap +# without the false positives, via a frozen baseline (tools/doc-overclaims.allow): +# the current accepted set of over-claim-phrase occurrences (every one +# legitimate today — future-tense roadmap milestones, dated history snapshots, +# the corrective banners) is frozen, and any *new* occurrence fails the build. +# The two governance docs that quote the rule itself (CAPABILITY-MATRIX + +# TECH-DEBT) are excluded so editing the rule-text never churns the baseline. +# Signatures are path + normalised-line, robust to line moves; the baseline's +# growth is a reviewable diff — the human-review signal the DOC rules describe. +# +# Usage: +# check-doc-truthing.sh run all checks (CI / `just check`) +# check-doc-truthing.sh --update re-baseline the over-claim ratchet, e.g. +# after a new dated roadmap milestone, then +# commit the tools/doc-overclaims.allow diff # # Wired into: # - just check (via the `guard` recipe in justfile) @@ -52,6 +70,53 @@ STATE_KEYS=( "drift-flag" ) +# Over-claim ratchet (DOC-08/09): the frozen baseline + the phrase families it +# guards. Patterns are intentionally broad — the frozen baseline gives zero +# false positives on existing content, so breadth only raises recall on new +# occurrences. +ALLOW="tools/doc-overclaims.allow" +PATTERN='production[- ]ready|production backends?|[0-9]+[[:space:]]+(production|complete)[[:space:]]+backends?|stdlib[^|]*100%|100%[^|]*stdlib|N production backend' + +# Emit one normalised signature per over-claim hit: "relpathline", with the +# line's internal whitespace collapsed + trimmed (robust to re-indent / re-flow; +# sensitive to the claim text itself). CAPABILITY-MATRIX + TECH-DEBT are excluded +# (they define/quote the rule itself; their banner/primacy presence is checked +# above instead). Sorted + de-duplicated. +scan_overclaims() { + grep -rniE "$PATTERN" README.adoc docs/ 2>/dev/null \ + --exclude="CAPABILITY-MATRIX.adoc" \ + --exclude="TECH-DEBT.adoc" \ + | sed -E 's/^([^:]+):[0-9]+:/\1\t/' \ + | awk -F'\t' 'BEGIN { OFS = "\t" } + { + line = $2 + gsub(/[[:space:]]+/, " ", line) + sub(/^ /, "", line) + sub(/ $/, "", line) + print $1, line + }' \ + | LC_ALL=C sort -u +} + +# --- --update / --bless mode: regenerate the ratchet baseline --------------- +if [ "${1:-}" = "--update" ] || [ "${1:-}" = "--bless" ]; then + { + echo "# SPDX-License-Identifier: MPL-2.0" + echo "# SPDX-FileCopyrightText: 2024-2026 hyperpolymath" + echo "# Over-claim baseline (issue #176, DOC-08/09) — the frozen set of" + echo "# accepted over-claim-phrase occurrences guarded by" + echo "# tools/check-doc-truthing.sh. Regenerate with" + echo "# \`./tools/check-doc-truthing.sh --update\`. Each line is a" + echo "# \"relpathnormalised-line\" signature. A new signature not listed" + echo "# here fails CI; adding one is a deliberate, reviewable act. Current" + echo "# entries are future-tense roadmap milestones, dated history snapshots," + echo "# and the corrective banners — none is a live over-claim." + scan_overclaims + } > "$ALLOW" + echo "OK: regenerated $ALLOW ($(grep -cvE '^#' "$ALLOW") signatures)." + exit 0 +fi + fail=0 note() { printf '%s\n' "$*" >&2; } @@ -109,6 +174,32 @@ else done fi +# --- 4. No NEW over-claim phrasing beyond the frozen baseline (DOC-08/09) ---- +if [ ! -f "$ALLOW" ]; then + note "ERROR: over-claim baseline is missing: $ALLOW" + note " Run ./tools/check-doc-truthing.sh --update to create it." + fail=1 +else + current="$(scan_overclaims)" + allowed="$(grep -vE '^#' "$ALLOW" | LC_ALL=C sort -u || true)" + new_hits="$(LC_ALL=C comm -13 <(printf '%s\n' "$allowed") <(printf '%s\n' "$current") | sed '/^$/d')" + if [ -n "$new_hits" ]; then + note "ERROR: new over-claim(s) detected in status docs (DOC-08/09)." + note " The authoritative readiness source is $MATRIX, which forbids" + note " re-introducing backend-breadth / \"production-ready\" /" + note " stdlib-percentage over-claims. Not in the frozen baseline" + note " ($ALLOW):" + note "" + printf '%s\n' "$new_hits" | sed 's/\t/ :: /; s/^/ /' >&2 + note "" + note " Fix the over-claim (preferred), or — if it is genuinely" + note " legitimate (e.g. a new dated roadmap milestone) — re-baseline" + note " with: ./tools/check-doc-truthing.sh --update (just doc-truth-bless)" + note " and commit the $ALLOW diff in the same PR." + fail=1 + fi +fi + if [ "$fail" -ne 0 ]; then note "" note "Doc-truthing guard failed. The status docs are drifting back toward" @@ -117,4 +208,4 @@ if [ "$fail" -ne 0 ]; then exit 1 fi -echo "OK: doc-truthing banners intact (matrix primacy + DOC-04 banners + DOC-05 mirror keys)." +echo "OK: doc-truthing intact — presence invariants + over-claim ratchet (DOC-04/05/08/09)." diff --git a/tools/doc-overclaims.allow b/tools/doc-overclaims.allow index 4e4c84a..f7b2ab4 100644 --- a/tools/doc-overclaims.allow +++ b/tools/doc-overclaims.allow @@ -1,8 +1,9 @@ # SPDX-License-Identifier: MPL-2.0 # SPDX-FileCopyrightText: 2024-2026 hyperpolymath -# Over-claim baseline (issue #176, DOC-08/09 / ledger DOC-17) — the -# frozen set of accepted over-claim-phrase occurrences. Regenerate with -# `./tools/check-doc-overclaims.sh --update`. Each line is a +# Over-claim baseline (issue #176, DOC-08/09) — the frozen set of +# accepted over-claim-phrase occurrences guarded by +# tools/check-doc-truthing.sh. Regenerate with +# `./tools/check-doc-truthing.sh --update`. Each line is a # "relpathnormalised-line" signature. A new signature not listed # here fails CI; adding one is a deliberate, reviewable act. Current # entries are future-tense roadmap milestones, dated history snapshots,