-- +goose Up -- The runner's half of a run: what the platform must know to spawn a transient systemd unit, to -- tail the engine's journal into this database, and to find out what happened to a unit it was not -- watching. The engine is NOT a child of this service (D39.106 §2), so every fact below has to -- survive the platform being restarted in the middle of the run that produced it. -- The ceiling of the run, in CHAPTERS: the unit the user chooses (D39.110 §2a). The money it is -- worth is not stored here, because it is not a property of the run's intent — the reservation row -- holds the amount that was actually taken. alter table runs add column ceiling_chapters integer not null default 0; -- Machine reason a run is paused, exactly the contract's PausedReason vocabulary. The DDL checks it -- because this value is produced by our own materializer: an unknown one is a defect, not data. alter table runs add column paused_reason text check (paused_reason in ('credit_exhausted')); -- When the money of this run was resolved. A run can be finished (the process is gone) and still -- unsettled (the hold is open) — those are different questions and the reconciler answers the -- second one on a retry, so it needs its own column rather than an inference from finished_at. alter table runs add column settled_at timestamptz; -- One transient unit per ATTEMPT, and everything needed to reason about it after a reboot. alter table run_attempts -- The transient unit's name. systemd's own state is not the truth (research/25 §Опс): the unit -- is started with --collect, so it is unloaded the moment it exits and `show` then answers -- "not-found" for a run that finished cleanly and for one that never existed alike. add column unit_name text, -- The VERSIONED path of the engine binary this attempt was pinned to (unified backlog row 139). -- The engine ships more often than a run finishes, so "the current binary" is not a stable -- answer; a resume uses the pinned path unless a resume with another version is asked for -- explicitly. add column engine_binary text not null default '', -- The ceiling handed to the engine for this attempt, in micro-USD. Kept because the hold can be -- released while the process is still exiting, and "what was this attempt allowed to spend" has -- to remain answerable afterwards. add column ceiling_micro_usd bigint not null default 0, -- Byte offset of the journal the cursor stands at. A HINT, not the cursor: the cursor of record -- is (engine_run_id, seq) (D39.106 §2). A hint that lands mid-file is simply where reading -- starts; what the cursor of record then does with the lines is decide them — a duplicate seq is -- skipped, a gap stops the projection of the attempt. It is NOT "the file is re-read from the -- start": that was written before the tailer was, and the register carries the correction. add column last_offset bigint not null default 0, -- SHA-256 of the line that moved last_seq. Delivery is at-least-once and a duplicate seq is -- NORMAL (PD-105); the same seq carrying a DIFFERENT payload is not, and it is the only form of -- corruption a high-water mark cannot see on its own. add column last_line_sha256 bytea, -- Cumulative spend as the engine last reported it, in micro-USD. Freshness only: the balance is -- protected by the hold and by the ceiling the engine enforces itself (D39.84/D39.100). add column spend_micro_usd bigint not null default 0, -- Set when materialization of this attempt was stopped on purpose. A quarantined attempt keeps -- RUNNING — the engine is not ours to kill over our own inability to read its journal — and its -- state is then only as fresh as the resync channel makes it. add column quarantine_reason text, -- What systemd said the unit's end was: $SERVICE_RESULT from ExecStopPost (success, exit-code, -- oom-kill, timeout, …). The exit CODE alone cannot distinguish "the engine exited 1" from "the -- kernel killed it", and the two lead to different next actions. add column exit_result text; -- Finding the live attempt of a run is on the hot path of every sweep of the reconciler. create index run_attempts_live_idx on run_attempts (run_id) where ended_at is null; -- +goose Down drop index run_attempts_live_idx; alter table run_attempts drop column exit_result, drop column quarantine_reason, drop column spend_micro_usd, drop column last_line_sha256, drop column last_offset, drop column ceiling_micro_usd, drop column engine_binary, drop column unit_name; alter table runs drop column settled_at; alter table runs drop column paused_reason; alter table runs drop column ceiling_chapters;