Repository navigation
Program engine M1.1b: run program steps on a supervised Bun host - #6265
Draft
schickling-assistant wants to merge 10 commits into
Draft
schickling-assistant wants to merge 10 commits into
schickling-assistant wants to merge 10 commits into
Conversation
ProgramEngine dispatches each program attempt to one Bun host per member (program_host.mjs, protocol v1): a worker per attempt, effects in recorded process groups (boot id + leader start time, verified before the next host starts), worker and host liveness pings, modules read from the store blob into a verified cache file, one fenced result per key and attempt, and the program's $result journaled on done. Every run evaluation releases program attempts whose step left them, so cancellation, timeouts and retries stop the program and its effects at once. Bun joins the dev shell and the Rust check environment.
Contributor
Author
|
Build-host verification at efe0519 ( |
…ing/2026-11-10-program-engine-host # Conflicts: # crates/fractal-reconcile/src/reconcile.rs
A late message for an earlier attempt or a replaced host no longer removes the current attempt; ack, nack and cancel go only to the host generation that sent the entry while its attempt still runs; refused completed/failed entries (reserved key, missing key or status) are nacked. DQ2 reaping treats a leader as gone only on ESRCH, keeps records whose live leader's start time cannot be read, verifies half-renamed .tmp records, and uses absolute ps/sysctl paths on macOS.
…gine-core' into schickling/2026-11-10-program-engine-host
…gine-core' into schickling/2026-11-10-program-engine-host
This was referenced Nov 10, 2026
…m:compoundingtech/fractal into schickling/2026-11-10-program-engine-host
This was referenced Nov 10, 2026
Contributor
Author
|
Review record for head
|
This branch has not been deployed
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.
Stacked on #6264 (base
schickling/2026-11-10-program-engine-core), which depends on #6260.Problem
Declared program steps need an engine: a supervised host that runs program bodies, journals each inner step durably, resumes after crashes, stops promptly when the step ends, and cannot be wedged by one program's busy loop or a dead host.
Goal
M1.1b of docs/st3/program-engine.md:
ProgramEngine+program_host.mjsper host protocol v1.Decisions
child(…)(fieldrunis the run subject), per the contract fix.program:STEP:ATTEMPT:KEY:result;$resultjournaled ondonebefore the step completes; replay = current attempt's completed/failed entries, paged by 500.ProgramEngine::release_left(run)runs at the top of everyevaluate_one_mission_run(before the inactive-run return) and cancels attempts whose step ended, failed, timed out, retried, was cancelled with its run, or left the generation. The journal-write check stays as backstop.unresponsive, the step fails naming the deadline. The engine pings the host every 5 s and replaces one silent for 30 s; programs resume.wake(step)callback,Dispatched::HostDown(reason),host_fault(step, attempt).FRACTAL_PROGRAM_RUNTIME, elsebunon PATH (documented). Bun added to the dev shell and the Rust check environment so the engine tests run, never skip.program/hostsource; terminating a worker kills that attempt's groups.Verification
At head 3ba3725 (merge of #6264 @9aa1096557) on the Linux build host, with the real Bun host (
bun1.3.13 from the dev shell):CARGO_TARGET_DIR=<slice target> nix develop -c nice -n 19 cargo test -p fractal-reconcile --lib -- reconcile::program reconcile::tests::program_engine: 9 passed, 0 failed (1.62 s):recorded_groups_are_killed_only_when_their_leader_is_verified,messages_for_another_attempt_or_host_change_nothing,a_revision_runs_the_stored_blob_it_pins,a_key_has_one_result_per_attempt,replay_returns_this_attempts_results_in_order,replay_pages_through_long_journals_in_ordera_program_resumes_from_its_journal_after_its_host_is_killed,a_step_that_leaves_its_attempt_stops_its_program_and_effects_at_once,an_unresponsive_worker_fails_only_its_own_stepHosted CI at the exact head is the proof (pushed with
ST_EVIDENCE_LOCAL=off). The #6264 tests listed in that PR passed at its head 9aa1096.python3 scripts/check-sqlite-large-valuespassed at this head (4285 sites).Review findings answered
forgetremoves arunningentry only when step, attempt and host generation still match (instop_if_left,done,unresponsive).send_totargets that generation, and only while its attempt still runs.seq(reserved$result, missing key, missing status) is nacked.psas a dead leader on macOS": a leader counts as gone only whenkill(pid, 0)fails with ESRCH; a live leader whose start time cannot be read keeps its record and is not killed; macOS uses/bin/psand/usr/sbin/sysctlby absolute path..tmpgroup record names a group that already started":.tmprecords are verified and killed like.jsonrecords; comment corrected; test asserts a.tmprecord's verified group is killed.mission_programbarrier row, guard buffer test, main after docs: accepted program engine design and build plan #6253, corpus v19).include_str!("program_host.mjs")in the large-value inventory (marker + record); the inventory guard failed without it (not a review finding).Complexity
~730 lines engine + host, ~400 lines tests.
Concerns
ps -o lstart=,sysctl kern.boottime) are untested here (Linux build host only).Worker.terminate()interrupting a busy loop (covered by the unresponsive-worker test).Friction & bottlenecks
Build host load ~60–95 on 32 cores, ~6 GiB RAM free; cold builds serialized across slices.
Follow-ups
M1.2 children and asks; M1.3 faults/visibility; M1.4 authority (journal actor, run credential).
References
docs/st3/program-engine.md §1, §2, §5, §6, DQ2, DQ8; spike PR #6254.