Skip to content

feat(core): track authorization state at consensus - #448

Open
rickyrombo wants to merge 1 commit into
feat/consensus-ruleset-enginefrom
feat/consensus-auth-state
Open

feat(core): track authorization state at consensus#448
rickyrombo wants to merge 1 commit into
feat/consensus-ruleset-enginefrom
feat/consensus-auth-state

Conversation

@rickyrombo

Copy link
Copy Markdown
Contributor

What

Stacked on #447. Adds consensus-maintained authorization state: the core_auth_* tables (users, grants, developer apps, entity ownership), populated by FinalizeBlock inside the block's pg transaction for both live ManageEntity and genesis-migration transactions. Every validator ends up with an identical, deterministic answer to "is this signer allowed to act for this user?" — without consulting the (non-consensus) ETL.

Nothing reads this state yet. Enforcement lands separately behind an upgrade-schedule height gate (next PR in the stack).

Design

Validate-then-apply, mirroring the ETL. The projection (pkg/core/server/auth_state.go) restates the auth-relevant rules of the ETL's entity_manager handlers: ValidateSigner (own wallet, or an active non-revoked grant whose grantee is a live app or active user, approved for user-to-user manager grants), wallet/handle/app-address/entity-id uniqueness, ownership on delete, and the grant create → approve/reject → revoke lifecycle. A tx whose auth effects the ETL would reject is skipped here too — otherwise the projection would accumulate state from rejected txs and, once enforcement exists, that state would be authoritative. This matters most in the pre-enforcement window.

Migration replay is relaxed exactly where the ETL relaxes it. Migration txs keep signer-authority checks (genesis-writer signs as the owning user) but drop wallet/handle uniqueness and ID offsets — legacy source data is the authority on those, and can contain collisions. Deleted tracks/playlists replay with their deleted flag. This means the genesis replay leaves behind a complete auth state, which is what the first live transaction after the migration boundary will validate against.

Deliberately not mirrored: content rules (title required, genre validity, gating conditions). Consequence documented in the file: a tx the ETL rejects on a content rule still projects here if its authorization is valid, so that entity id reads as taken. That conservative approximation is the price of keeping content semantics out of consensus.

Determinism: reads by primary key only, addresses/handles lowercased at write time, no clocks, ErrNoRows = absent (never an error), all writes conflict-safe so replay is idempotent. Store failures are logged without failing the tx, matching how the rest of FinalizeBlock treats local db errors.

Current-state only: unlike the ETL's history-keeping tables (is_current rows), core_auth_grants holds one row per (grantee, grantor) pair — consensus only ever asks about the present.

Testing

auth_state_test.go runs the projection against a map-backed store: wallet/handle uniqueness (live vs migration), app-grant auto-approval and revocation, the user-to-user pending → approve/reject lifecycle, grantee-side revocation, ownership-checked deletes, deactivation ending grantee liveness, and the {\"cid\":...,\"data\":{...}} metadata envelope unwrap. go test ./pkg/core/server/ green.

🤖 Generated with Claude Code

Adds the core_auth_* tables — users, grants, developer apps, entity
ownership — as a consensus-maintained projection of the
authorization-relevant subset of ManageEntity effects. FinalizeBlock
applies the projection inside the block's transaction for both live and
genesis-migration transactions, so every validator holds an identical
answer to 'is this signer allowed to act for this user?' without
consulting the (non-consensus) ETL.

The projection mirrors the ETL's entity_manager handlers — validate,
then apply — so consensus state tracks what the ETL actually indexes:
wallet/handle uniqueness on live user creates (relaxed for migration
replay, where legacy source data is the authority), signer authority via
own-wallet or active approved grants, grantee liveness, entity ownership
on create/delete, and the grant create/approve/reject/revoke lifecycle.
Content semantics (titles, genres, gating) stay in the ETL on purpose.

Nothing reads this state yet: enforcement arrives separately behind an
upgrade-schedule height gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rickyrombo
rickyrombo force-pushed the feat/consensus-auth-state branch from 0dec4c1 to bccecad Compare August 6, 2026 08:36
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