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
The known soundness holes (#554/#555/#556/#558/#559) were fixed, fenced, or
removed across 2026-05/2026-06, but their status was duplicated across ~6 docs
that drifted independently. A reader who opened the stale one (the
CAPABILITY-MATRIX rows, the CLAUDE.md survey block, a STATE snapshot) got a
stale "is it sound?" answer — and in the dangerous direction.
Structural fix, not just prose:
- Add docs/SOUNDNESS.adoc: the single source of truth for soundness-hole
status, test-anchored (every row names the fixture/test that proves it),
with a freshness stamp (SHA + date). Ground-truthed against a green
`dune build` / `dune runtest` at 85e3f0d on 2026-06-21.
- Add 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 it cites goes missing, or if a status surface stops linking
back to it. This binds prose to executable truth so the ledger cannot rot
silently (verified: the gate fails on a missing anchor).
- Correct every live status surface to ground-truth and point at the ledger:
README, CAPABILITY-MATRIX (borrow / effects / refinement / traits rows + the
anti-over-claim bullet + See-also), PROOF-NEEDS (holes block + P-9/P-10),
NAVIGATION, reference/COMPILER-CAPABILITIES, TECH-DEBT (CORE-04/CORE-05),
the wiki (README + traits + dependent-types), STATE.a2ml, agent debt, and
the CLAUDE.md survey (converted to a deferral; no header/license change).
- Cap the dated STATE-2026-06-11 snapshot with a superseded banner rather than
rewriting history.
Ground-truth recorded: #554 fixed (use-after-move via a callee-returned borrow
rejected), #555 fenced loud on every compiled backend (one pinned interpreter
non-tail-resume residual), #556 fixed, #558 removed, #559 fixed for concrete
overlaps, #553 Polonius M1-M3 but test-only/unwired. Closing these
implementation holes is not the same as proving soundness; the metatheory
remains prose (PROOF-NEEDS).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BbxKhXQwTvVgkYDgBMLJoa
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