Phase 1: Strategy D: epoch / indirection revocation #73

Merged
erikinkinen merged 4 commits from 1-strategy-d-epoch-indirection-revocation into main 2026-03-06 10:19:31 +01:00
Owner

Closes #33


Summary

This PR adds Strategy D (epoch_indirection) for constant-time revocation via
edge-local epoch indirection.

Revocation no longer needs eager graph-wide deletion for this strategy:
RevokeCap bumps epochs on selected root edges, and enforcement is deferred to
UseCap via deterministic epoch-chain validation over delegation ancestry.

This keeps replay deterministic, preserves event-log v3 compatibility, and maps
stale epoch denials to the existing invalidated reason.


Scope

Included

  • Edge-local epoch metadata on CapabilityEdge:
    • epoch
    • epoch_at_issue
    • parent_epoch_at_issue
  • Epoch mutation primitive in EdgeStore:
    • bump_epoch(EdgeId) with overflow guard
  • Delegation wiring for epoch metadata:
    • DelegateCap captures parent_epoch_at_issue = parent.epoch
    • CreateCap initializes epoch fields to zero/default
    • ReduceRights preserves epoch metadata
  • New revocation strategy:
    • RevokerKind::EpochIndirection
    • epoch_indirection_revoker()
    • RevocationEnforcementPolicy::LazyEpoch
  • Revoke/Use behavior:
    • RevokeCap (Strategy D) bumps epochs on normalized direct roots
    • UseCap performs epoch-chain stale checks and denies with invalidated
  • CLI and event-log v3 wiring:
    • --revoker epoch_indirection
    • v3 revoker supports epoch_indirection
  • Validation/snapshot updates:
    • graph validation rules for parent/parent-epoch consistency
    • canonical snapshot/hash include epoch fields
  • Extensive deterministic test coverage across core, engine, and io replay/reader

Explicitly excluded

  • Event-log schema version bump (v=3 remains current)
  • New result reason taxonomy (no new stale_epoch reason)
  • Eager strategy semantics changes (A/C remain eager-delete + oracle gate)
  • Lazy marker strategy semantics changes (B remains marker-based lazy invalidate)

Behavioral contract (locked)

  1. Strategy D selector scope is normalized direct roots only.
  2. Revocation action is epoch bump only (no immediate edge deletion).
  3. Stale epoch denial uses existing UseCapOutcomeReason::Invalidated.
  4. Missing parent edge during epoch walk is a valid boundary.
  5. Existing parent with missing parent_epoch_at_issue is InvariantViolation.
  6. Epoch-chain cycles are InvariantViolation.
  7. Event-log remains v=3 with strategy-specific revoker metadata.

Design details

Epoch metadata model

  • epoch: current revocation epoch for the edge.
  • epoch_at_issue: issuance baseline for the edge itself.
  • parent_epoch_at_issue: parent epoch captured at delegation time.

UseCap epoch-chain check

For a present, non-marker-invalidated edge:

  • deny if edge.epoch != edge.epoch_at_issue
  • if no parent: chain valid boundary
  • if parent missing: valid boundary
  • if parent exists but parent_epoch_at_issue missing: invariant failure
  • deny if parent.epoch != child.parent_epoch_at_issue
  • continue upward; detect cycles via visited set and fail invariant on cycle

RevokeCap (Strategy D)

  • resolve normalized direct roots (sort+unique)
  • bump each target epoch via EdgeStore::bump_epoch
  • no edge deletion, removed_edges empty, edges_removed == 0
  • revocation cost counters remain strategy-independent and deterministic

Compatibility and replay

  • No new log version introduced.
  • v0/v1/v2 read/replay support unchanged.
  • v3 writer/reader now accepts revoker:"epoch_indirection".
  • Replay remains strategy-correct by applying record-specified revoker.
  • Reader/replay tamper checks extended for epoch strategy scenarios.

Verification

  • cmake --build _build --target aes_edge_store_tests aes_graph_validation_tests aes_snapshot_tests aes_apply_event_tests aes_engine_tests aes_revocation_strategy_tests aes_event_log_format_tests aes_event_log_reader_tests aes_event_log_replay_tests aes_cli_simulate_tests aes
  • ctest --test-dir _build --output-on-failure -R "aes_edge_store_tests|aes_graph_validation_tests|aes_snapshot_tests|aes_apply_event_tests|aes_engine_tests|aes_revocation_strategy_tests"
  • ctest --test-dir _build --output-on-failure -R "aes_event_log_format_tests|aes_event_log_reader_tests|aes_event_log_replay_tests|aes_cli_simulate_tests|aes_revocation_oracle_tests|aes_invalid_event_determinism_tests"

Review focus

  • Epoch metadata lifecycle correctness (CreateCap, DelegateCap, ReduceRights)
  • UseCap epoch-chain logic and invariant/error boundaries
  • Strategy D revocation correctness (bump only, deferred denial)
  • v3 revoker parse/encode and replay determinism for epoch_indirection
  • Snapshot/validation sensitivity to epoch metadata changes
Closes #33 --- ## Summary This PR adds Strategy D (`epoch_indirection`) for constant-time revocation via edge-local epoch indirection. Revocation no longer needs eager graph-wide deletion for this strategy: `RevokeCap` bumps epochs on selected root edges, and enforcement is deferred to `UseCap` via deterministic epoch-chain validation over delegation ancestry. This keeps replay deterministic, preserves event-log v3 compatibility, and maps stale epoch denials to the existing `invalidated` reason. --- ## Scope ### Included - Edge-local epoch metadata on `CapabilityEdge`: - `epoch` - `epoch_at_issue` - `parent_epoch_at_issue` - Epoch mutation primitive in `EdgeStore`: - `bump_epoch(EdgeId)` with overflow guard - Delegation wiring for epoch metadata: - `DelegateCap` captures `parent_epoch_at_issue = parent.epoch` - `CreateCap` initializes epoch fields to zero/default - `ReduceRights` preserves epoch metadata - New revocation strategy: - `RevokerKind::EpochIndirection` - `epoch_indirection_revoker()` - `RevocationEnforcementPolicy::LazyEpoch` - Revoke/Use behavior: - `RevokeCap` (Strategy D) bumps epochs on normalized direct roots - `UseCap` performs epoch-chain stale checks and denies with `invalidated` - CLI and event-log v3 wiring: - `--revoker epoch_indirection` - v3 `revoker` supports `epoch_indirection` - Validation/snapshot updates: - graph validation rules for parent/parent-epoch consistency - canonical snapshot/hash include epoch fields - Extensive deterministic test coverage across core, engine, and io replay/reader ### Explicitly excluded - Event-log schema version bump (`v=3` remains current) - New result reason taxonomy (no new `stale_epoch` reason) - Eager strategy semantics changes (A/C remain eager-delete + oracle gate) - Lazy marker strategy semantics changes (B remains marker-based lazy invalidate) --- ## Behavioral contract (locked) 1. Strategy D selector scope is normalized direct roots only. 2. Revocation action is epoch bump only (no immediate edge deletion). 3. Stale epoch denial uses existing `UseCapOutcomeReason::Invalidated`. 4. Missing parent edge during epoch walk is a valid boundary. 5. Existing parent with missing `parent_epoch_at_issue` is `InvariantViolation`. 6. Epoch-chain cycles are `InvariantViolation`. 7. Event-log remains `v=3` with strategy-specific `revoker` metadata. --- ## Design details ### Epoch metadata model - `epoch`: current revocation epoch for the edge. - `epoch_at_issue`: issuance baseline for the edge itself. - `parent_epoch_at_issue`: parent epoch captured at delegation time. ### UseCap epoch-chain check For a present, non-marker-invalidated edge: - deny if `edge.epoch != edge.epoch_at_issue` - if no parent: chain valid boundary - if parent missing: valid boundary - if parent exists but `parent_epoch_at_issue` missing: invariant failure - deny if `parent.epoch != child.parent_epoch_at_issue` - continue upward; detect cycles via visited set and fail invariant on cycle ### RevokeCap (Strategy D) - resolve normalized direct roots (`sort+unique`) - bump each target epoch via `EdgeStore::bump_epoch` - no edge deletion, `removed_edges` empty, `edges_removed == 0` - revocation cost counters remain strategy-independent and deterministic --- ## Compatibility and replay - No new log version introduced. - `v0/v1/v2` read/replay support unchanged. - `v3` writer/reader now accepts `revoker:"epoch_indirection"`. - Replay remains strategy-correct by applying record-specified revoker. - Reader/replay tamper checks extended for epoch strategy scenarios. --- ## Verification - [x] `cmake --build _build --target aes_edge_store_tests aes_graph_validation_tests aes_snapshot_tests aes_apply_event_tests aes_engine_tests aes_revocation_strategy_tests aes_event_log_format_tests aes_event_log_reader_tests aes_event_log_replay_tests aes_cli_simulate_tests aes` - [x] `ctest --test-dir _build --output-on-failure -R "aes_edge_store_tests|aes_graph_validation_tests|aes_snapshot_tests|aes_apply_event_tests|aes_engine_tests|aes_revocation_strategy_tests"` - [x] `ctest --test-dir _build --output-on-failure -R "aes_event_log_format_tests|aes_event_log_reader_tests|aes_event_log_replay_tests|aes_cli_simulate_tests|aes_revocation_oracle_tests|aes_invalid_event_determinism_tests"` --- ## Review focus - Epoch metadata lifecycle correctness (`CreateCap`, `DelegateCap`, `ReduceRights`) - `UseCap` epoch-chain logic and invariant/error boundaries - Strategy D revocation correctness (`bump` only, deferred denial) - v3 `revoker` parse/encode and replay determinism for `epoch_indirection` - Snapshot/validation sensitivity to epoch metadata changes
erikinkinen added this to the Phase 1 milestone 2026-03-06 10:18:27 +01:00
Phase 1: Add epoch correctness tests (#33)
All checks were successful
ci / smoke (pull_request) Successful in 18s
clang-format / check-format (pull_request) Successful in 9s
markdownlint / markdown-lint (pull_request) Successful in 9s
ci / smoke (push) Successful in 18s
clang-format / check-format (push) Successful in 9s
markdownlint / markdown-lint (push) Successful in 10s
6f412e6898
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
erikinkinen/AES!73
No description provided.