The generated C, amalgams, vendored runtime pins, and compiled binaries from the Claude Code era are removed from the worktree. The El sources survive; this tree is now source-only for the first-principles rebuild. Per Principal direction 2026-08-19.
8.6 KiB
CLAIMS — cycle 19, a convention is not a gate
Source doc: docs/v1/experiments/cycles/19-a-convention-is-not-a-gate.md
Pinned commits
| role | sha | subject |
|---|---|---|
| parent / before-state | cb7289f06510c002b6ab7c5ca8c2bd182d8216bc |
thread provenance end to end |
| experiment (system under test) | 9a6c161ba98a4e34275f46c39f18d120523f1ddb |
a slot must be validated before it is dereferenced |
| land (merge) | 3049a7083707de1508795e5daf3c65ab6ca21995 |
make the guard a gate: sha256_hex(50000) no longer segfaults |
| current HEAD at re-run time | a0cc95e3db7b04b6e221f89e89352b0e6b15d5b7 |
instrument build log |
Verdicts
| # | claim | artifact | commit | verdict |
|---|---|---|---|---|
| A1 | P1: looks_like_heap_obj is static, not exported |
0001-P1-looks-like-heap-obj-is-static.out |
cb7289f |
REPRODUCED (exact) |
| A2 | P2: each tagged type re-derives the check — geom_of and mfld_of full guard, el_bin_lookup floor only, el_input_len NULL only |
0002-P2P3-four-tagged-checks.out |
cb7289f |
REPRODUCED (exact, all four) |
| A3 | P3: at least one is missing guard components — two are | 0002 |
cb7289f |
REPRODUCED |
| A4 | el_bin_lookup reads 8 bytes BACKWARD |
0002 |
cb7289f |
REPRODUCED (exact) |
| A5 | el_input_len strlen's an integer |
0002 |
cb7289f |
REPRODUCED (exact) |
| A6 | P6: sha256_hex(50000) → exit 139, SIGSEGV, compiled clean |
0004-pre-cc-compiles-clean.out, 0005-P6-sha256-hex-50000-exit-code.out |
cb7289f |
REPRODUCED (exact) |
| A7 | measurement defect 4: the first run reported exit=0 because $? read head's status through a pipe |
0006-measurement-defect-4-control-pipe-hides-sigsegv.out |
cb7289f |
REPRODUCED (as a live control) |
| A8 | P8 IS THE USEFUL FAILURE — routing el_bin_lookup through the gate fixes nothing; the FALLBACK was the hazard |
0016–0019-P8-rederived-still-segfaults.out |
9a6c161 + patch |
NOT-CAPTURED historically; CORROBORATED by re-derivation |
| A9 | P9: the legitimate hash is unchanged | 0012-P9-legitimate-hash-unchanged.out |
cb7289f vs 9a6c161 |
REPRODUCED |
| A10 | el_tagged() is now exported in el_runtime.h |
0007-post-el-tagged-exported.out |
9a6c161 |
REPRODUCED (exact) |
| A11 | the fix: sha256_hex(50000) no longer segfaults |
0011-post-sha256-hex-50000-no-longer-segfaults.out |
9a6c161 |
REPRODUCED |
| A12 | P11: fixpoint and suites hold | 0013-P11-fixpoint.out |
9a6c161 |
REPRODUCED |
| A13 | 105/105 native | 0014-P11-native-suite.out |
9a6c161 |
REPRODUCED (exact) |
| A14 | 42/42 integration across eight harnesses | 0015-P11-eight-integration-harnesses.out |
9a6c161 |
REPRODUCED (exact) |
| A15 | "sixty seconds after diagnosing let s: String = 42 I wrote the identical defect into el_await" |
— | — | NOT-CAPTURED (narrative; no artifact of the pre-repair el_await — see cycle 18 A10) |
| A16 | the defect at current HEAD | 0020-head-sha256-hex-50000-TODAY.out |
a0cc95e3 |
fixed — exit 0 |
A6 — the headline, captured directly
Fixture fixtures/sha256_hex_int.el:
fn main() {
println(sha256_hex(50000))
}
At cb7289f: cc exits 0 with 0 errors (0004), and the program exits
139, stdout 0 bytes (0005).
The exit code was captured by capture.sh running the binary as the direct
child — "$@" > "$B.out" 2> "$B.err"; rc=$? — never through a pipe, which is the
control this record's own measurement defect 4 demands.
A7 — measurement defect 4, reproduced as a live control
0006 runs the same binary twice in one capture:
exit code read THROUGH A PIPE: 0 <- this is measurement defect 4
exit code read DIRECTLY: 139 <- the truth
A SIGSEGV really does read as a clean run when $? is taken after a pipeline
whose last stage succeeds. The defect the record confesses to is not an
anecdote; it is a reproducible property of the shell, demonstrated here against
the exact program it originally hid.
A1–A5 — the four checks, verbatim from cb7289f
0001: looks_like_heap_obj is declared static int at el_runtime.c:715,
and el_runtime.h contains 0 occurrences of either looks_like_heap_obj or
el_tagged. Not exported — so every sibling translation unit must re-derive it.
0002, the four call sites, exactly as tabulated in the record:
static ElGeometry* geom_of(el_val_t g) {
if (!looks_like_heap_obj(g)) return NULL; /* full guard — correct */
static ElManifold* mfld_of(el_val_t m) {
if (!looks_like_heap_obj(m)) return NULL; /* full guard — correct */
static int el_bin_lookup(const void* p, size_t* out_len) {
if (!p) { *out_len = 0; return 0; }
if ((uintptr_t)p < 4096) return 0; /* floor only */
const el_bin_hdr_t* hdr = (…)((const char*)p - sizeof(el_bin_hdr_t));
/* reads 8 bytes BACKWARD */
static size_t el_input_len(const char* s) {
size_t n;
if (el_bin_lookup(s, &n)) return n;
return s ? strlen(s) : 0; /* NULL only — strlen's an integer */
}
looks_like_heap_obj itself rejects zero, small ints (|s| < 0x10000), low
addresses and misaligned pointers. el_bin_lookup's 4096 floor has none of
those components, and 50000 clears it.
A8 — P8, the useful failure: re-derived, and labelled as such
The intermediate state P8 describes — el_bin_lookup routed through the gate,
el_input_len untouched — was never committed, so no historical artifact
exists and none was manufactured. It was reconstructed today from 9a6c161 by
reverting only the el_input_len hunk back to its cb7289f form. The
reconstruction script and the resulting diff are stored with the evidence:
fixtures/p8_reconstruct_intermediate.pyfixtures/p8_intermediate.patch
Result (0019): sha256_hex(50000) still exits 139.
So with the tagged lookup fully guarded and the fallback unguarded, the crash is
unchanged — the fallback was the hazard, exactly as P8 says. The committed fix
(9a6c161) needed both hunks:
if (!looks_like_heap_obj((el_val_t)(uintptr_t)hp)) return 0; /* el_bin_lookup */
…
if (!looks_like_heap_obj((el_val_t)(uintptr_t)s)) return 0; /* el_input_len */
return strlen(s);
Verdict wording matters here. The historical measurement is NOT-CAPTURED; the re-derivation CORROBORATES it. These are different things and the record should not conflate them.
A9 / A11 — the fix, and that it costs nothing
0012 — the legitimate hash is byte-identical across the change and matches an
independent implementation:
pre sha256_hex(abc) = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
post sha256_hex(abc) = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
reference (openssl) = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
0011 — the hazardous call now returns cleanly, exit 0:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
which is SHA-256 of the empty string: el_input_len now returns 0 for a slot
that is not a pointer, so the integer hashes as no bytes rather than walking
address 50000. Still true at HEAD (0020).
0007 — the gate is exported:
891:int el_tagged(el_val_t v, uint32_t magic); /* the gate: validate a slot BEFORE dereferencing it */
A12–A14 — the suites at 9a6c161
FIXPOINT-OK gen2 == gen3 (0013)
105 tests, 105 passed, 0 failed, 253 assertions (0014)
arity_query.sh exit=0 assertions=5
capability_query.sh exit=0 assertions=5
definitions_query.sh exit=0 assertions=6
prohibition_query.sh exit=0 assertions=4
seam_binding.sh exit=0 assertions=7
tagged_gate.sh exit=0 assertions=5
temporal_query.sh exit=0 assertions=6
temporal_signatures.sh exit=0 assertions=4
harnesses: 8 TOTAL assertions: 42 (0015)
105/105, eight harnesses, 42 assertions. All three figures exact.
Provenance notes
Behavioural captures come from /tmp/rerun-v1b-17-pre (a worktree at cb7289f,
shared with cycle 17 because the two cycles branch from the same parent),
/tmp/rerun-v1b-19-post (9a6c161) and /tmp/rerun-v1b-head (a0cc95e3).
The four P8 artifacts (0016–0019) carry DIRTY-TREE flags, correctly and
deliberately: the working tree was patched to construct a state that was never
committed, so those measurements are not reproducible by checking out
9a6c161 alone. They are reproducible by checking out 9a6c161 and applying
fixtures/p8_intermediate.patch, which is stored alongside them. The worktree
was removed after capture.