The conformance lane added F16-F19 after the master ledger was built; they were present in the copied evidence file but absent from PLAN.md. Added: - W16 (Hyperscript shipped-kernel conformance): F16 shipped host-call-fn binding gap (~900 tests, one-liner), F17 dropped jit-exclude! (sync drift), F18 mock-DOM red-band re-baseline + 9 WASM-only bisect, F19 corpus drift + inverted assert= labels - ledger rows F16-F19; conf-S2 marked RESOLVED (superseded by F16/17/18) Caveat recorded: hs engine may be absent from the production boot list, so F16/F17 may be latent not live — confirm before treating as an outage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
384 lines
28 KiB
Markdown
384 lines
28 KiB
Markdown
# SX Review — Master Remediation Plan
|
||
|
||
Consolidates every finding from the three parallel review sessions (2026-07-03):
|
||
- `core.md` — language core / spec semantics (K01–K110)
|
||
- `hosts.md` — per-host implementations + FFI (J*, C*, JS*, P*, S*, PY)
|
||
- `conformance.md` — cross-host agreement + test adequacy (F1–F15, conf-S1–S5)
|
||
- `RULINGS.md` — 40 draft normative rulings (R1–R40) that gate the ambiguity fixes
|
||
|
||
**How to read this.** Findings are grouped into workstreams (W1–W15). Each workstream lists the
|
||
finding IDs it resolves, the approach, what ratified ruling(s) it needs, and status. The full
|
||
per-ID coverage ledger is at the bottom — every finding maps to a workstream + status, so nothing
|
||
is silently dropped. `[DONE]` = landed in commit dc7aa709 (quick-wins batch). `[GATE]` = blocked on
|
||
a Phase-0 decision. `[dup→Kxx]` = same defect found by another lane, fixed once.
|
||
|
||
**Prime directive from the review:** the verification infrastructure currently cannot tell you
|
||
whether a fix works (runner envs diverge from production, the WASM kernel never runs the corpus,
|
||
the JS gate is structurally red, one test passed *because of* the bug it tested). So Phase 1 Track A
|
||
(gate repair) comes before the bulk of the semantic work — otherwise fixes land blind.
|
||
|
||
---
|
||
|
||
## Phase 0 — Decisions (BLOCKING; maintainer; no code)
|
||
|
||
Nothing in Phases 2+ that changes observable semantics should merge before the relevant ruling is
|
||
ratified. These three decisions unblock ~40 findings.
|
||
|
||
### D1. Host lineup
|
||
Evidence: the JS-transpiled bundle is hollow (C0a: define-library files → 0 bytes) and its gate is
|
||
red (C0b: 2490/5086 fail); nothing serves it. The standalone Python host cannot load (C30/PY).
|
||
Production = OCaml native + WASM kernel (one OCaml library) + the load-bearing Python parser/bridge
|
||
in `shared/sx/`.
|
||
**Recommendation:** declare the kernel family the only evaluator targets; retire `hosts/javascript`
|
||
+ `hosts/python` standalone; shrink `shared/sx/parser.py` to a wire-subset with a parity suite.
|
||
→ Ratifying this **closes W13 entirely** (C0a/C0b/JS1–JS8 become "delete") and simplifies W6/W7.
|
||
|
||
### D2. Ratify RULINGS.md (R1–R40)
|
||
Each ruling is one normative answer + one mechanical fix. Ratify in a pass; four need a
|
||
pre-ratification usage sweep because they're high-churn: **R17** (arity: kill nil-fill), **R9**
|
||
(cond flat-only), **R31** (append! errors on derived lists), **R15a** (HO swap only when
|
||
unambiguous). See RULINGS.md for the per-ruling recommendation.
|
||
|
||
### D3. Define the merge gate
|
||
Recommendation: (a) native `run_tests` green with hs-upstream skip-listed; (b) same corpus on the
|
||
WASM kernel; (c) cross-kernel differential battery output-identical; (d) CEK-vs-forced-JIT
|
||
differential when JIT is on; (e) `sx_ref.ml` regen + diff. This is W14's definition of done.
|
||
|
||
---
|
||
|
||
## Phase 1 — Trustworthy verification + stop the bleeding
|
||
|
||
### W14. Test gate & conformance infrastructure *(do FIRST — everything else verifies against it)*
|
||
Findings: C0b, C9, C21, C22, C23, C3, C4, C5, C6, C7, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
|
||
F12, K19 (harness/runtime primitive drift, partial from batch), K104 (harness log-before-mock).
|
||
Approach:
|
||
1. **Unify runner env with production env** — delete or productionize every runner-only binding:
|
||
`values`/`call-with-values` (F7, K42), the JS runner's fake sha3/equal?/apply/env-set! shims
|
||
(JS5, F7). Rule: if the spec needs it, it's a kernel primitive; if not, the test can't have it.
|
||
2. **WASM corpus runner** in CI (F2) — promote conformance's `run_wasm.js` prototype.
|
||
3. **MCP harness honesty** (K19): `mcp_tree.ml` drops its parallel primitive table and links real
|
||
`sx_primitives` (batch aligned 8 entries as a stopgap); make `sx_harness_eval` fresh per call.
|
||
4. **Harness fixes**: log IO before invoking the mock (C22/K104); real perform/suspend mode (C21);
|
||
adapter-dom render-output tests (C23).
|
||
5. **Epoch-loop protocol fuzz suite** (C3/C4/C5/C6/C7) + skip-list hs-upstream (F10) + empty suite
|
||
label (C9).
|
||
6. **Test-debt ledger**: pin every confirmed finding with a failing test FIRST — the three lane
|
||
files are a ready-made corpus of minimal reprs. **Batch gap to close: dc7aa709's fixes have no
|
||
pinning tests** (except crit-2, now non-vacuous). Add tests for K09, K11, K18, K20, K39, K49,
|
||
C1/C1b, S4 before further evaluator work.
|
||
Gate: none (this IS the gate). Status: OPEN — highest priority.
|
||
|
||
### W1. Condition system & delimited continuations *(the kernel criticals)*
|
||
Findings: K01 (guard/handler re-raise hang — CRITICAL), K03 (shift-k nested cek-run double-exec —
|
||
CRITICAL), K10 (dynamic-wind re-entry + sibling winder corruption), K12 (`->` non-HO steps in
|
||
nested CEK), K36 (guard multi-expr clause body — inherits cond fix W5), K41 (host errors uncatchable
|
||
by guard), K57 (strict errors uncatchable), K106 (SUSPECTED: expand-macro/let-values/qq nested-eval
|
||
boundaries), S10 (VM inline-IO in HO callbacks can't suspend). K02 [DONE].
|
||
Root cause (shared by K03/K12/K106/S10): evaluation crosses a **nested `cek-run`/`trampoline
|
||
(eval-expr)` boundary** the outer continuation can't see. One architectural fix — invoke
|
||
continuations and evaluate these sub-expressions via CEK frames, not nested runs — resolves the
|
||
cluster. K01 is separate: run handlers with the OUTER handler set (unwound kont must EXCLUDE the
|
||
matched frame); make guard clause bodies evaluate after the escape (the no-match auto-reraise path
|
||
already does this — make it the only path). K10: common-ancestor before/after algorithm + winders
|
||
stored per-continuation, not one global length-keyed stack. K41/K57: raise host/primitive/strict
|
||
errors as structured catchable conditions (needs R7).
|
||
Gate: R6 (handler installation), R7 (what's catchable), R8 (raise-continuable). Status: OPEN —
|
||
**K01 is the single highest-value fix left** (DoS-able hang, server + browser).
|
||
|
||
### W3. HTTP-mode concurrency & serving safety *(production robustness — lib/host is LIVE)*
|
||
Findings: S1 (multi-Domain render race — LIVE CRASH), S2 (per-request globals read by queued
|
||
workers), S3 (`expand-components?` bind/remove on shared env), S5 (cache key ignores cookies/query),
|
||
S11 (URL evaluated as SX — any env binding invokable), S12 (island hydration reuses no SSR DOM),
|
||
S13 (SSR/client purity, no dev-mode check), K30 (emit!/emitted cross-request — shared with W2). S4
|
||
[DONE], J1/J2/J3 mitigated by the batch JIT gate.
|
||
Approach: serialize or isolate rendering (S1: lock `_stream_mutex` or per-Domain env/cache);
|
||
per-request state carried with the request not process-global (S2/S3/K30); include query in cache
|
||
key + cookie policy (S5); whitelist URL-routable bindings to a `page:` prefix (S11); hydration cursor
|
||
+ dev-mode purity check (S12/S13). Pairs with W2 (per-flow scope stacks).
|
||
Gate: none for S1/S4/S5 (safety). Status: OPEN — S1 is a live crash.
|
||
|
||
---
|
||
|
||
## Phase 2 — Correctness families (each = ruling + fixes + conformance rows)
|
||
|
||
### W2. Environment & scope integrity
|
||
Findings: K04 (caller frame leaks into interpreted lambda + JIT disagrees), K05 (letrec injects into
|
||
foreign closures — global contamination), K06 (named-let leaks loop name), K07 (~60 unshadowable
|
||
names; = J8 VM-honors-CEK-doesn't), K30 (emit! cross-request — shared W3), K31 (provide leak on
|
||
raise/shift), K32 (provide! ambient global), K33 (set! unbound creates + JIT/interp split brain),
|
||
K40 (scope :value dead + dead frame type), K107 (SUSPECTED env_merge depth-100 flip).
|
||
Approach: fresh frames for letrec/named-let (K05/K06); drop the top-frame copy in env_merge
|
||
(K04/K107); reserved-words error for dispatch names, aligning VM+CEK (K07/J8); unwind-safe +
|
||
invocation-scoped dynamic state — one mechanism for provide/emit!/batch (K30/K31/K32); set!-unbound
|
||
per R1 + kill the JIT/interp global split (K33); remove dead scope :value/frame (K40).
|
||
Gate: R1 (set!), R2 (reserved names). Status: OPEN.
|
||
|
||
### W4. Higher-order forms & threading
|
||
Findings: K13 (2-arg reduce returns coll), K14 (reduce init-swap), K15 (data-first drops extra
|
||
args), K43 (O(n²) map/filter), K44 (HO names not first-class), K45 (cryptic uncatchable HO errors),
|
||
K46 (multi-coll rejects strings/vectors), K47 (thread lambda literal), K78 (component in HO → zeros),
|
||
K79 (dead `|>`), K80 (keyword getters in HO/->), K81 (zero-arg HO silent ()), J7 (VM data-first
|
||
deopt — shared W11).
|
||
Approach: implement R15 sub-rulings (swap only when one arg callable + error otherwise; reduce
|
||
arities; drop-extra→error; multi-coll seq-to-list parity; HO first-class; zero-arg→error); fix O(n²)
|
||
via reversed-cons accumulation; delete dead `|>`.
|
||
Gate: R13 (threading), R15 (HO forms). Status: OPEN.
|
||
|
||
### W5. Special forms & macros
|
||
Findings: K08 (cond dual-grammar — silent side-effect drops), K34 (qq depth), K35 (qq dict
|
||
traversal), K37 (&key misbind on fn/defmacro), K38 (splice non-list/malformed), K70 (case else any
|
||
position), K71 (case dialect + punning), K72 (letrec parallel + ref-before-init), K76 (defmacro
|
||
unhygienic vs "hygiene" test name), K77 (match guard clauses silently structural), K42 (values —
|
||
special forms now registered [DONE-partial]; `values` primitive still runner-only). K09/K11/K39 [DONE].
|
||
Approach: cond flat-only + explicit begin (R9); qq depth tracking + dict traversal + splice arity
|
||
errors (R12); &key one binding path for fn/defmacro/component (R5/K37); case final-else + evaluated-
|
||
datum doc + clause-syntax error (R10); letrec* + ref-before-init error (R4); match guards implemented
|
||
or error (R14); make `values` a real kernel primitive (finish K42).
|
||
Gate: R4, R5, R9, R10, R12, R14. Status: OPEN (K09/K11/K39 done).
|
||
|
||
### W6. Parser, serializer, canonical form & CIDs
|
||
Findings: K21 (canonical.sx runner-only helpers), K22 (serializer dict-key escaping + CID fixed-
|
||
point), K23 (four divergent ident/number classifiers), K24 (`1e`→nil), K25 (guest rationals throw),
|
||
K63 (`#;` before `)`), K64 (`=` no Char arm — shared W7), K65 (`#\a` mcp crash), K66 (multibyte char
|
||
literals), K67 (`\uXXXX` validation), K68 (unknown-escape divergence), K69 (`#name` reader macro
|
||
unimpl on OCaml), K100 (parse error locations), K101 (dict literal edges), K102 (`#|` raw string),
|
||
K103 (`:`/`::` keyword edges), K108 (SUSPECTED cross-host CID nondeterminism), C25 (Py↔OCaml escape
|
||
corruption), C26 (Py unicode symbols), C27 (Py dict order — shared W7/P9).
|
||
Approach: ONE normative ident/number classifier bound by every surface (R32); \u validation +
|
||
unknown-escape error + datum-comment fix (R27/R33); native `#name` reader macro registry;
|
||
canonical path = native CBOR/CID normative, spec/canonical.sx tested mirror or deleted, property-
|
||
test `parse(serialize(x))=x` and canonical fixed-point cross-kernel (R34/R35). CID determinism
|
||
(K108/K35-in-canonical) is sx-pub-critical.
|
||
Gate: R27, R32, R33, R34, R35. Status: OPEN.
|
||
|
||
### W7. Numbers, equality, strings, collection primitives
|
||
Findings: K17 (append! silent no-op), K52 (byte-based strings), K53 (spec/runtime primitive drift),
|
||
K54 (div-by-zero inconsistency), K55 (`/` doc), K56 (sort no comparator), K64 (char equality), K85
|
||
(binary `=`, exactness conflation), K86 (rounding/inexact->exact/sqrt), K87 (float/nil rendering),
|
||
K88 (nil/empty tolerance), K89 (keys reverse order — GATED, see R29 note: breaks render tests), K90
|
||
(keyword-name on evaluated kw), K91 (string->number), K92 (apply doesn't spread), P1 (lossy float
|
||
wire), P2 (sort mixed int/float), P3 (into needs bridge), P4 (int63 vs float64), P5 (= not deep on
|
||
JS dicts, missing eq?/eqv?), P6 (string units), P7 (JS coercion cluster — GATE D1), P8 (nil/list
|
||
strictness), P10 (NaN/Inf wire tokens), P11 (upcase/round), P12 (zip-pairs). K18/K20 [DONE].
|
||
Approach: append! errors on non-mutable lists + deprecate (R31); codepoint string semantics (R25);
|
||
implement eq?/eqv?, add `=` Char arm, n-ary comparisons (R19); exact-±2^53 + overflow-promote (R21);
|
||
shortest-round-trip float printing + inf/nan wire tokens (R23); div-by-zero catchable (R22); apply
|
||
spreads (R16); sort comparator + numeric compare (R30/P2); into native, contains?-on-dict [done],
|
||
merge-skip-nil, zip-pairs sliding window (R30/P8/P12); reconcile spec/runtime primitive lists (K53).
|
||
Gate: R16, R19, R21, R22, R23, R25, R29, R30, R31. Status: OPEN (K18/K20 done).
|
||
|
||
### W8. Render pipeline
|
||
Findings: K16 (infinite recursion no depth guard), K48 (attr-name injection — XSS class), K50 (aser
|
||
list kwargs), K51 (dom/html attr parity = C19), K82 (bool-attr truthiness footgun), K83 (dead
|
||
is-render-expr? / html: tags), K84 (script/style escaping), K87 (float render — shared W7), C19 (=K51),
|
||
C20 (CSRF cross-origin), S14 (deep nested-list flatten html vs aser), S9 (SPA boosted-nav fragility).
|
||
K49 [DONE]. Approach: depth limit + cycle guard (K16); attr-name validation (R36/K48); quote aser
|
||
list kwargs (R38/K50); align 4 adapters on bool-attr contract (R36/C19/K51); script/style raw-text
|
||
error-on-breakout (R37/K84); wire or delete is-render-expr? (R37/K83); depth-2 aser/html parity test
|
||
(S14). CSRF cross-origin (C20) + SPA manifest staleness (S9, overlaps W11 stale-bundle).
|
||
Gate: R36, R37, R38. Status: OPEN (K49 done).
|
||
|
||
### W9. Strict typing
|
||
Findings: K26 (HO callbacks bypass), K27 (apply bypasses), K58 (unknown type names match all), K59
|
||
(keyword type dead / components untypeable), K60 (component &key misalign), K93 (name-keyed, evaded),
|
||
K94 (set-prim-param-types! no validation), K95 (too-few args skip checks), K96 (`(:as type)` unenforced),
|
||
K97 (paper cuts). Approach (R20): move checks to continue-with-call/vm_call chokepoints (covers HO,
|
||
apply, components, => receivers); validate type names at declaration; real "component" branch, remove
|
||
dead "keyword" (R18); `(:as type)` as the declaration channel; merge+validate set-prim-param-types!;
|
||
strict errors catchable (R7, shared W1). Return types explicitly out of scope.
|
||
Gate: R7, R18, R20. Status: OPEN.
|
||
|
||
### W10. Signals & coroutines
|
||
Findings: K28 (dispose-computed no-op), K29 (batch wedge on exception), K61 (identity-not-equality
|
||
change detection), K62 (diamond glitch), K98 (batch unusable on server / coroutines inert), K99
|
||
(effect cleanup double-invoke), K109 (SUSPECTED coroutine non-yield wedge), K110 (SUSPECTED VM no
|
||
strict — shared W9/W11). Approach (R39): `=`-based change detection (needs W7 R19); unwind-safe batch
|
||
(shared W2 mechanism); two-phase/topological notify for glitch-freedom; fix dispose-computed + effect
|
||
cleanup; make batch/coroutines work outside run_tests (bind batch-begin!/end! + cek hooks in real
|
||
envs, or fold into kernel). Zero test coverage today — add suites.
|
||
Gate: R39. Status: OPEN.
|
||
|
||
### W12. Python bridge & boundary *(load-bearing in production)*
|
||
Findings: C24 (boundary validation dead — [DONE-partial]: now warns; full revival needs tier-1
|
||
declarations recreated + zero-violation proof since SX_BOUNDARY_STRICT=1 is live), C28 (two SxExpr
|
||
classes double-quote), C29 (reader-macro auto-resolve broken), C30 (standalone Python host dead —
|
||
GATE D1: delete), C31 (14/33 test files broken + 5 live failures), S-bridge (coroutine-cancel
|
||
desync, no timeouts, dead _restart), S-bridge2 (numeric-result-as-epoch ambiguity), K42 (values —
|
||
shared W5). C25/C26/C27 live in W6 (parser). Approach: finish C24 (recreate declarations, prove
|
||
clean, re-enable); single SxExpr class (C28); fix OcamlSync.start→_ensure (C29); bridge timeouts +
|
||
working _restart (S-bridge); robust (ok N V) parse (S-bridge2); fix/retire broken tests (C31).
|
||
Gate: D1 (C30). Status: OPEN (C24 partial).
|
||
|
||
### W11. JIT correctness (serving-JIT re-enable preconditions)
|
||
Findings: J1 (`->` miscompile), J2 (fallback re-runs whole call — double side effects), J3 (macro
|
||
args eager), J4 (VM component kwargs misparse), J5 (specialized opcodes freeze redefs), J6 (compiler-
|
||
used prim redef poisons), J7 (data-first deopt — shared W4), J10 (stale Sx_compiler stub), J11 (JIT
|
||
debug paths diverge), K33 (set! split brain — shared W2), K19 (harness drift — shared W14), C10
|
||
(browser compiler one fix behind), C11 (stale module-manifest.sx), C12 (dead SOURCE_MAP paths), C14
|
||
(stale dist/ bundle). J12 = positive (perform/resume fixed). Currently MITIGATED (JIT gated OFF in
|
||
both epoch and — post-batch — HTTP mode). Approach: fix compile-thread-step (J1); fallback-before-
|
||
side-effects or compile-time reject of fallback-prone forms (J2); macro-aware compile (J3); keyword
|
||
tagging in constant pool (J4); redefinition invalidation (J5/J6); one browser-compiler sync pipeline
|
||
+ single bundle dir (C10/C11/C12/C14). Do NOT re-enable serving-JIT until the CEK-vs-JIT differential
|
||
(W14) is green.
|
||
Gate: W14 differential. Status: DEFERRED (mitigated; only unblock if serving-JIT is wanted).
|
||
|
||
### W16. Hyperscript engine — shipped-kernel conformance *(production-facing; added post-ledger from conformance F-16–F-19)*
|
||
Findings: F-16 (shipped browser hs cannot call functions — `host-call-fn`/`host-call-fn-raising`
|
||
referenced by shipped `hs-runtime.sx`/`hs-integration.sx` but defined ONLY in run_tests.ml:3564;
|
||
906 "Undefined symbol: host-call-fn" on the behavioral corpus against the shipped stack), F-17
|
||
(shipped `shared/static/wasm/sx/hs-runtime.sx` dropped the `(jit-exclude! "hs-*")` guard that
|
||
`lib/hyperscript/runtime.sx` has — hs is JIT-eligible in the browser where the parser-combinator
|
||
recursion miscompiles; the tested config ≠ the shipped config), F-18 (the native runner's MOCK DOM
|
||
is the outlier: ≥118 of the 272 "permanent red" hs failures PASS on the shipped WASM kernel +
|
||
happy-dom — the red band mostly indicts the test env, not the engine; 9 genuine WASM-only failures
|
||
remain to bisect: behavior-scoping ×4, as-fragment `__host_handle` leak ×3, init/where ×2), F-19
|
||
(hs corpus drift — generated tests still expect the pre-`beingTold`/`poss` parser AST, ~50 shared
|
||
failures on every kernel; PLUS `assert=` is `(actual expected msg)` but the generated corpus calls
|
||
`(assert= expected actual)` so every failure prints Expected/got SWAPPED — actively misled diagnosis).
|
||
Approach:
|
||
1. **F-16 (quick, production):** register `host-call-fn`/`host-call-fn-raising` in the shipped
|
||
platform (`sx-platform.js`) — or rename the runtime's calls to the existing `host-call`. One
|
||
binding unbreaks ~900 hs behaviors in browsers. Same class as F-7/K42 (runner-only binding).
|
||
2. **F-17 (quick, safety):** restore `(jit-exclude! "hs-*")` in the shipped `hs-runtime.sx`, and —
|
||
better — make the lib→`wasm/sx` sync SCRIPTED (this is the same manual-copy drift as C10/C11/C12/
|
||
C14 in W11/W15; one sync script fixes the whole family so the guard can't silently drop again).
|
||
3. **F-19 (quick + medium):** fix `assert=` arg order (or the generator's call order) so failure
|
||
messages stop lying — cosmetic but it misleads every future session; then regenerate the upstream
|
||
hs corpus against the current parser AST (~50 tests fail purely from drift). Belongs with W14.
|
||
4. **F-18 (medium):** re-baseline the native red band — improve the mock DOM or skip-list the
|
||
browser-only hs suites so FAIL means something (feeds W14's F-10 skip-list + gate). Then bisect
|
||
the 9 WASM-only failures — the only candidates for real shipped-kernel bugs left in hs.
|
||
CAVEAT (accuracy): hs engine modules are shipped but may be absent from the production boot list
|
||
(`loadWebStackFallback`, sx-platform.js:670 — hs load path "unclear/on-demand only" per F-19), so
|
||
F-16/F-17 may be LATENT rather than live on blog.rose-ash.com today — confirm whether any served
|
||
page loads the hs engine before treating them as a live outage.
|
||
Ownership: F-16/F-17 are hosts-lane fixes; F-19 assert= + F-18 re-baseline are conformance/W14;
|
||
the WASM corpus runner they need is W14's. Note: js_of_ocaml is ~1-2 orders slower on this corpus
|
||
(≈24s/test) — gate on a curated subset, not the full 6k.
|
||
Gate: pairs with W14 (WASM runner) and W11/W15 (sync-script). Status: OPEN — F-16/F-17 are one-liners.
|
||
|
||
### W13. JS host *(GATE D1 — likely "delete")*
|
||
Findings: C0a (hollow bundle), C0b (2490 fail gate), JS1 (define-record-type/makeRtd), JS2 (host-
|
||
callback type tag), JS3 (arithmetic drops args), JS4 (`.` symbol), JS5 (runner shims), JS6 (str nil),
|
||
JS7 (no qq emission), JS8 (stale metadata). If D1 retires the JS bundle: delete `hosts/javascript`,
|
||
remove from `sx-build-all.sh`/CI, keep only the WASM kernel path. If kept: this is a ~2500-test
|
||
revival project. Gate: D1. Status: BLOCKED on D1.
|
||
|
||
---
|
||
|
||
## Phase 3 — Hygiene & docs
|
||
|
||
### W15. Hygiene & documentation
|
||
Findings: C8 (triplicated hosts/ocaml/hosts/ tree), C13 (test_platform.js stale path), C15 (tracked
|
||
stale wasm blob), C16 (orphaned hosts/native), C17 (sx-platform-2.js + 23 dead .sxbc.json), C18
|
||
(spa-debug.js + root clutter), C2 (r7rs string->number radix shadow), F14 (doc drift — batch fixed
|
||
canonical-ref + island rules; suite counts + case-syntax + primitives-header still stale), F15
|
||
(sha3 stub / test.sx dead filename), F13 (regen reproducibility — [DONE] as batch side effect).
|
||
K105/K73 [DONE]. Approach: delete dead trees/blobs/files; fix r7rs shadow (C2); finish CLAUDE.md
|
||
(suite counts, case syntax); regen-diff CI check (F13 → make it a gate in W14).
|
||
Gate: D1 (some deletions). Status: OPEN (K105/K73/F13 done).
|
||
|
||
---
|
||
|
||
## Suggested execution shape (maps to the loop workflow)
|
||
|
||
Four loops, mostly independent after Phase 0:
|
||
1. **loops/sx-gate** (W14 + W15 hygiene) — the enabler. Start FIRST. Pins tests for the dc7aa709
|
||
batch, builds the WASM corpus runner + differential battery, unifies runner env, cleans dead code.
|
||
2. **loops/sx-kernel** (W1 + W2 + W5) — condition system, scope integrity, special forms. Single
|
||
owner (touches evaluator.sx + regen). TDD off W14's pinned tests. K01 first.
|
||
3. **loops/sx-runtime** (W3 HTTP safety + W12 Python bridge) — production robustness; can run
|
||
parallel to kernel since it's mostly host OCaml + Python, not spec.
|
||
4. **loops/sx-families** (W4, W6, W7, W8, W9, W10) — one family at a time, each gated by its rulings
|
||
+ the new batteries. W6/W7 pay the sx-pub CID debt.
|
||
W11 (JIT) and W13 (JS) are decision-gated and sit out until D1 + a green differential exist.
|
||
|
||
**Sequencing rule:** no semantic fix merges before (a) its pinning test exists, (b) the relevant
|
||
ruling is ratified, (c) native + WASM both run it. D1/D2/D3 are the only hard blockers.
|
||
|
||
---
|
||
|
||
## Coverage ledger — every finding accounted for
|
||
|
||
Status key: DONE (dc7aa709) · OPEN · PARTIAL · DEFERRED · GATE(Dn) · dup→(primary). Workstream in [].
|
||
|
||
### Core (K01–K110)
|
||
- K01 [W1] OPEN — guard/handler re-raise hang (CRITICAL, highest value)
|
||
- K02 [W1] DONE — signal-return frame key
|
||
- K03 [W1] OPEN — shift-k nested cek-run (CRITICAL)
|
||
- K04 [W2] OPEN · K05 [W2] OPEN · K06 [W2] OPEN · K07 [W2] OPEN (=J8)
|
||
- K08 [W5] OPEN — cond dual grammar
|
||
- K09 [W5] DONE · K10 [W1] OPEN · K11 [W5] DONE
|
||
- K12 [W1] OPEN (=W4 threading) · K13 [W4] OPEN · K14 [W4] OPEN · K15 [W4] OPEN
|
||
- K16 [W8] OPEN · K17 [W7] OPEN — append! · K18 [W7] DONE · K19 [W14] PARTIAL · K20 [W7] DONE
|
||
- K21 [W6] OPEN · K22 [W6] OPEN · K23 [W6] OPEN · K24 [W6] OPEN · K25 [W6] OPEN
|
||
- K26 [W9] OPEN · K27 [W9] OPEN · K28 [W10] OPEN · K29 [W10] OPEN
|
||
- K30 [W2/W3] OPEN — emit! cross-request (=S2 dir)
|
||
- K31 [W2] OPEN · K32 [W2] OPEN · K33 [W2/W11] OPEN — set! split brain
|
||
- K34 [W5] OPEN · K35 [W5/W6] OPEN · K36 [W1/W5] OPEN · K37 [W5] OPEN · K38 [W5] OPEN
|
||
- K39 [W5] DONE · K40 [W2] OPEN · K41 [W1] OPEN · K42 [W5/W12] PARTIAL (forms registered; `values` prim runner-only)
|
||
- K43 [W4] OPEN · K44 [W4] OPEN · K45 [W4] OPEN · K46 [W4] OPEN · K47 [W4] OPEN
|
||
- K48 [W8] OPEN · K49 [W8] DONE · K50 [W8] OPEN · K51 [W8] OPEN (=C19)
|
||
- K52 [W7] OPEN · K53 [W7] OPEN · K54 [W7] OPEN · K55 [W7] OPEN · K56 [W7] OPEN
|
||
- K57 [W1/W9] OPEN · K58 [W9] OPEN · K59 [W9] OPEN · K60 [W9] OPEN
|
||
- K61 [W10] OPEN · K62 [W10] OPEN · K63 [W6] OPEN · K64 [W6/W7] OPEN — char `=`
|
||
- K65 [W6] OPEN · K66 [W6] OPEN · K67 [W6] OPEN · K68 [W6] OPEN · K69 [W6] OPEN
|
||
- K70 [W5] OPEN · K71 [W5] OPEN · K72 [W5] OPEN · K73 [W15] DONE
|
||
- K74 [W2] OPEN (component &key false→nil; R5) · K75 [W2] OPEN (trailing kw; R5)
|
||
- K76 [W5] OPEN · K77 [W5] OPEN · K78 [W4] OPEN · K79 [W4] OPEN · K80 [W4] OPEN · K81 [W4] OPEN
|
||
- K82 [W8] OPEN · K83 [W8] OPEN · K84 [W8] OPEN · K85 [W7] OPEN · K86 [W7] OPEN · K87 [W7/W8] OPEN
|
||
- K88 [W7] OPEN · K89 [W7] OPEN — keys order, GATED R29 (breaks render tests, see RULINGS note)
|
||
- K90 [W7] OPEN · K91 [W7] OPEN · K92 [W7] OPEN — apply spread
|
||
- K93 [W9] OPEN · K94 [W9] OPEN · K95 [W9] OPEN · K96 [W9] OPEN · K97 [W9] OPEN
|
||
- K98 [W10] OPEN · K99 [W10] OPEN · K100 [W6] OPEN · K101 [W6] OPEN · K102 [W6] OPEN · K103 [W6] OPEN
|
||
- K104 [W14] OPEN · K105 [W15] DONE
|
||
- K106 [W1] OPEN (SUSPECTED nested-eval boundaries) · K107 [W2] OPEN (SUSPECTED)
|
||
- K108 [W6] OPEN (SUSPECTED CID nondeterminism) · K109 [W10] OPEN (SUSPECTED) · K110 [W9/W11] OPEN (SUSPECTED)
|
||
|
||
### Hosts — JIT (J1–J12)
|
||
- J1 [W11] DEFERRED (mitigated: JIT gated off) · J2 [W11] DEFERRED · J3 [W11] DEFERRED
|
||
- J4 [W11] DEFERRED · J5 [W11] DEFERRED · J6 [W11] DEFERRED · J7 [W11/W4] DEFERRED
|
||
- J8 [W2] OPEN dup→K07 · J9 [W11/W14] DEFERRED · J10 [W11] DEFERRED · J11 [W11] DEFERRED
|
||
- J12 POSITIVE (no action — perform/resume verified fixed)
|
||
|
||
### Hosts — kernel/protocol/build (C*)
|
||
- C0a [W13] GATE(D1) · C0b [W13/W14] GATE(D1) · C1 [W3] DONE · C1b [W3] DONE
|
||
- C2 [W15] OPEN · C3 [W14] OPEN · C4 [W14] OPEN · C5 [W14] OPEN · C6 [W14] OPEN · C7 [W14] OPEN
|
||
- C8 [W15] OPEN · C9 [W14] OPEN · C10 [W11] DEFERRED · C11 [W11] DEFERRED · C12 [W11/W15] OPEN
|
||
- C13 [W15] OPEN · C14 [W11/W15] OPEN · C15 [W15] OPEN · C16 [W15] OPEN · C17 [W15] OPEN · C18 [W15] OPEN
|
||
- C19 [W8] OPEN dup→K51 · C20 [W8] OPEN · C21 [W14] OPEN · C22 [W14] OPEN · C23 [W14] OPEN
|
||
- C24 [W12] PARTIAL · C25 [W6] OPEN · C26 [W6] OPEN · C27 [W6/W7] OPEN dup→P9
|
||
- C28 [W12] OPEN · C29 [W12] OPEN · C30 [W12] GATE(D1) · C31 [W12] OPEN
|
||
|
||
### Hosts — JS host (JS1–JS8)
|
||
- JS1–JS8 [W13] all GATE(D1) — delete if JS retired, else ~2500-test revival
|
||
|
||
### Hosts — cross-host parity (P1–P12, PY)
|
||
- P1 [W7] OPEN · P2 [W7] OPEN · P3 [W7] OPEN · P4 [W7] OPEN · P5 [W7] OPEN · P6 [W7] OPEN
|
||
- P7 [W7] GATE(D1) · P8 [W7] OPEN · P9 [W6/W7] OPEN (=C27) · P10 [W7] OPEN · P11 [W7] OPEN · P12 [W7] OPEN
|
||
- PY [W13] GATE(D1) dup→C30
|
||
|
||
### Hosts — HTTP/suspected (S1–S14, S-bridge*)
|
||
- S1 [W3] OPEN (LIVE CRASH) · S2 [W3/W2] OPEN · S3 [W3] OPEN · S4 [W3] DONE · S5 [W3] OPEN
|
||
- S6 [W14] OPEN · S7 [W14/W1] OPEN (unify eval/IO paths) · S8 [W13/W8] OPEN (browser env prims)
|
||
- S9 [W8/W11] OPEN · S10 [W1] OPEN · S11 [W3] OPEN · S12 [W3] OPEN · S13 [W3] OPEN · S14 [W8] OPEN
|
||
- S-bridge [W12] OPEN · S-bridge2 [W12] OPEN
|
||
|
||
### Conformance (F1–F15, conf-S1–S5)
|
||
- F1 [W7] OPEN dup→K18/P4 (WASM int wrap) · F2 [W14] OPEN · F3 [W7/W6] OPEN (apply + dict order) · F4 [W13/W14] GATE(D1)
|
||
- F5 [W14] OPEN (host-neutral corpus) · F6 [W14] OPEN (directories one-host-gated) · F7 [W14] OPEN dup→K42
|
||
- F8 [W14] OPEN (differential battery) · F9 [W7/W14] OPEN (primitive parity) dup→K53 · F10 [W14] OPEN (skip hs, =F18)
|
||
- F11 [W12] OPEN dup→C24 · F12 [W6] OPEN dup→C25/26/27 · F13 [W15] DONE · F14 [W15] PARTIAL · F15 [W15] OPEN
|
||
- F16 [W16] OPEN (shipped hs host-call-fn binding gap — one-liner, ~900 tests) dup-class→F7/K42
|
||
- F17 [W16] OPEN (shipped hs missing jit-exclude! — sync drift) dup-class→C10/C11/C12/C14
|
||
- F18 [W16/W14] OPEN (mock-DOM red band re-baseline + 9 WASM-only bisect) dup→F10
|
||
- F19 [W16/W14] OPEN (hs corpus drift + inverted assert= labels)
|
||
- conf-S1 [W14] OPEN (native-vs-WASM web-stack diff) · conf-S2 RESOLVED→promoted to F16/F17/F18
|
||
- conf-S3 [W11] OPEN (import path browser vs test) · conf-S4 [W14] OPEN (float golden precision) · conf-S5 [W11] OPEN (JS build-flag ADT divergence)
|
||
|
||
### Tally
|
||
~217 finding-instances (incl. late conformance F16–F19). DONE: 13 (dc7aa709). PARTIAL: 4 (K19, K42,
|
||
C24, F14). DEFERRED: 12 (W11 JIT). GATE(D1): ~16 (JS host + Python standalone). RESOLVED-superseded:
|
||
1 (conf-S2). OPEN: the rest, distributed across W1–W12/W14/W15/W16.
|