Skip to content

Mission run authority: decide every write by a run, audited by default - #6272

Merged
schickling-assistant merged 15 commits into
mainfrom
schickling/2026-11-10-program-engine-authority-gate
Nov 10, 2026
Merged

schickling-assistant merged 15 commits into
mainfrom
schickling/2026-11-10-program-engine-authority-gate

Conversation

@schickling-assistant

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

Copy link
Copy Markdown
Contributor

Problem

A program step's effects act as mission-run/RUN (#6263), but nothing holds that actor to the authority the mission declares (#6260). docs/st3/program-engine.md §3 (D2): the run holds its revision's authority intersected with its starter's, "and nothing else".

Goal

Third PR of the M1.4 run-authority stack (stacked on #6263): one decision at the store's write admission for every claim a run writes, audited by default. The next PR (stacked here) makes enforce the default.

Decisions

  • Chokepoint: run_authority::admit_tx runs in append_admitted_claim_tx, beside the other actor gates. Writers that are not mission-run/* pass untouched.

  • What a claim needs:

    • mission.published on mission/ID: publish ID.
    • A run's mission-run.created and its initial run-generation.created: start ID.
    • A later generation: revise ID.
    • Anything else: write SUBJECT.
    • A run always journals program.step on its own step runs.
  • Effective authority, read at write time and never copied, so a starter that loses authority takes it from its runs:

    • Start from the authority of the run's current generation's revision.
    • Intersect it with the starter's. The starter is the actor of the run's mission-run.created.
    • When that starter is a run, recurse up the chain, bounded at 32.
    • A person, agent or daemon starter contributes everything free mode gives it. The rules that restrict it (rule.set in enforce mode) also decide each of the run's writes.
  • Program-started children: ChildMissionContext.started_by plus create_program_child_mission_run write the child's creation as mission-run/PARENT; the requester stays the human. The engine's child-run call (M1.2) switches to it.

  • Mode: the daemon setting [programs] authority = "audit" | "enforce", default audit here, read at start.

    • Audit records reuse rule.audited on rule/run-authority, readable with fractal rules audit run-authority. No new claim kind, no schema change.
    • Enforce refuses with run-authority-denied.
  • Cancel: setting another run's outcome (cancelling it) already takes a person or agent actor, so a run cannot cancel one; the docs say so instead of implying a grant.

  • Review fixes:

    • A run's message send stays on the graph append (legacy_reason returns run-sender), where the gate applies.
    • Documents a run binds are decided through a new Runtime::admit_writer_tx hook that the smallclaims document write calls.
    • Start vs revise is chosen by the generation's predecessor field, not its free-text reason.
    • Everything a revision writes on the runs it changes (proposal, carried and terminalized steps, superseded generation, run and descendant states) needs revise on that run's mission, not write, and those errors stay typed (run-authority-denied).
    • Each level of the starter chain reads only json_extract(body,'$.authority').
    • cancel is documented as reserved.

Verification

Run on the Linux build host at the stack head 5494372 (contains this PR), all pass:

fractal-store: covering_and_intersection_are_exact_for_namespaces ok, a_run_writes_only_within_its_authority_intersected_with_its_starters ok, writers_other_than_runs_are_untouched ok (9 passed incl. credential and barrier tests)
fractal (lib): a_program_effect_acts_as_its_run ok

Run on the Linux build host, cargo test -p fractal-store --lib -- run_authority run_credential declares_ and cargo test -p fractal --lib -- a_program_effect_acts_as_its_run: see above.

  • covering_and_intersection_are_exact_for_namespaces
  • a_run_writes_only_within_its_authority_intersected_with_its_starters:
    • a write inside the authority passes, attributed to the run; one outside is refused and nothing is written;
    • the child's creation is written as the parent;
    • the child's declared custom/* is narrowed to the parent's custom/factory/*;
    • the parent may not start a mission it lacks start for;
    • an undeclared mission's run writes nothing;
    • a starter's enforce-mode rule refuses both the run's write and its child's;
    • in audit mode the write proceeds and is recorded under rule/run-authority, and an in-authority write leaves no record.
  • writers_other_than_runs_are_untouched

Hosted CI at the exact head is the proof; pushed with ST_EVIDENCE_LOCAL=off.

Complexity

High risk by docs/review.md: the first enforced declared authority (a permission change) and a new config key. Lowered by shipping audit first, and because nothing writes as a run until the engine dispatches with credentials.

Concerns

  • The mode is process-wide (set once at daemon start). Tests that depend on it take a mutex.
  • A starter's rule refusal is recorded against the starter (rule.audited actor = starter) when that rule is in audit mode.

Friction & bottlenecks

The shared build host is serialized across slices.

Follow-ups

  • The engine mints the credential and journals as the run.
  • M1.2 swaps in create_program_child_mission_run.

References

docs/st3/program-engine.md §3; #6260, #6263.

…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
… pick start or revise by predecessor; read only the authority member
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
…gine-run-credential' into schickling/2026-11-10-program-engine-authority-gate
@schickling-assistant

Copy link
Copy Markdown
Contributor Author

Review record: independent reviewer round 1 at bc2bbb7c8a returned CHANGES. Findings: message sends on the messages shard bypassed the gate; start vs revise was chosen from free text; companion claims needed write; typed errors; performance. Round 2 at d0f61bce41ad8bd934959faca790527d92b71df0 returned GO, delta, with all four fixed: run-sender routing, predecessor-based start/revise, operation-verb companion claims with typed errors, and a single-column authority read. Risk high (trust path); audit is the default until #6273. The owner pre-approved queueing this effort's high-risk pull requests on an independent GO plus green CI. Queue alone after #6263, with CI green at the head. #6273 had a GO at 54943727; its new head 510b2191a6 needs a delta read.

Base automatically changed from schickling/2026-11-10-program-engine-run-credential to main November 10, 2026 19:53
@schickling-assistant

Copy link
Copy Markdown
Contributor Author

Delta review record for head 5a6fd5e49761cdb83b82312dccc2ef9c9cedc92d.

  • Independent reviewer: GO at d0f61bce41 (earlier rounds recorded above).
  • Delta at 5a6fd5e49761cdb83b82312dccc2ef9c9cedc92d: GO, no conditions beyond CI. The only change is a clean merge of main (c19482439c, which contains Mission run authority: bind run credentials to mission-run/RUN #6263). git show --remerge-diff is empty, and the PR's diff against main matches its earlier diff against the run-credential branch line for line (20 files, +629/-39). The run-authority check still sits in append_admitted_claim_tx before admit_reassignment, and the document hook admit_writer_tx is still called from put_document_as. Main's 149 new commits add no mutating routes, no raw append_claim_record_tx producers and no message-stream writers, so nothing new needs the gate.
  • Risk high: every write by a run is now decided (audit by default). Queue alone, not batched; Mission run authority: enforce by default #6273 follows.
  • The owner pre-approved queueing this effort's high-risk pull requests on an independent GO plus green CI.
  • Verdict: GO; queue alone on hosted CI green at this exact head.

@schickling-assistant
schickling-assistant added this pull request to the merge queue Nov 10, 2026
Merged via the queue into main with commit 4f21f2f Nov 10, 2026
75 of 76 checks passed
@schickling-assistant
schickling-assistant deleted the schickling/2026-11-10-program-engine-authority-gate branch November 10, 2026 21:38

This branch was previously deployed

1 inactive deployment
evidence-signing — 5a6fd5e4 Deployed Nov 10, 2026 by schickling-assistant via evidence-note-linux-gate #19628
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