Phase 1: Revocation event types and API #66

Merged
erikinkinen merged 4 commits from 1-revocation-event-types-and-api into main 2026-03-03 15:45:50 +01:00
Owner

Summary

Introduces Phase 1 revocation as a first-class event via RevokeCap, with deterministic selector semantics, explicit revocation outcomes, and engine/log integration through existing paths.

Closes #26.

What changed

Event model

  • Added EventType::RevokeCap.
  • Added RevocationSelector { std::vector<EdgeId> edge_ids; }.
  • Added RevokeCapPayload { RevocationSelector selector; }.
  • Extended EventPayload/constructors for RevokeCap.

Revocation semantics (apply_event)

  • Implemented strict selector handling:
  • Normalize selector (sort + dedupe).
  • Reject invalid IDs (EdgeId{0}) with Errc::InvalidArgument.
  • Reject missing selected edges with Errc::NotFound.
  • Validate full selector before mutation (all-or-nothing behavior).
  • Empty selector is a valid no-op success.
  • On success, remove exactly selected edges in ascending order.
  • Added robust invariant-mapped error path for unexpected remove failures.

Result surface

  • Added RevocationResult:
  • targeted_edges (normalized, unique, ascending).
  • removed_edges (actual removed, ascending).
  • Added ApplyEventResult::revocation_result (std::optional).
  • Populated only for successful RevokeCap.
  • Cleared on hard errors (same discipline as delta and other outcomes).
  • Non-revoke events keep revocation_result empty.

Event log + replay

  • No log envelope version bump.
  • Added event token/payload support:
  • "type":"revoke_cap"
  • "payload":{"selector":{"edge_ids":[...]}}
  • v1 result behavior unchanged for non-UseCap events ({"ok":true,"reason":"ok"}).
  • Reader/replay accept revoke_cap and validate deltas as usual.

Engine integration

  • No new engine APIs required.
  • Engine::step/run now naturally handle RevokeCap through core::apply_event.
  • Successful revoke advances time and appends to history.
  • Failed revoke does not advance time/history.

Docs

  • Updated docs/model.md with RevokeCap semantics and removed “revocation selector absent” note.

Commit breakdown

  1. Phase 1: Add RevokeCap event type (#26)
  2. Phase 1: Define revocation selector semantics (#26)
  3. Phase 1: Define RevocationResult API surface (#26)
  4. Phase 1: Integrate revocation into engine loop (#26)

Test coverage

  • Added/updated tests for:
  • Event/type wiring and payload roundtrip.
  • Strict revoke_cap payload schema validation.
  • Selector normalization, dedupe, and deterministic delete ordering.
  • Empty-selector no-op success.
  • Invalid/missing selector targets with no mutation.
  • RevocationResult population and clearing rules.
  • Engine step/run behavior with revoke success/failure.
  • Reader/replay compatibility with logs containing revoke_cap.

Validation

  • cmake --build _build
  • ctest --test-dir _build --output-on-failure
  • Result: all tests passing (36/36).

Compatibility notes

  • Additive API change in core event/apply-result types.
  • Event-log envelope remains backward-compatible (v0/v1 unchanged structurally).
  • Existing non-revoke behavior is preserved.
## Summary Introduces Phase 1 revocation as a first-class event via `RevokeCap`, with deterministic selector semantics, explicit revocation outcomes, and engine/log integration through existing paths. Closes #26. ## What changed ### Event model - Added `EventType::RevokeCap`. - Added `RevocationSelector { std::vector<EdgeId> edge_ids; }`. - Added `RevokeCapPayload { RevocationSelector selector; }`. - Extended `EventPayload`/constructors for `RevokeCap`. ### Revocation semantics (`apply_event`) - Implemented strict selector handling: - Normalize selector (`sort + dedupe`). - Reject invalid IDs (`EdgeId{0}`) with `Errc::InvalidArgument`. - Reject missing selected edges with `Errc::NotFound`. - Validate full selector before mutation (all-or-nothing behavior). - Empty selector is a valid no-op success. - On success, remove exactly selected edges in ascending order. - Added robust invariant-mapped error path for unexpected remove failures. ### Result surface - Added `RevocationResult`: - `targeted_edges` (normalized, unique, ascending). - `removed_edges` (actual removed, ascending). - Added `ApplyEventResult::revocation_result` (`std::optional`). - Populated only for successful `RevokeCap`. - Cleared on hard errors (same discipline as `delta` and other outcomes). - Non-revoke events keep `revocation_result` empty. ### Event log + replay - No log envelope version bump. - Added event token/payload support: - `"type":"revoke_cap"` - `"payload":{"selector":{"edge_ids":[...]}}` - v1 `result` behavior unchanged for non-`UseCap` events (`{"ok":true,"reason":"ok"}`). - Reader/replay accept `revoke_cap` and validate deltas as usual. ### Engine integration - No new engine APIs required. - `Engine::step/run` now naturally handle `RevokeCap` through `core::apply_event`. - Successful revoke advances `time` and appends to `history`. - Failed revoke does not advance `time/history`. ### Docs - Updated `docs/model.md` with `RevokeCap` semantics and removed “revocation selector absent” note. ## Commit breakdown 1. `Phase 1: Add RevokeCap event type (#26)` 2. `Phase 1: Define revocation selector semantics (#26)` 3. `Phase 1: Define RevocationResult API surface (#26)` 4. `Phase 1: Integrate revocation into engine loop (#26)` ## Test coverage - Added/updated tests for: - Event/type wiring and payload roundtrip. - Strict `revoke_cap` payload schema validation. - Selector normalization, dedupe, and deterministic delete ordering. - Empty-selector no-op success. - Invalid/missing selector targets with no mutation. - `RevocationResult` population and clearing rules. - Engine `step`/`run` behavior with revoke success/failure. - Reader/replay compatibility with logs containing `revoke_cap`. ## Validation - `cmake --build _build` - `ctest --test-dir _build --output-on-failure` - Result: all tests passing (`36/36`). ## Compatibility notes - Additive API change in core event/apply-result types. - Event-log envelope remains backward-compatible (v0/v1 unchanged structurally). - Existing non-revoke behavior is preserved.
erikinkinen added this to the Phase 1 milestone 2026-03-03 15:35:43 +01:00
Phase 1: Integrate revocation into engine loop (#26)
All checks were successful
ci / smoke (push) Successful in 17s
clang-format / check-format (push) Successful in 9s
markdownlint / markdown-lint (push) Successful in 10s
ci / smoke (pull_request) Successful in 16s
clang-format / check-format (pull_request) Successful in 9s
markdownlint / markdown-lint (pull_request) Successful in 9s
7625c61c73
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!66
No description provided.