feat(rfc-026): stream_ingest/stream_manage Cedar actions and read-only stream status - #392
Merged
Merged
Conversation
…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.
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.
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_ingestandstream_manage, registered across all six sites inomnigraph-policy. Both graph-scoped: the experimental profile is main-only, so a branch dimension would describe a topology the lane refuses — bothbranch_scopeandtarget_branch_scopeare rejected at validation, with a matrix test that also round-trips each wire name throughFromStr.Two splits, each for a concrete reason rather than symmetry:
stream_ingestvschange— 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_ingestvsstream_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
Adminset_streaming_enabled_asnow enforcesstream_manage, which is what it always meant — P1 shipped on the reservedAdminaction only becausestream_managedid 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
adminaction no longer reaches the flip. Without it the split would be cosmetic.Read-only
stream_statusA 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 aHashMap's iteration order never reaches a result surface.Three deliberate properties:
forbidden_apisclassifies it read-only, which makes that a structural claim rather than a promise in a doc comment.stream_manage, so an operator can always see that a lane is stuck even without the rights to act on it.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
cluster statusalready surfaces the flag for P1 (via the live-graph observation), so nothing is currently invisible; adding an embedded-onlyomnigraph stream statusnow would need aKNOWN_DIVERGENCESentry in the parity matrix that we would delete again when HTTP lands in the front-door slice.LastFoldOutcomegainsas_strso status reports the durable wire name instead of minting a second spelling of it.Evidence
cargo test --workspace --lockedgreen.omnigraph-policy18/18 (new graph-scope/round-trip matrix);policy_engine_chassisdeny + allow + the admin-only negative;lifecycle.rsstatus against a graph with no lanes (including that re-reading mints no commit);memwal_stream.rsstatus against an enrolled lane, pinning the compare token;forbidden_apis19/19.Greptile Summary
This PR introduces the RFC-026 streaming authorization and status slice.
stream_ingestandstream_manageCedar actions.admintostream_manage.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
Snapshotparameter 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
admintostream_manage.stream_manageauthorization and rejection of the former admin-only grant.Reviews (2): Last reviewed commit: "fix: tighten stream status and policy su..." | Re-trigger Greptile