feat(gust): execute the composite — the claim holds, and the gate that checked it did not - #250
Open
avrabe wants to merge 2 commits into
Open
feat(gust): execute the composite — the claim holds, and the gate that checked it did not#250avrabe wants to merge 2 commits into
avrabe wants to merge 2 commits into
Conversation
…one clock observed, not asserted (REQ-OS-COMPOSITE-EXEC-001)
v0.6.0 shipped "exactly one scheduler and one clock" for the fused gust:os
component on STRUCTURAL evidence only: import routing across the unbundled core
modules (build-fused-gustos.sh gate 4) and executor-source ownership
(build-gustos-components.sh). Nobody had ever called it. This runs it.
gustos-hostrun instantiates fused-gustos.component.wasm on wasmtime 42.0.2,
supplying its two residual imports from the host — a fake gust:hal/mmio register
file (so every clock read is host-answered and observable) and gust:os/taskdisp
(so a task can actually be dispatched and complete).
Result: the claims HELD. 21/21 checks, notably
- spawn.start(0xA5) = 0; exec.state(0) = 1 (pending); timer.sleep(0,500) = 0 —
one handle accepted by all three interfaces;
- poll-round dispatched poll-task(0) — the id the trusted seam receives IS the
handle spawn minted, and the task's 1 -> 2 (done) transition is agreed by
exec.state, spawn.poll and timer.slept;
- spawn and exec exhaust ONE 8-slot table jointly (8 distinct handles across
both, then 0xFFFF_FFFF from either) — two private tables would allow 8 each;
- timer.sleep performs exactly ONE clock read, and the deadline it installs is
that read's answer + ticks (measured by sweeping the fake clock under the
pure timer.slept query: flips 0->1 at 4500 for a read served 4000, ticks 500)
— re-verified after jumping the register to 900000, where it flips at 901000.
A harness nobody has watched fail is not a gate, so the script also composes two
negative controls from the same unmodified providers. Control 1 binds timer to a
SECOND exec-provider instance: the harness refutes it (5 checks fail). That shape
is invisible to every existing gate — same world, same 5 unbundled core modules,
same import routing, gate 4 computes n_disp=n_spawn=n_timer=1 and ACCEPTS it; the
second task table is `(instantiate 0)` appearing twice, and a count over MODULES
cannot see a count over INSTANCES. Control 2 (a second time-provider instance) is
recorded as the known blind spot: the provider is stateless and both instances
read the same register through the same host import, so they are one clock source
reached twice and are indistinguishable at the seam.
Also observed, and NOT fixed here (timer-provider is out of scope for this
change): timer.sleep returns 0 (success) for an out-of-range handle (8,
0xDEADBEEF) and for a Done handle, where wit-os/gust-os.wit specifies
0xFFFF_FFFF. set_deadline correctly no-ops, so the arm is silently lost — the
caller is told a wake was armed that will never fire. Reported as a WIT
return-contract deviation in a separate bucket; it does not bear on the
one-scheduler/one-clock property.
Host-engine execution only. Nothing here is claimed about the dissolved/native
path — that is the second rung of REQ-OS-COMPOSITE-EXEC-001.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo
…t checked it did not REQ-OS-COMPOSITE-EXEC-001. v0.6.0 shipped "one scheduler, one clock" as a STRUCTURAL claim, established by import routing and source ownership. The composite had never been run. It has now, on wasmtime, and the claim was NOT refuted: spawn.start(0xA5) = 0 (not the invalid sentinel) exec.state(0) = 1 (pending) (recognised) timer.sleep(0, 500) = 0 (success) (same handle accepted) poll-round(1500) dispatched poll-task[0] <- timer's arming woke SPAWN's task then all three agree the task is done 21/21 checks. Corroborated independently: spawn and exec exhaust ONE 8-slot table jointly (two private tables would allow 8 each). The more valuable finding is about our own gate. Composing the SAME exec-provider twice — once for spawn, once for timer — produces a composite with byte-identical WIT, the same five core modules, and the same import routing. Two private task tables behind one facade. Every check in build-fused-gustos.sh accepted it, including the "one scheduler" check added in v0.6.0 and verified by hand at the time. The reason is now obvious and was not before: a count over MODULES cannot see a count over INSTANCES. The split composite instantiates module 0 twice. The gate now asserts every core module is instantiated exactly once, and that check refutes the split composite while passing the real one. Also found, reported not fixed: timer.sleep returns 0 (success) for an out-of-range handle, a garbage handle, and a completed task, where gust-os.wit specifies 0xFFFFFFFF. Tasks::set_deadline correctly no-ops, so the arm is silently lost — the caller is told a wake was armed that will never fire. Providers were out of scope for this task. The one-clock check is honest about its limits: it catches a different source register, an extra read during arming, a deadline not derived from the served value, and a timer that ignores a register jump. It does NOT distinguish two stateless instances of the same time provider reading the same register — that composite passes, and is one clock SOURCE reached twice. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
REQ-OS-COMPOSITE-EXEC-001. v0.6.0 shipped "one scheduler, one clock" as a structural claim — import routing and source ownership. The composite had never been executed. It has now, on wasmtime.The claim was not refuted
21/21. Independently corroborated:
spawnandexecexhaust one 8-slot table jointly — two private tables would allow 8 each.The finding that matters more: our gate could not have caught the opposite
Composing the same
exec-providertwice — once forspawn, once fortimer— yields a composite with byte-identical WIT (same md5 over imports+exports), the same five core modules, and the same import routing. Two private task tables behind one facade.Every check in
build-fused-gustos.shaccepted it — including the "one scheduler" check added in v0.6.0, which I verified by hand at the time and reported as sound.The reason is obvious in hindsight: a count over modules cannot see a count over instances.
The gate now asserts every core module is instantiated exactly once. It refutes the split composite and passes the real one. The harness is also a live gate — run against the split composite it fails 5 checks (
3d,3e,4c,4d,4e), so it is not a test that can only pass.Secondary: a real WIT contract deviation, reported not fixed
Tasks::set_deadlinecorrectly no-ops, so the arm is silently lost — the caller is told a wake was armed that will never fire. Providers were out of scope here.What the one-clock check does and does not catch
Catches: a different source register or offset; an extra read during arming; a deadline not derived from the value actually served; a timer that ignores a register jump (verified by jumping the register to 900000 and showing the deadline tracks to 901000).
Does not catch: two stateless instances of the same time provider reading the same register. That composite passes all 21 checks — and honestly, it is one clock source reached twice.
Not exercised: the dissolved/native path,
channel/io, 32-bit clock wraparound, multi-task interleaving, silicon.🤖 Generated with Claude Code
https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo