Phase 0: Event application API #50

Merged
erikinkinen merged 4 commits from 0-event-application-api into main 2026-02-17 06:46:39 +01:00
Owner

Closes #8


Summary

This PR implements the event application API for Phase 0, introducing apply_event() as the single, canonical mechanism for mutating the authority graph. This establishes strict mutation discipline: all graph modifications must occur through event application, with explicit precondition checking and explicit delta reporting.

The implementation supports all Phase 0 event types (CreateSubject, CreateObject, CreateCap, DeleteCap, DelegateCap, ReduceRights, DestroyObject, DestroySubject, UseCap) and enforces all invariants (I1–I10) through mandatory runtime precondition checks.


Scope

Included

  • apply_event() API with ApplyEventResult containing error status and explicit GraphDelta
  • All Phase 0 event type handlers with precondition validation
  • GraphDelta structure tracking all graph mutations (created/destroyed nodes, created/deleted/modified edges)
  • TestAccess helper for unit tests to access store methods directly (test-only, not for production)
  • Private mutation methods on SubjectStore, ObjectStore, and EdgeStore (accessible only through apply_event() or TestAccess)
  • Comprehensive unit tests for all event types and precondition violations
  • Documentation in docs/model.md covering preconditions, postconditions, and event application discipline

Explicitly excluded

  • Temporal semantics (creation time, generations) — reserved for Phase 1+
  • Revocation mechanisms — reserved for later phases
  • Event log persistence or replay — out of scope for Phase 0
  • Optimizations (batching, incremental validation) — premature for initial implementation

Design intent

The event application API establishes mutation discipline as a first-class architectural constraint. By making store mutation methods private and accessible only through apply_event(), the design enforces that:

  1. All graph changes are explicit and traceable: Every mutation produces a GraphDelta describing exactly what changed
  2. Preconditions are mandatory: Invalid operations fail visibly with specific error codes rather than corrupting state
  3. The graph is always valid: Atomic event application means either all postconditions hold or the graph remains unchanged
  4. Tests remain practical: TestAccess allows direct store manipulation in unit tests while preventing accidental misuse in production

This design supports the broader AES goal of deterministic, reproducible simulation by ensuring that the authority graph evolves only through well-defined event sequences.


Phase discipline

Phase 0: Event Application API

This PR completes the Phase 0 authority model by implementing the event application layer. It builds on prior Phase 0 work:

  • Subject/Object node storage (#46)
  • Capability edge representation (#47)
  • Graph indexing and integrity (#48)
  • Event taxonomy (#49)

Phase stability: The semantics of Phase 0 events are now fixed. Later phases may introduce new event types but must not retroactively alter the meaning of Phase 0 events.

Reserved fields: The GraphDelta structure does not include temporal information (creation time, generation counters). These fields are reserved for Phase 1+ when the temporal model is defined.


Verification

  • Tests pass (316 test cases covering all event types and preconditions)
  • All Phase 0 event types implemented with precondition validation
  • Store mutation methods made private and accessible only through apply_event() or TestAccess
  • GraphDelta correctly reports all mutations
  • Model documentation updated with preconditions, postconditions, and discipline
  • No regressions in existing functionality (all existing tests updated to use TestAccess)

Notes

Review focus:

  • Precondition encoding in core/src/apply_event.cpp — ensure all invariants (I1-I10) are enforced
  • TestAccess usage pattern — confirm it's only used in tests, never in production code
  • GraphDelta completeness — verify all mutations are recorded

Implementation notes:

  • Some helper methods (e.g., edges_from_subject()) were made public to support precondition checking without exposing mutation methods
  • Debug labels remain accessible in test builds to support debugging and test readability
  • UseCap event is a no-op in Phase 0 (temporal effects reserved for later phases)

Known limitations:

  • Error messages are minimal (just error codes). Rich error context (e.g., "subject S1 not found") could be added later.
  • Performance is not optimized. Precondition checks may be redundant with internal store validation.

Follow-up work:

  • Integration with simulation engine (event dispatch, ID allocation)
  • Event log serialization/deserialization (if persistence is needed)
  • Phase 1 temporal extensions
Closes #8 --- ## Summary This PR implements the **event application API** for Phase 0, introducing `apply_event()` as the single, canonical mechanism for mutating the authority graph. This establishes strict mutation discipline: all graph modifications must occur through event application, with explicit precondition checking and explicit delta reporting. The implementation supports all Phase 0 event types (CreateSubject, CreateObject, CreateCap, DeleteCap, DelegateCap, ReduceRights, DestroyObject, DestroySubject, UseCap) and enforces all invariants (I1–I10) through mandatory runtime precondition checks. --- ## Scope ### **Included** - `apply_event()` API with `ApplyEventResult` containing error status and explicit `GraphDelta` - All Phase 0 event type handlers with precondition validation - `GraphDelta` structure tracking all graph mutations (created/destroyed nodes, created/deleted/modified edges) - `TestAccess` helper for unit tests to access store methods directly (test-only, not for production) - Private mutation methods on `SubjectStore`, `ObjectStore`, and `EdgeStore` (accessible only through `apply_event()` or `TestAccess`) - Comprehensive unit tests for all event types and precondition violations - Documentation in [docs/model.md](docs/model.md) covering preconditions, postconditions, and event application discipline ### **Explicitly excluded** - Temporal semantics (creation time, generations) — reserved for Phase 1+ - Revocation mechanisms — reserved for later phases - Event log persistence or replay — out of scope for Phase 0 - Optimizations (batching, incremental validation) — premature for initial implementation --- ## Design intent The event application API establishes **mutation discipline as a first-class architectural constraint**. By making store mutation methods private and accessible only through `apply_event()`, the design enforces that: 1. **All graph changes are explicit and traceable:** Every mutation produces a `GraphDelta` describing exactly what changed 2. **Preconditions are mandatory:** Invalid operations fail visibly with specific error codes rather than corrupting state 3. **The graph is always valid:** Atomic event application means either all postconditions hold or the graph remains unchanged 4. **Tests remain practical:** `TestAccess` allows direct store manipulation in unit tests while preventing accidental misuse in production This design supports the broader AES goal of deterministic, reproducible simulation by ensuring that the authority graph evolves only through well-defined event sequences. --- ## Phase discipline **Phase 0: Event Application API** This PR completes the Phase 0 authority model by implementing the event application layer. It builds on prior Phase 0 work: - Subject/Object node storage (#46) - Capability edge representation (#47) - Graph indexing and integrity (#48) - Event taxonomy (#49) **Phase stability:** The semantics of Phase 0 events are now fixed. Later phases may introduce new event types but must not retroactively alter the meaning of Phase 0 events. **Reserved fields:** The `GraphDelta` structure does not include temporal information (creation time, generation counters). These fields are reserved for Phase 1+ when the temporal model is defined. --- ## Verification - [x] Tests pass (316 test cases covering all event types and preconditions) - [x] All Phase 0 event types implemented with precondition validation - [x] Store mutation methods made private and accessible only through `apply_event()` or `TestAccess` - [x] GraphDelta correctly reports all mutations - [x] Model documentation updated with preconditions, postconditions, and discipline - [x] No regressions in existing functionality (all existing tests updated to use `TestAccess`) --- ## Notes **Review focus:** - Precondition encoding in [core/src/apply_event.cpp](core/src/apply_event.cpp) — ensure all invariants (I1-I10) are enforced - `TestAccess` usage pattern — confirm it's only used in tests, never in production code - GraphDelta completeness — verify all mutations are recorded **Implementation notes:** - Some helper methods (e.g., `edges_from_subject()`) were made public to support precondition checking without exposing mutation methods - Debug labels remain accessible in test builds to support debugging and test readability - UseCap event is a no-op in Phase 0 (temporal effects reserved for later phases) **Known limitations:** - Error messages are minimal (just error codes). Rich error context (e.g., "subject S1 not found") could be added later. - Performance is not optimized. Precondition checks may be redundant with internal store validation. **Follow-up work:** - Integration with simulation engine (event dispatch, ID allocation) - Event log serialization/deserialization (if persistence is needed) - Phase 1 temporal extensions
erikinkinen added this to the Phase 0 milestone 2026-02-17 06:45:50 +01:00
Implement apply_event(graph, event) (#8)
All checks were successful
ci / smoke (push) Successful in 9s
clang-format / check-format (push) Successful in 8s
markdownlint / markdown-lint (push) Successful in 15s
68f0d01034
Encode precondition checks (#8)
All checks were successful
ci / smoke (push) Successful in 9s
clang-format / check-format (push) Successful in 8s
markdownlint / markdown-lint (push) Successful in 11s
0454a18d24
Return explicit graph delta (#8)
All checks were successful
ci / smoke (push) Successful in 8s
clang-format / check-format (push) Successful in 8s
markdownlint / markdown-lint (push) Successful in 10s
fea57b4c8e
Enforce “no mutation outside apply_event” (#8)
All checks were successful
ci / smoke (push) Successful in 8s
clang-format / check-format (push) Successful in 8s
markdownlint / markdown-lint (push) Successful in 10s
ci / smoke (pull_request) Successful in 8s
clang-format / check-format (pull_request) Successful in 7s
markdownlint / markdown-lint (pull_request) Successful in 11s
db0241fb1d
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!50
No description provided.