Context
The cascade-revocation functions (revoke_credential_cascade, revoke_credentials_cascade, migration 007; RETURNS TABLE in 029) find affected credentials by recursively walking parent_jti downward from an anchor. mission_id (migration 022) is a denormalized delegation-tree-root id that every credential in a tree shares, with its own btree index (idx_issued_credentials_mission_id).
The distinction
parent_jti walk = the anchor node + its descendants (a downward subtree). Excludes the anchor's ancestors and siblings.
WHERE mission_id = ? = the entire delegation tree in one indexed equality (no recursion).
They return the same set only when the anchor is the tree root. For a mid-tree anchor they differ — mission_id also sweeps the anchor's ancestors and sibling branches.
Why not just switch the existing functions
The current subtree semantics are the correct, least-surprising behaviour for token revocation: revoking a delegated child must not revoke the parent that delegated to it, nor unrelated sibling delegations. So mission_id is not a drop-in replacement for:
revoke_credential_cascade (RFC 7009 single-token revoke, auth-code replay) — anchor is often mid-tree; mission_id would over-revoke.
revoke_credentials_cascade (identity deactivation) — an identity may merely participate mid-tree in another tree; mission_id would sweep the whole foreign tree.
Proposal
Add a separate mission_id-indexed operation for the legitimate "revoke an entire mission in one shot" use case (e.g. tear down a whole delegation tree by its root), as a single indexed UPDATE ... WHERE mission_id = ? RETURNING ... — no recursion, faster than the walk. Keep the existing parent_jti subtree functions unchanged for per-token / per-identity revocation.
Scope / acceptance
Spun out of the RevocationNotifier PR (#172) review — deliberately kept separate since it's a new operation with different semantics, not a change to the established cascade.
🤖 Generated with Claude Code
Context
The cascade-revocation functions (
revoke_credential_cascade,revoke_credentials_cascade, migration 007;RETURNS TABLEin 029) find affected credentials by recursively walkingparent_jtidownward from an anchor.mission_id(migration 022) is a denormalized delegation-tree-root id that every credential in a tree shares, with its own btree index (idx_issued_credentials_mission_id).The distinction
parent_jtiwalk = the anchor node + its descendants (a downward subtree). Excludes the anchor's ancestors and siblings.WHERE mission_id = ?= the entire delegation tree in one indexed equality (no recursion).They return the same set only when the anchor is the tree root. For a mid-tree anchor they differ —
mission_idalso sweeps the anchor's ancestors and sibling branches.Why not just switch the existing functions
The current subtree semantics are the correct, least-surprising behaviour for token revocation: revoking a delegated child must not revoke the parent that delegated to it, nor unrelated sibling delegations. So
mission_idis not a drop-in replacement for:revoke_credential_cascade(RFC 7009 single-token revoke, auth-code replay) — anchor is often mid-tree;mission_idwould over-revoke.revoke_credentials_cascade(identity deactivation) — an identity may merely participate mid-tree in another tree;mission_idwould sweep the whole foreign tree.Proposal
Add a separate
mission_id-indexed operation for the legitimate "revoke an entire mission in one shot" use case (e.g. tear down a whole delegation tree by its root), as a single indexedUPDATE ... WHERE mission_id = ? RETURNING ...— no recursion, faster than the walk. Keep the existingparent_jtisubtree functions unchanged for per-token / per-identity revocation.Scope / acceptance
mission_id(indexed), returning affected rows for the RevocationNotifier fan-out (sameRevokedCredentialprojection).account_id/project_id) on the anchor, consistent with the existing functions.Spun out of the RevocationNotifier PR (#172) review — deliberately kept separate since it's a new operation with different semantics, not a change to the established cascade.
🤖 Generated with Claude Code