Skip to content

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
mainfrom
feat/composite-execution
Open

feat(gust): execute the composite — the claim holds, and the gate that checked it did not#250
avrabe wants to merge 2 commits into
mainfrom
feat/composite-execution

Conversation

@avrabe

@avrabe avrabe commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

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

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(1400) dispatched []             <- before the deadline, nothing
poll-round(1500) dispatched poll-task[0]   <- timer's arming woke SPAWN's task
                     then exec, spawn and timer all agree it is done

21/21. Independently corroborated: spawn and exec exhaust 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-provider twice — once for spawn, once for timer — 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.sh accepted 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.

fused-gustos        mod0 x1  mod1 x1  mod2 x1  mod3 x1  mod4 x1
split-sched-gustos  mod0 x2  ...

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

timer.sleep(8, 10)          = 0   (spec: 0xFFFFFFFF, out of range)
timer.sleep(0xDEADBEEF, 10) = 0   (spec: 0xFFFFFFFF)
timer.sleep(0, 10)          = 0   with exec.state(0) = done (spec: 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 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

avrabe and others added 2 commits July 30, 2026 23:18
…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

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant