Skip to content

Raise program/stalled and program/host faults on program steps - #6297

Draft
schickling-assistant wants to merge 18 commits into
schickling/2026-11-10-program-engine-hostfrom
schickling/2026-11-10-program-engine-faults
Draft

schickling-assistant wants to merge 18 commits into
schickling/2026-11-10-program-engine-hostfrom
schickling/2026-11-10-program-engine-faults

Conversation

@schickling-assistant

@schickling-assistant schickling-assistant commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Problem

A program step that stops journaling never raises anything, and a host that cannot start only logs a line (design §8, R11, DQ8).

Goal

  • program/stalled: a running program step whose journal has no new entry within its stalled-after raises a fault on the step naming its open key; closed on progress or when the step stops running.
  • program/host: raised from the engine's host_fault(step, attempt): a host that cannot start (Dispatched::HostDown), cannot resume after an exit, or a worker that missed its liveness deadline.
  • Both closed by the inactive-fault sweep when the run ends.

Decisions

  • Faults are on the step subject (one per program step, as "on every program step it held" requires), not the run subject, which would collide when a run has several program steps.
  • reconcile_program_faults runs once per program step in every run evaluation, right after the step's own evaluation, so a dispatch that just hit HostDown is seen in the same pass.
  • Stall deadline = max(last journal entry of the attempt, execution start) + stalled-after (default 30 minutes), armed with smallclaims::touched::note_due; journal entries are claims on the step, which its run's evaluation reads, so an entry moves the deadline without polling. The reason names no age, so a lasting stall is recorded once.
  • A HostDown step keeps its state and is dispatched again at a 30 s deadline (HOST_RETRY_MS); while program/host is open the step does not also raise program/stalled.
  • The engine's wake(step) (in Program engine M1.1b: run program steps on a supervised Bun host #6265) re-evaluates the run when the engine fails a step for liveness or cannot resume it.

Verification

On the build host, on an integration with #6261 and #6262, with real Bun:

  • cargo test -p fractal-reconcile --lib program_faults: 2 passed.
    • a_quiet_journal_raises_program_stalled_at_its_deadline_and_an_entry_closes_it: the due time equals the last entry plus stalled-after. At the deadline the fault names the open key and is recorded once; a new entry closes it and moves the due time; leaving working closes it.
    • a_host_that_cannot_start_raises_program_host_until_the_run_ends: a host that cannot start raises program/host with the engine's reason. The step keeps working with no stall, and the sweep closes the fault after the run ends.
  • cargo test -p fractal-reconcile --lib program_engine: 3 passed. The engine's real-host tests still pass with the fault hook.
  • python3 scripts/check-sqlite-large-values: passed.
    Hosted CI at the exact head is the proof.

Complexity

About 280 changed lines of its own (tests and docs included), plus #6261 merged in.

Concerns

  • A host fault lives in engine memory: after a daemon restart it is gone and the fault closes on the next evaluation (the restart retries the host anyway).
  • A step-subject fault does not set mission_run in attention items (attention_snapshot); run-filtered fault views do not list it yet.

Friction & bottlenecks

Build host memory: cold builds serialized across the program engine slices.

Follow-ups

Link step-subject faults to their run in attention items.

References

docs/st3/program-engine.md §8, DQ8; stacked on #6265 and merges #6261.

missions show projects each program step's current attempt journal (latest status, timing,
failure and child per key) under the step and in --json; the published work row names the
innermost open key with gate_kind program, so waiting-on reports kind program instead of
watching and no-progress once the journal is quiet past stalled-after.
…gine-core' into schickling/2026-11-10-program-engine-visibility
…gine-visibility' into schickling/2026-11-10-program-engine-faults
A running program step's evaluation arms a deadline at its last journal entry plus
stalled-after and raises program/stalled naming the open key past it; the engine's host
fault (a host that cannot start or a worker that missed its liveness deadline) raises
program/host and re-dispatches a waiting step at a deadline. The inactive sweep closes both.
…gine-visibility' into schickling/2026-11-10-program-engine-faults
…gine-host' into schickling/2026-11-10-program-engine-faults
…gine-visibility' into schickling/2026-11-10-program-engine-faults
…/kind page read

Three unresolved sinks share one fingerprint, so their IDs follow their order in the file;
moving the subject/kind page read into a function after the other two reorders them.
…gine-visibility' into schickling/2026-11-10-program-engine-faults
…tten

missions show --json failed client-side with "u128 is not supported": serde's flatten
buffers the journal through its Content type, which cannot hold u128. The view now
deserializes from its spelled-out wire fields; the JSON shape is unchanged.
…gine-visibility' into schickling/2026-11-10-program-engine-faults

This branch has not been deployed

No deployments
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.

2 participants