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.
74 lines
2.8 KiB
Markdown
74 lines
2.8 KiB
Markdown
# async — half expressible, and the cycle that was dogma
|
|
|
|
**Status: measured on a branch, not merged. Two runs — the first was invalid.**
|
|
|
|
## The first attempt was DOGMA, not science
|
|
|
|
I had just finished arguing that `@async` was expressible, then ran something to
|
|
confirm it. **No prediction was committed.** The test was rigged in a way that
|
|
should have been visible while writing it:
|
|
|
|
```c
|
|
pthread_create(&t,NULL,runner,NULL); pthread_join(t,NULL);
|
|
```
|
|
|
|
`join` immediately after `create` — the caller blocks until the body finishes.
|
|
That is a thread round-trip, not deferral. And the test printed the word
|
|
`DEFERRED` itself: I wrote the conclusion into the output and read it back.
|
|
|
|
```
|
|
Ishikawa on the rigged test
|
|
method ran after concluding, not to decide
|
|
machine nothing forces a prediction before execution
|
|
material the assertion was written into the output string
|
|
measurement no falsification criterion existed, so nothing could fail
|
|
root cause the test was authored by the party holding the conclusion,
|
|
with no commitment made before it ran
|
|
```
|
|
|
|
Discarded and re-run properly.
|
|
|
|
## Second run — predictions committed first
|
|
|
|
```
|
|
P1 the caller proceeds while the body runs expect TRUE
|
|
P2 interleaving is observable in timestamps expect TRUE
|
|
P3 the result cannot be retrieved — one 64-bit slot, no
|
|
future type, so the wrap either blocks or returns
|
|
something that is not the result expect TRUE
|
|
P4 therefore HALF expressible: fire-and-forget yes, await no expect TRUE
|
|
```
|
|
|
|
## Results — 4/4
|
|
|
|
```
|
|
[ 18 us] wrap RETURNS to caller
|
|
[ 29 us] body START
|
|
caller continues, got 0
|
|
[ 50176 us] body END (computed 42)
|
|
caller done
|
|
```
|
|
|
|
The caller got **0, not 42**. Both of my earlier claims were wrong in opposite
|
|
directions: "not expressible" was too strong — fire-and-forget works today,
|
|
bound after the build, no compiler change. "Expressible" was too strong the
|
|
other way.
|
|
|
|
## Follow-on cycle — a future is one more tagged object
|
|
|
|
```
|
|
P1 el_val_t already carries tagged heap objects TRUE 5 magic tags exist
|
|
P2 a future is one more TRUE
|
|
P3 the caller awaits and gets 42 TRUE
|
|
P4 ZERO compiler changes TRUE runtime C + one binding
|
|
P5 the unbound path still works FALSE SIGSEGV
|
|
```
|
|
|
|
**P4 is the result.** `@async` — called unexpressible for hours — needs no
|
|
compiler change. A future is one more magic-tagged heap object; `defer` returns
|
|
the handle, `el_await` blocks.
|
|
|
|
**P5 is the failure that mattered.** Sixty seconds after diagnosing
|
|
`let s: String = 42` as an arbitrary read, I wrote the identical defect into
|
|
`el_await`: reading `->magic` off an unvalidated slot. That opened cycle 19.
|