c6ba0677f0
cycles/ one file per Ishikawa -> scientific method -> Six Sigma loop, named
for the DEFECT not the fix, carrying the commit record as written at
the time
findings/ what the cycles produced, cross-cut: live bugs, architecture answers,
and defects in my own measurement
The organising finding is that predictions which came back FALSE produced every
significant result. Eleven of sixty-one failed, and those eleven found: that the
arity table was not drifted but 40% incomplete; that the AST traversal is
irreducible and only rules and judgments move; that guards could refuse through
the seam after all; and that routing el_bin_lookup through the gate did NOT fix
the SIGSEGV, because the fallback strlen was the hazard -- a wrong fix I would
otherwise have shipped as verified.
One cycle was run without committing predictions first and had to be discarded
as rigged. It is kept, in full, as 18-async-half-expressible.md.
171 lines
7.2 KiB
Markdown
171 lines
7.2 KiB
Markdown
# the crossing resolves at emission
|
|
|
|
One `Ishikawa → scientific method → Six Sigma` loop. The record below is the
|
|
commit message as written at the time, before the outcome was known to anyone
|
|
reading this file.
|
|
|
|
## Record — `35b07ba`
|
|
|
|
```
|
|
EXPERIMENT: resolve the crossing at execution, not at emission
|
|
|
|
HYPOTHESIS (Will's): a compiler whose one compiled mechanism is extending the
|
|
LANGUAGE — not the compiler — can compose without recompilation.
|
|
|
|
ISHIKAWA — why does a construct require a recompile today?
|
|
method codegen inlines the target call into the body
|
|
machine the binary has no table to consult
|
|
material the declaration lives in source, read at compile time
|
|
measurement nothing observes what applied at runtime
|
|
root cause the crossing is resolved at EMISSION, not at EXECUTION
|
|
|
|
CHANGE: codegen emits one unconditional indirection per fn. Which constructs
|
|
apply is read from a table that can be written AFTER the binary exists;
|
|
targets resolve through dlsym against the running image.
|
|
|
|
PREDICTIONS AND RESULTS
|
|
P1 a construct declared after the build applies TRUE
|
|
P2 an unlinked target is skipped, not fatal TRUE
|
|
P3 emitting on every fn is measurably slower FALSE — 0.37s -> 0.36s
|
|
with 267 indirections and
|
|
no bindings. Free unused.
|
|
P4 the compiler still self-hosts TRUE (see note)
|
|
|
|
DEMONSTRATED: an El program with NO decorator in its source, already compiled
|
|
and linked, picked up a construct declared afterwards:
|
|
|
|
$ /tmp/seamrun -> 7
|
|
$ echo 'work audited entry audit_entry' > constructs.txt
|
|
$ EL_CONSTRUCTS=constructs.txt /tmp/seamrun
|
|
AUDIT: work applied by audited
|
|
7
|
|
|
|
P4 note: my first fixpoint test was wrong, not the code. I compared gen1 to
|
|
gen2, which must differ whenever codegen's output changes. gen2 == gen3, 267
|
|
seam sites, stable.
|
|
|
|
MEASURED COST, and the root cause was not where I looked
|
|
0 bindings 0.36s vs 0.37s baseline free
|
|
2 bindings, dlsym per call 2.45s 6.6x
|
|
2 bindings, resolved once 0.69s 3.5x recovered
|
|
The table scan was never the cost. dlsym walks the dynamic symbol table on
|
|
every call. Resolve once and cache — which is the smallest form of what
|
|
salience does for memory: what is hot stays resolved. The 0.69s residual is
|
|
audit_entry's own printf on two of the compiler's hottest functions, not seam
|
|
overhead.
|
|
|
|
CONSEQUENCE: the five compile-time declaration kinds on iteration-1 are a
|
|
compile-time specialisation of something that resolves at runtime. They are not
|
|
wrong, but they are not the mechanism — the mechanism is one indirection, and a
|
|
kind is data.
|
|
```
|
|
|
|
## Record — `886626a`
|
|
|
|
```
|
|
seam refusal + control tests: a runtime binding can short-circuit
|
|
|
|
Prediction 3 was FALSE. I expected refusal to be impossible through the seam
|
|
because the entry indirection discarded its return. One line:
|
|
|
|
{ el_val_t __s = el_seam_run(EL_STR(f), 0, 0); if (__s) return __s; }
|
|
|
|
work() returns 7; bound to a refusing construct AFTER the build it returns 42.
|
|
So three of the five compile-time kinds are runtime-bindable: entry injection,
|
|
exit injection, and refusal. wraps_body needs invocation control and
|
|
prohibits_outside is compile-time by nature.
|
|
|
|
104/104 native compiler tests pass.
|
|
```
|
|
|
|
## Record — `28d19da`
|
|
|
|
```
|
|
strip the compile-time machinery the seam replaces
|
|
|
|
PREDICTION: codegen.el drops below 4661, its size before any of these passes.
|
|
RESULT: FALSE. 5157 -> 5096. Still +435 over baseline.
|
|
|
|
injects_at_entry collapsed into the seam removed
|
|
guards_at_entry collapsed into the seam removed
|
|
injects_at_exit needs the body-helper wrapper STRUCTURAL
|
|
wraps_body needs the closure + wrapper structural
|
|
prohibits_outside a #error cannot be emitted at runtime
|
|
|
|
The wrapper is not a consequence of compile-time resolution. Early returns must
|
|
be routed through something no matter when the target is resolved, so exit
|
|
injection was never going to collapse. I predicted it would because I had
|
|
conflated "resolved late" with "emitted less".
|
|
|
|
What did collapse is entry injection and refusal -- 61 lines of compiler
|
|
replaced by one refusable indirection, with the capability now bindable after
|
|
the binary exists.
|
|
|
|
8 tests fail, and they are exactly the 8 controls for compile-time entry
|
|
injection and guards. No unrelated breakage: the controls reported precisely
|
|
what moved. They assert emission of something that now happens at runtime, so
|
|
they need rewriting as integration tests -- which the framework does not
|
|
currently support, because runtime binding needs a built binary and an
|
|
environment, not compile_capture.
|
|
|
|
Verified after the strip: fixpoint gen2==gen3, observation and refusal both
|
|
work through the seam with the compiler knowing nothing about either.
|
|
```
|
|
|
|
## Record — `8bbb750`
|
|
|
|
```
|
|
control the claim that cannot be unit tested
|
|
|
|
The seam's whole claim is that a construct declared AFTER a binary exists
|
|
applies to that already-built program. compile_capture only sees emitted text,
|
|
so it structurally cannot check this: it needs a built binary, a linked target,
|
|
and an environment. Verified by hand until now, which is the standing problem
|
|
this session has been about.
|
|
|
|
tests/integration/seam_binding.sh builds a probe from El source containing no
|
|
construct at all, links a target that El never references, and asserts:
|
|
|
|
ok unbound program is unaffected
|
|
ok a construct declared AFTER the build applies
|
|
ok a construct declared after the build can REFUSE
|
|
ok an unlinked target is skipped, not fatal
|
|
ok a binding for a different fn does not fire
|
|
ok two constructs compose on one crossing
|
|
|
|
6 assertions, 6 passed, 0 failed
|
|
|
|
The eight controls that failed after the strip were replaced, not repaired.
|
|
They asserted compile-time emission of capability that moved to runtime;
|
|
contorting them would have kept an assertion whose subject no longer exists.
|
|
Three took their place, asserting the emitted shape, and the behaviour they
|
|
used to cover is now the integration harness's job -- which is the honest
|
|
division, since the shape and the behaviour are no longer the same fact.
|
|
|
|
99/99 native compiler tests pass. Fixpoint holds.
|
|
```
|
|
|
|
## Record — `24f7fb5`
|
|
|
|
```
|
|
land the runtime seam: resolve the crossing at execution
|
|
|
|
Five compile-time passes added 491 lines to the thing that was supposed to stop
|
|
growing. The seam is ~55 lines of C and one line of emission, and it does at
|
|
runtime what three of those five kinds did at compile time -- for programs that
|
|
are already built.
|
|
|
|
a construct declared AFTER the binary exists applies to it
|
|
free when unused: 0.36s vs 0.37s baseline across 267 indirections
|
|
dlsym was the cost, not the table scan; resolve-once recovered 3.5x
|
|
refusal works, composition works, unlinked targets are skipped not fatal
|
|
|
|
injects_at_exit and wraps_body do NOT collapse: early returns must route
|
|
through the body-helper wrapper regardless of when the target is resolved. The
|
|
wrapper is structural, which I had wrong. prohibits_outside cannot move at all
|
|
-- a #error has no runtime.
|
|
|
|
Controls: 99/99 native compiler tests, plus tests/integration/seam_binding.sh
|
|
(6/6) for the claim compile_capture structurally cannot see.
|
|
```
|