You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: make soundness status a single, test-anchored source of truth (#622)
## Why
A reader (human or agent) asking "is AffineScript sound / what's
broken?" could open any of ~6 docs and get a **stale answer in the
dangerous direction**. The known holes `#554/#555/#556/#558/#559` were
fixed, fenced, or removed across 2026-05/06, but their status was
duplicated across the capability matrix, a `CLAUDE.md` survey block,
`STATE-*` snapshots, the wiki, etc. — surfaces that drift independently.
(This PR was prompted by exactly that: a stale answer sourced from
`CAPABILITY-MATRIX.adoc` + the `CLAUDE.md` survey.)
This fixes the **content and the layout** so it can't silently rot
again.
## What
**New single source of truth — `docs/SOUNDNESS.adoc`**
- The one place soundness-hole status lives. **Test-anchored**: every
row names the fixture/test that proves it.
- Carries a freshness stamp (`:ground-truth-sha:` + date).
Ground-truthed against a green `dune build` / `dune runtest` at
`d55e22c`.
- Honest about residuals (interpreter non-tail resume, Lean/Why3
`return`-drop, #559 generic overlap) and about the
implementation-vs-proof distinction.
**New anti-staleness gate — `tools/check-soundness-ledger.sh`** (wired
into `just guard` + CI)
- Fails the build if the ledger loses its primacy declaration or
freshness stamp, if any **anchor fixture goes missing**, or if a status
surface stops linking back to the ledger. This binds prose to executable
truth.
- Verified it *bites*: returns non-zero and names the offender on a
missing anchor.
**Corrected every live status surface** to ground-truth + made them
defer to the ledger: `README`, `CAPABILITY-MATRIX`
(borrow/effects/refinement/traits rows + anti-over-claim bullet +
See-also), `PROOF-NEEDS` (holes block + P-9/P-10), `NAVIGATION`,
`reference/COMPILER-CAPABILITIES`, `TECH-DEBT` (CORE-04/05), the wiki
(README + traits + dependent-types), `STATE.a2ml`, agent debt, and the
`CLAUDE.md` survey. Dated snapshot `STATE-2026-06-11` is **capped with a
superseded banner**, not rewritten.
## Ground-truth recorded (verified in source + green suite)
| Issue | Was documented as | Actually |
|---|---|---|
| #554 | open use-after-move | **fixed** — rejected `MoveWhileBorrowed`
|
| #555 | silently mis-lowered | **fenced loud** on every compiled
backend; 1 pinned interp residual |
| #556 | silent sync fallback | **fixed** — fails loud |
| #558 | parse-only/unenforced | **removed** in v1; `assume(...)`
rejected at parse |
| #559 | coherence unchecked | **fixed** for concrete overlaps (wired in
`typecheck.ml`) |
| #553 | "0% implemented" | M1–M3, **test-only/unwired** |
Closing these *implementation* holes is **not** the same as *proving*
soundness — the metatheory is still prose (one Wave-0 Coq seed from #620
noted), per `PROOF-NEEDS.adoc`.
## Note for review
- The `.claude/CLAUDE.md` change is **body-only** (the stale survey → a
deferral to the ledger). I did **not** add or alter its license header —
that's the owner-gated act flagged in the soundness handoff.
- No code touched; docs + one shell gate + CI/justfile wiring. `dune
build` and `dune runtest` are green at `d55e22c`.
- `AFFIRMATION.adoc` (a parked, dated attestation) was deliberately left
untouched.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01BbxKhXQwTvVgkYDgBMLJoa
---
_Generated by [Claude
Code](https://claude.ai/code/session_01BbxKhXQwTvVgkYDgBMLJoa)_
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .claude/CLAUDE.md
+16-17Lines changed: 16 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@
9
9
| File extension |`.affine` (plus face dialects) |`.eph`|
10
10
| Build |`dune-project` at root |`Cargo.toml` at root |
11
11
| Type checker |`lib/borrow.ml` (OCaml) |`ephapax-linear/src/{linear,affine}.rs` (Rust) |
12
-
| Proofs | None mechanized (programme filed: #513–#521, unstarted); soundness arguments live in `lib/borrow.ml` + `docs/CAPABILITY-MATRIX.adoc`. CORE-01/#177 CLOSED 2026-05-30; known hole #554; Polonius residual #553|`formal/Semantics.v` (Coq), `src/abi/Ephapax/…` (Idris2) |
12
+
| Proofs | None mechanized (programme filed: #513–#521, unstarted); soundness arguments live in `lib/borrow.ml` + `docs/CAPABILITY-MATRIX.adoc`; soundness-hole status is the test-anchored `docs/SOUNDNESS.adoc` (CORE-01/#177 CLOSED 2026-05-30; #554 FIXED; Polonius #553 test-only/unwired)|`formal/Semantics.v` (Coq), `src/abi/Ephapax/…` (Idris2) |
13
13
14
14
**The trap.** Ephapax is internally dyadic — it contains `ephapax-linear` and `ephapax-affine`*sublanguages* inside one Rust crate. **The `ephapax-affine` sublanguage is NOT AffineScript.** The word `affine` is shared because both type systems happen to be substructural-logic-family — that's a logic-family fact, not a project relationship.
15
15
@@ -208,22 +208,21 @@ Action (gitbot): Never use GitHub's "close issue" API directly; only close via P
208
208
Practical guidance for agents (Claude / other) operating in this repo,
209
209
captured from parallel-bot session experience. Read once; saves turns.
210
210
211
-
### Known soundness items (2026-06-11 survey — read before claiming soundness)
212
-
213
-
Execution-verified, open, and load-bearing for any "is this sound?" answer:
214
-
215
-
***#554** — the borrow checker ACCEPTS use-after-move through a
216
-
callee-returned borrow (`let r = pick(a); consume(a); *r` passes).
217
-
Do not state "the soundness gap closed with CORE-01" — #177 closed,
218
-
this hole remains. Polonius residual: #553 (ADR-022, 0% implemented).
219
-
***#555** — `handle` is silently mis-lowered on core-WASM / JS-text /
220
-
Deno-ESM (arms dropped; interpreter 42 vs wasm 41 on an effects-free
221
-
return-arm program). Interpreter handler dispatch is shallow
222
-
single-shot tail-resume only. Zero runtime handler tests exist.
Copy file name to clipboardExpand all lines: .machine_readable/6a2/STATE.a2ml
+3-3Lines changed: 3 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -79,9 +79,9 @@ affine-types = "wired-and-reachable (Track A Manhattan plan complete 2026-04-10.
79
79
linear-arrows = "enforced (2026-04-11): Three-part fix landed. (1) typecheck.ml lambda synth: |@linear x: T| e now synthesises T -[1]-> U (was always QOmega). (2) typecheck.ml lambda check mode: explicit param quantity annotation validated against expected TArrow quantity; unannotated params inherit context quantity. (3) quantity.ml ExprLambda: added env.errors accumulator; annotated lambda params declared via env_declare so env_use tracks them; usage verified with check_quantity after body walk; violations pushed to env.errors and drained at end of check_function_quantities (step 4). Saved/restored env.quantities entries to prevent scope leakage. Two E2E fixtures + 2 passing tests. 75 tests total, 0 regressions. Commit d2f9b7b pushed."
80
80
borrow-checker = "phase-3-parts-1-3-Slices-A-B-C-light-landed (CORE-01, Refs #177, 2026-05-24): pt1 (#240, gate 263/263) borrow-graph validation wired — BorrowOutlivesOwner emitted, shared-XOR-exclusive enforced at use sites, ownership from param type TyOwn/TyRef/TyMut, call-arg borrows temporary, ref-binding graph tracked. pt2 (gate 271→274 and 278→281) return-escape + &mut e parser surface. pt3 Slice A (PR #335) NLL last-use expiry: compute_last_use_index pre-pass; check_block expires in-block ref-bindings once their binder is dead. pt3 Slice B (effectively #354/#355/#356 after #351 procedural close) flow-sensitive escape via re-assignment: `outer = &y` in StmtAssign pre-releases the held borrow and re-binds the ref-graph entry to the freshly-created borrow. pt3 Slice C-light (this PR) CFG-join semantics for non-match join constructs: ExprHandle handler arms and ExprTry catch arms are now isolated via snapshot-restore-merge (factored merge_arm_results helper, mirroring ExprMatch's inlined logic) — moves/borrows from arm i no longer pollute arm i+1. 2 hermetic tests (positive: independent catch-arm moves OK; anti-regression: body-side move persists past the try). Residual (Slices C-full, C', D): true Polonius origin/region variables on TyRef/TyMut with subset constraints + datalog-style solver (architectural; ADR-gated); loop soundness via 2-iter check (coupled to StmtAssign clear-on-rewrite fix); reborrow through indirection (ref-to-ref binding); quantity-checker tightening for captured linears. Authoritative: docs/CAPABILITY-MATRIX.adoc + docs/TECH-DEBT-alt.adoc CORE-01."
81
81
row-polymorphism = "60% (records + effects rows implemented in typecheck/unify; not fully exercised end-to-end)"
82
-
effects = "interpreter-complete (handler dispatch, PerformEffect propagation, ExprResume, multi-arg ops all wired in interp.ml 2026-04-11). WasmGC: ops registered as unreachable stubs; ExprHandle/ExprResume reject with UnsupportedFeature — full WASM dispatch needs EH proposal or CPS transform."
83
-
dependent-types = "parse-only (TRefined AST node exists and refinement predicates parse, but predicates do not reduce; no SMT/decision procedure wired in)"
84
-
traits = "90% (2026-04-11, commit 1ca143e): trait_registry added to typecheck context; TopTrait/TopImpl processed in forward pass; ExprField falls back to Trait.find_method_for_type on record-field failure; find_impl/find_impls_for_type use unification-based matching via fresh_impl_self_ty + Unify.unify instead of name string comparison; TopImpl bodies type-checked via check_fn_decl with Self bound; check_impl_satisfies_trait verifies required methods present. Two E2E fixtures + 2 tests. 80 total, 0 regressions. Remaining: associated type substitution in method bodies, where-clause supertrait enforcement, coherence checking.)"
82
+
effects = "interpreter-complete (handler dispatch, PerformEffect propagation, ExprResume, multi-arg ops all wired in interp.ml 2026-04-11). WasmGC: ops registered as unreachable stubs; ExprHandle/ExprResume reject with UnsupportedFeature. Every compiled backend (core-WASM, WasmGC, Deno-ESM, JS-text, C) now fails loud on handle/resume (#555 fenced); interp multi-shot fails loud; one non-tail single-shot residual is pinned by a test. Authoritative: docs/SOUNDNESS.adoc."
83
+
dependent-types = "removed-v1 (refinement/dependent surface withdrawn 2026-04-10 per #558; no TRefined node remains; assume(...) rejected at parse; T where (P) is a parse error — no unenforced predicate is expressible). Authoritative: docs/SOUNDNESS.adoc + docs/CAPABILITY-MATRIX.adoc"
84
+
traits = "90% (2026-04-11, commit 1ca143e): trait_registry added to typecheck context; TopTrait/TopImpl processed in forward pass; ExprField falls back to Trait.find_method_for_type on record-field failure; find_impl/find_impls_for_type use unification-based matching via fresh_impl_self_ty + Unify.unify instead of name string comparison; TopImpl bodies type-checked via check_fn_decl with Self bound; check_impl_satisfies_trait verifies required methods present. Two E2E fixtures + 2 tests. 80 total, 0 regressions. Coherence checking now wired (#559, concrete overlaps whose self types unify are rejected; typecheck.ml check_all_coherence). Remaining: associated type substitution in method bodies, where-clause supertrait enforcement, generic-subsumption overlap (#559 follow-up). Authoritative: docs/SOUNDNESS.adoc.)"
Copy file name to clipboardExpand all lines: .machine_readable/agent_instructions/debt.a2ml
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -53,7 +53,7 @@ discovered = "2026-04-11"
53
53
54
54
[[debt.could]]
55
55
component = "lib/typecheck.ml"
56
-
issue = "Associated type substitution in method bodies and where-clause supertrait enforcement not yet implemented in traits. Coherence checking absent."
56
+
issue = "Associated type substitution in method bodies and where-clause supertrait enforcement not yet implemented in traits. Concrete-overlap coherence checking DONE (#559, typecheck.ml check_all_coherence); generic-subsumption overlap is the follow-up. Authoritative: docs/SOUNDNESS.adoc."
*Authoritative status lives in link:docs/CAPABILITY-MATRIX.adoc[docs/CAPABILITY-MATRIX.adoc].*
35
-
Where this README's prose implies broader maturity than that matrix states,
36
-
the matrix wins. AffineScript is *alpha*: CORE-01 (#177) closed
37
-
2026-05-30, but one known base-language soundness hole remains
38
-
(use-after-move via a callee-returned borrow, issue #554; Polonius
39
-
residual #553) and effect handlers are silently mis-lowered on three
40
-
backends (#555). The v1 release-readiness ledger is issue #563.
34
+
*Authoritative status lives in link:docs/CAPABILITY-MATRIX.adoc[docs/CAPABILITY-MATRIX.adoc]
35
+
(feature readiness) and link:docs/SOUNDNESS.adoc[docs/SOUNDNESS.adoc]
36
+
(soundness-hole status — test-anchored, the single source of truth for what is
37
+
fixed / fenced / removed / residual).* Where this README's prose implies
38
+
broader maturity than those state, they win. AffineScript is *alpha*: CORE-01
39
+
(#177) closed 2026-05-30, and the base-language soundness holes tracked through
40
+
2026-06 are now fixed, fenced, or removed — use-after-move via a callee-returned
41
+
borrow (#554) is rejected, effect handlers (#555) fail loud on every compiled
42
+
backend rather than silently dropping arms, the async sync-fallback (#556) fails
43
+
loud, and refinement predicates (#558) were removed rather than left unenforced.
44
+
One pinned interpreter residual remains; see
45
+
link:docs/SOUNDNESS.adoc[docs/SOUNDNESS.adoc] for the per-issue ledger. Closing
46
+
these *implementation* holes is not the same as *proving* soundness — the
47
+
metatheory is still prose (link:docs/PROOF-NEEDS.adoc[docs/PROOF-NEEDS.adoc]).
48
+
The v1 release-readiness ledger is issue #563.
41
49
typed-wasm is a *separate*
42
50
language-agnostic target (`hyperpolymath/typed-wasm`), not an AffineScript
43
51
subsystem — see link:docs/ECOSYSTEM.adoc[docs/ECOSYSTEM.adoc].
@@ -50,7 +58,7 @@ Write software where the compiler helps enforce resource lifecycles, protocol st
50
58
51
59
[NOTE]
52
60
====
53
-
Honest status sync (2026-04-12): affine/QTT and borrow checking are wired into the standard CLI paths today (`check`, `compile`, `eval`) and gate user programs. Dependent/refinement features are still parse-first in places, and some backend features remain incomplete, especially around effect-handler lowering in Wasm targets. See link:docs/CAPABILITY-MATRIX.adoc[docs/CAPABILITY-MATRIX.adoc] for the authoritative per-feature status (`.machine_readable/6a2/STATE.a2ml` mirrors that matrix; it does not lead).
61
+
Honest status sync (2026-06-21): affine/QTT and borrow checking are wired into the standard CLI paths today (`check`, `compile`, `eval`) and gate user programs. Refinement/dependent-type surface was *removed* in v1 rather than left parse-only-and-unenforced (#558); effect-handler lowering on the compiled backends now *fails loud* rather than silently dropping arms (#555). See link:docs/CAPABILITY-MATRIX.adoc[docs/CAPABILITY-MATRIX.adoc] for authoritative per-feature status and link:docs/SOUNDNESS.adoc[docs/SOUNDNESS.adoc] for soundness-hole status (`.machine_readable/6a2/STATE.a2ml` mirrors the matrix; it does not lead).
0 commit comments