Ownership Boundaries¶
flowchart TD
system["Monitoring system"] --> aggregate["Aggregate boundary"]
system --> policy["Policy boundary"]
system --> projection["Projection boundary"]
system --> runtime["Runtime boundary"]
system --> persistence["Persistence boundary"]
system --> public["Public surface boundary"]
flowchart TD
change["Consider a change"] --> owner["Identify the owning boundary"]
owner --> reject["Reject cross-boundary leakage"]
reject --> redesign["Redesign or push the change outward"]
Use this guide when the capstone technically makes sense but you still need one page that states who owns what, who only derives views, and what kinds of changes should be rejected or pushed outward.
Aggregate boundary¶
Owner:
MonitoringPolicyinsrc/service_monitoring/model.py
This boundary owns:
- lifecycle transitions for monitoring rules
- cross-rule authority during registration, activation, retirement, and incident creation
- domain events that describe authoritative changes
This boundary does not own:
- persistence mechanics
- projection updates as the source of truth
- runtime coordination or adapter I/O
Reject or redesign when:
- runtime code starts bypassing aggregate methods to mutate rule state
- projections begin deciding domain truth
- policy variation is encoded as condition ladders inside the aggregate instead of a stable seam
Policy boundary¶
Owners:
- evaluation strategy types in
src/service_monitoring/policies.py
This boundary owns:
- evaluation variation
- threshold, consecutive-breach, and rate-of-change logic
- replaceable behavior that should not widen the aggregate's authority
This boundary does not own:
- repository access
- orchestration timing
- domain lifecycle authority
Reject or redesign when:
- a policy object starts reaching into storage or runtime concerns
- evaluation variation becomes coupled to transport, logging, or adapter details
- the aggregate stops being able to explain the contract around a policy seam
Projection boundary¶
Owners:
- read-model and projection surfaces such as
read_models.pyandprojections.py
This boundary owns:
- derived views of active rules and incident history
- post-event read models meant to support inspection and reporting
This boundary does not own:
- authoritative lifecycle state
- rule registration or activation decisions
- mutation of aggregate truth
Reject or redesign when:
- a projection becomes a hidden write model
- downstream reporting surfaces begin deciding what the domain means
- projections can drift silently because no event or test route would notice first
Runtime boundary¶
Owners:
runtime.py,application.py, and the demo and CLI entry surfaces
This boundary owns:
- coordination across sources, sinks, repositories, and the aggregate
- scenario execution, command entrypoints, and learner-facing review output
- retries, scheduling, or surrounding operational concerns that belong outside the model
This boundary does not own:
- domain truth
- storage semantics disguised as orchestration
- projection authority
Reject or redesign when:
- the runtime becomes the place where invariants are enforced first
- operational convenience starts bypassing aggregate methods
- a learner can no longer tell whether behavior belongs to the model or to orchestration
Persistence boundary¶
Owners:
- repository and unit-of-work surfaces
This boundary owns:
- translating authoritative state into storage or in-memory retention
- commit and rollback semantics
- keeping persistence replaceable without flattening the domain
This boundary does not own:
- domain rules
- public API governance
- direct scenario narration
Reject or redesign when:
- repository code starts constructing semantically invalid aggregates
- storage shape becomes the apparent domain model
- commit or rollback logic leaks into the aggregate
Public surface boundary¶
Owners:
application.py, public CLI routes, and the published learner-facing bundles
This boundary owns:
- what another human reader or consumer is meant to rely on
- narrow extension and inspection seams that can actually be documented and defended
This boundary does not own:
- deep internal imports as accidental extension points
- hidden behavior that cannot be reached through public guides or proof routes
Reject or redesign when:
- a deep internal module becomes the de facto public API
- extension pressure requires violating aggregate or runtime ownership
- the published bundles no longer reflect the surface you claim is stable
Best companion files¶
ARCHITECTURE.mdPACKAGE_GUIDE.mdPROJECTION_GUIDE.mdPUBLIC_API_GUIDE.mdEXTENSION_GUIDE.md