Skip to content

feat(rfc-026): stream_ingest/stream_manage Cedar actions and read-only stream status - #392

Merged
aaltshuler merged 3 commits into
mainfrom
rfc026/exp-p1-stream-manage
Jul 28, 2026
Merged

feat(rfc-026): stream_ingest/stream_manage Cedar actions and read-only stream status#392
aaltshuler merged 3 commits into
mainfrom
rfc026/exp-p1-stream-manage

Conversation

@aaltshuler

@aaltshuler aaltshuler commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Slice 2a of the RFC-026 §4.7 experimental profile — the authorization split and the read-only status the management verbs need before they can be written as compare-and-set. Follows #389 (P1 enablement authority, internal schema v10).

No format change, no new durable state, no new lifecycle transition.

The Cedar split (§4.6)

stream_ingest and stream_manage, registered across all six sites in omnigraph-policy. Both graph-scoped: the experimental profile is main-only, so a branch dimension would describe a topology the lane refuses — both branch_scope and target_branch_scope are rejected at validation, with a matrix test that also round-trips each wire name through FromStr.

Two splits, each for a concrete reason rather than symmetry:

  • stream_ingest vs change — a stream append acknowledges durability without graph visibility. Those are genuinely independent grants: you may want a high-rate producer that cannot make direct-lane writes, or an operator who can mutate but not admit into a lane.
  • stream_ingest vs stream_manage — the blast radii differ in kind. Ingestion adds rows; management can seal a lane, drain acknowledged data, or reopen it at a new epoch.

The P1 flip migrates off Admin

set_streaming_enabled_as now enforces stream_manage, which is what it always meant — P1 shipped on the reserved Admin action only because stream_manage did not exist yet. In-window because §4.7 declares the experimental profile's authorization surface unstable.

The chassis test asserts both directions, and the negative is the load-bearing half: a policy granting only the old admin action no longer reaches the flip. Without it the split would be cosmetic.

Read-only stream_status

A pure projection of one canonical-main manifest snapshot: the enablement flag and its revision, plus per-lane lifecycle, lifecycle_revision, enrollment id, epoch floors, drain/strict-block identity, and last-fold outcome — sorted, so a HashMap's iteration order never reaches a result surface.

Three deliberate properties:

  • Structurally lifecycle-inert. No admission lease, no recovery resolution, no publication — and forbidden_apis classifies it read-only, which makes that a structural claim rather than a promise in a doc comment.
  • Least-privileged. Authorized like other graph operational metadata, not by stream_manage, so an operator can always see that a lane is stuck even without the rights to act on it.
  • Honestly scoped. This is the §4.7 minimal status: the authoritative manifest row. Fields whose only truthful source is §4.3's exclusive-cut physical read — observed epoch, pending generation rows/bytes, StatusChanged/StatusBusy — are absent rather than guessed from durable state. They arrive additively with the verbs that need them, so nothing here becomes wrong later.

Why status ships before the verbs

§4.6 makes status the compare-token source: every mutating management call is compare-and-set against an expected lifecycle_revision, and status is where callers read it. Shipping it first is what lets fold/quiesce/resume be written as CAS from the start rather than retrofitted.

Scope calls

  • CLI deferred to the slice that ships the verbs. cluster status already surfaces the flag for P1 (via the live-graph observation), so nothing is currently invisible; adding an embedded-only omnigraph stream status now would need a KNOWN_DIVERGENCES entry in the parity matrix that we would delete again when HTTP lands in the front-door slice.
  • LastFoldOutcome gains as_str so status reports the durable wire name instead of minting a second spelling of it.

Evidence

cargo test --workspace --locked green. omnigraph-policy 18/18 (new graph-scope/round-trip matrix); policy_engine_chassis deny + allow + the admin-only negative; lifecycle.rs status against a graph with no lanes (including that re-reading mints no commit); memwal_stream.rs status against an enrolled lane, pinning the compare token; forbidden_apis 19/19.

Greptile Summary

This PR introduces the RFC-026 streaming authorization and status slice.

  • Registers graph-scoped stream_ingest and stream_manage Cedar actions.
  • Moves streaming enablement authorization from admin to stream_manage.
  • Adds deterministic, read-only embedded stream status types and lifecycle projection.
  • Updates policy, lifecycle, MemWAL, CLI parsing, structural read-only checks, and documentation.

Confidence Score: 3/5

The PR is not yet safe to merge because stream status can still return profile and lifecycle authority from different manifest versions.

Live branch resolution replaces the profile inside an already-resolved snapshot using an independent canonical-profile read, so the status projector's single Snapshot parameter does not ensure that all returned fields came from one manifest revision.

Files Needing Attention: crates/omnigraph/src/db/omnigraph/stream_status.rs, crates/omnigraph/src/db/omnigraph.rs

Important Files Changed

Filename Overview
crates/omnigraph/src/db/omnigraph/stream_status.rs Adds the public manifest-backed stream-status projection and deterministic lane ordering.
crates/omnigraph/src/db/omnigraph/stream_profile.rs Changes streaming-profile mutation authorization from admin to stream_manage.
crates/omnigraph-policy/src/lib.rs Registers and validates the new graph-scoped streaming policy actions.
crates/omnigraph/tests/policy_engine_chassis.rs Covers both stream_manage authorization and rejection of the former admin-only grant.

Reviews (2): Last reviewed commit: "fix: tighten stream status and policy su..." | Re-trigger Greptile

…status

RFC-026 §4.6's streaming authorization split, plus the read-only status the
management verbs need before they can be written as compare-and-set.

Cedar: register stream_ingest and stream_manage across all six sites. Both are
graph-scoped -- the experimental profile is main-only, so a branch dimension
would describe a topology the lane refuses, and both scope qualifiers are
rejected at validation. They are split from each other because the blast radii
differ in kind: ingestion adds rows, while management can seal a lane, drain
acknowledged data, or reopen it at a new epoch. Ingest is likewise split from
"change" because a stream append acknowledges durability without graph
visibility, so the two grants are genuinely independent.

Migrate the P1 enablement flip off the reserved "admin" action onto
stream_manage, which is what it always meant; P1 predated the new action's
existence. The migration is in-window because §4.7 declares the experimental
profile's authorization surface unstable. The chassis test asserts both
directions, including that an admin-only policy no longer reaches the flip --
without that negative the split would be cosmetic.

Add Omnigraph::stream_status: a pure projection of one canonical-main manifest
snapshot -- the enablement flag, its revision, and per-lane lifecycle, epoch
floors, drain/strict-block identity, and last-fold outcome, sorted so a
HashMap's iteration order never reaches a result surface. It takes no admission
lease, resolves no recovery, and publishes nothing; forbidden_apis classifies
it read-only, which is the structural claim that status cannot move a
lifecycle. It is authorized like other graph operational metadata rather than
by stream_manage, so an operator can always see that a lane is stuck even
without the rights to act on it.

Status ships before fold/quiesce/resume deliberately: §4.6 makes it the
compare-token source, exposing the lifecycle_revision those verbs pass back as
their expected revision. Scope is the §4.7 minimal status -- the authoritative
manifest row. Fields whose only honest source is §4.3's exclusive-cut physical
read (observed epoch, pending generation rows/bytes, StatusChanged/StatusBusy)
are absent rather than guessed from durable state; they arrive additively with
the verbs that need them. The CLI verb is deferred to the slice that ships the
verbs, so no embedded-only surface enters the parity matrix only to be reworked
when HTTP lands.

LastFoldOutcome gains as_str so status reports the durable wire name instead of
minting a second spelling of it.
Comment thread crates/omnigraph/src/db/omnigraph/stream_status.rs Outdated
@aaltshuler
aaltshuler merged commit 329ace3 into main Jul 28, 2026
8 checks passed
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