epic-12: after epic audit and init commit

This commit is contained in:
2026-05-16 11:42:00 +04:00
commit c77277af0b
461 changed files with 28958 additions and 0 deletions
@@ -0,0 +1,234 @@
---
name: "Core Approvals Submodule Spec"
description: "Specification for :core:approvals tiered approval system"
depth: 2
links: ["../index.md", "../decisions/adr-0004-approval-tier-design.md", "./core-validation-submodule-spec.md"]
---
# :core:approvals module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:approvals` defines the risk-aware approval system that decides whether operations beyond preconfigured thresholds may proceed.
It is the authoritative subsystem for:
* approval tier semantics
* approval mode enforcement
* approval request/decision lifecycle
* escalation rules
* steering injection
* approval history (immutable audit trail)
Approvals are the primary humanintheloop safety mechanism. They are not a simple popup; they gate execution by checking tiers and policies, and they record every decision.
---
# 2. responsibilities
`:core:approvals` owns:
* approval tier definitions (T0T4)
* approval mode configurations (prompt, auto, deny, yolo)
* approval event contracts
* escalation rules
* sessionscope approval grants
* steeringaware approval injection
* approval part of validation pipeline integration
* immutable approval ledger
---
# 3. non-responsibilities
`:core:approvals` MUST NOT own:
* the validation pipeline itself (that's `:core:validation`)
* artifact generation
* transition execution
* policy enforcement (policies may be evaluated, but the engine is separate)
* UI rendering of approval prompts
* persistence implementations
---
# 4. architectural role
`:core:approvals` acts as:
* human/system checkpoint authority
* risk boundary for mutable operations
* audit trail for sensitive decisions
All tool or stage escalation that exceeds the configured autoapproved tier passes through this subsystem.
---
# 5. design principles
## 5.1 tiers enforce risk boundaries
Every tool and operation has a declared tier. By default, only T0 and T1 may be autoapproved. Higher tiers require explicit human approval unless the session is in an elevated mode.
## 5.2 approvals are immutable
An approval decision, once recorded, cannot be changed. Corrections require a new decision that supersedes the previous one within the audit log.
## 5.3 steering is firstclass
Approval decisions may include steering instructions: natural language suggestions injected into the next context pack. This bridges human guidance into the execution loop without breaking replay.
## 5.4 replay-safe
Approval events are replayed deterministically. In replay, approval decisions are reapplied from history, not rerequested from the user.
---
# 6. tier model
```
T0 inference only (read model outputs)
T1 readonly tool access
T2 reversible mutation (e.g., git commit, file create)
T3 external/network access
T4 destructive (e.g., rm -rf, database drop)
```
Each tool, stage, or even artifact category may declare a tier requirement.
---
# 7. approval modes
Mode can be changed per session or per approval gate.
* **prompt** always ask user
* **auto** approve automatically if tier ≤ configured threshold
* **deny** automatically reject
* **yolo** bypass all checks (logging only); for sandboxed experimentation
---
# 8. approval request lifecycle
1. An artifact or tool invocation triggers an `ApprovalRequired` event from the validation pipeline.
2. `:core:approvals` evaluates:
- tier vs. current session mode
- any explicit denials
- sessionscoped grants (e.g., “autoapprove all T2 for this session”)
3. If decision can be made automatically, emit `ApprovalGranted/Automatic`.
4. If human input needed, pause orchestration and emit `ApprovalPending`.
5. User supplies decision (approve/reject/steer). Decision is recorded, orchestration resumes.
---
# 9. steering injection
When user approves with a steering message, the approval event carries that text. The context processor later picks it up and injects it as additional instruction for the next stage, with proper delimiting (e.g., “User guidance: …”).
---
# 10. event ownership
`:core:approvals` owns:
* `ApprovalRequired`
* `ApprovalPending`
* `ApprovalGranted` / `ApprovalGrantedAuto`
* `ApprovalRejected`
* `ApprovalEscalated`
* `ApprovalSessionGrantAdded`
* `ApprovalModeChanged`
All carry causation back to the originating artifact or tool event.
---
# 11. consumed events
Consumes:
* `ArtifactValidated` (when approval layer decides escalation)
* `ToolAboutToExecute` (for tool-level approvals)
* `UserInput` (approval decision)
---
# 12. invariants
* Approval history is append-only.
* No operation above its tier may execute without a matching `ApprovalGranted` event.
* Session grants are ephemeral and must be replayreconstructed from events.
* Steering text is preserved verbatim.
---
# 13. replay semantics
During replay, `:core:approvals` replays decisions from the event log. No user interaction occurs. If a decision is missing (e.g., corrupted log), replay fails explicitly.
---
# 14. threading/concurrency
Approval handling is sequential within a session. The orchestration coroutine suspends until a decision is available. Timeout mechanisms exist for approval expiration.
---
# 15. failure semantics
If an approval request times out or the user refuses, the corresponding artifact or tool execution is rejected, and a failure event is emitted. The session may transition to a recovery or failed state according to transition rules.
---
# 16. observable requirements
Must expose:
* approval request frequency
* approval response latency
* rejection rates per tier
* active session grants
---
# 17. security boundaries
Approvals are a trust boundary. Untrusted plugins cannot circumvent approval checks. The approval engine runs inside core with no external dependencies.
---
# 18. extension model
Plugins cannot alter tier definitions but may add custom escalation logic or additional constraints (e.g., “never approve network access after 10pm”).
---
# 19. forbidden patterns
* silent escalation without event
* mutable approval records
* approval decisions that bypass tier checks
* replay that reprompts the user
* granting broad permissions without session scope
---
# 20. testing requirements
* tier enforcement across modes
* autoapprove/deny logic
* steering injection hygiene
* replay of approval sequences
* timeout and cancellation behavior
---
# 21. philosophy
Approvals translate bounded autonomy into practice. They are the harnesss way of saying “you may go this far without me, but not further”, with a clear audit trail and the ability to inject human judgment exactly where its needed.
@@ -0,0 +1,489 @@
---
name: "Core Artifacts Submodule Spec"
description: "Specification for :core:artifacts structured outputs with lineage"
depth: 2
links: ["../index.md", "./core-module-spec.md", "./core-context-submodule-spec.md"]
---
# :core:artifacts module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:artifacts` defines the canonical structured output model for correx.
It is the authoritative subsystem for:
* artifact contracts
* artifact lifecycle semantics
* schema ownership
* lineage tracking
* artifact immutability
* artifact validation boundaries
* artifact serialization contracts
Artifacts represent:
* structured outputs produced during orchestration
* machine-validated workflow state contributions
* replayable execution products
Artifacts are the primary mechanism through which models contribute semantic work to the harness.
---
# 2. responsibilities
`:core:artifacts` owns:
* base artifact contracts
* artifact schema contracts
* artifact lifecycle semantics
* lineage semantics
* artifact identity semantics
* immutability guarantees
* serialization contracts
* artifact metadata contracts
* artifact relationship semantics
* artifact provenance semantics
---
# 3. non-responsibilities
`:core:artifacts` MUST NOT own:
* artifact persistence implementations
* semantic validation logic
* transition evaluation
* orchestration progression
* model execution
* tool execution
* UI rendering
* websocket serialization transport
Artifact legality is validated externally.
---
# 4. architectural role
`:core:artifacts` acts as:
* structured semantic output authority
* workflow data contract authority
* lineage authority
* execution provenance authority
All meaningful workflow progression MUST operate on artifacts rather than freeform model text.
---
# 5. design principles
## 5.1 artifacts are immutable
Artifacts MUST NEVER be mutated after creation.
Corrections MUST produce:
* new artifacts
* superseding relationships
* compensating events
---
## 5.2 artifacts are structured
Artifacts MUST conform to explicit schemas.
Freeform orchestration state is forbidden.
---
## 5.3 artifacts are replayable
Artifacts MUST remain:
* serializable
* deterministic
* reconstructable
* versioned
Replay MUST reproduce identical artifact history.
---
## 5.4 artifacts are proposals
Artifacts represent proposed semantic state.
Artifacts gain workflow authority only after:
* validation
* approvals
* transition acceptance
---
# 6. artifact model
## base artifact contract
```kotlin id="zskldn"
sealed interface Artifact {
val id: ArtifactId
val sessionId: SessionId
val stageId: StageId
val schemaVersion: Int
val createdAt: Instant
val lineage: ArtifactLineage
val metadata: ArtifactMetadata
}
```
---
# 7. artifact identity semantics
Artifact identifiers MUST be:
* globally unique
* immutable
* replay-stable
Artifact identity MUST NOT depend on:
* provider internals
* runtime memory
* mutable projections
---
# 8. artifact lifecycle model
Mandatory lifecycle phases:
```text id="oztzsu"
CREATED
VALIDATING
VALIDATED
REJECTED
SUPERSEDED
ARCHIVED
```
Lifecycle changes MUST emit events.
---
# 9. schema model
Artifacts MUST conform to explicit schemas.
Schemas MAY be:
* built-in
* config-defined
* plugin-defined
Recommended schema model:
* kotlinx.serialization
* pydantic-compatible external definitions
* explicit versioning
---
## schema guarantees
Schemas MUST support:
* deterministic validation
* version compatibility
* explicit field typing
* replay-safe deserialization
---
# 10. artifact lineage model
All artifacts MUST support lineage tracking.
Lineage MUST include:
* parent artifacts
* originating events
* originating stage
* tool receipts
* validation history
* approval history
---
## lineage guarantees
Lineage MUST remain:
* immutable
* replayable
* traceable
---
# 11. provenance model
Artifacts MUST record provenance metadata for:
* originating model
* provider
* stage runtime
* generation config
* tool interactions
* context pack references
This metadata exists for:
* replay
* diagnostics
* auditability
* evaluation
---
# 12. artifact relationships
Supported relationships:
```text id="1wz8ny"
PARENT
CHILD
SUPERSEDES
DERIVED_FROM
VALIDATED_BY
APPROVED_BY
GENERATED_FROM
```
Relationships MUST remain append-only.
---
# 13. serialization requirements
Artifacts MUST support:
* deterministic serialization
* schema versioning
* replay-safe decoding
* portable encoding
Recommended:
* kotlinx.serialization
Forbidden:
* provider-specific formats
* reflection-dependent serialization
* mutable serialization contracts
---
# 14. validation boundaries
`:core:artifacts` defines structure only.
Validation responsibilities belong to:
* `:core:validation`
* `:core:approvals`
* `:core:policies`
Artifacts themselves MUST remain validation-agnostic.
---
# 15. artifact categories
Recommended top-level categories:
```text id="k93gb0"
ReasoningArtifact
PatchArtifact
PlanArtifact
SummaryArtifact
CommandArtifact
AnalysisArtifact
ToolResultArtifact
ContextArtifact
ApprovalArtifact
RecoveryArtifact
```
Additional categories MAY be plugin-defined.
---
# 16. artifact storage expectations
Artifacts MUST remain:
* append-only
* immutable
* replay-safe
Storage implementations belong to infrastructure modules.
---
# 17. replay guarantees
Replay MUST reconstruct:
* artifact history
* artifact lineage
* artifact relationships
* supersession chains
* validation history
Replay MUST NOT require:
* original models
* provider access
* live tool execution
---
# 18. supersession semantics
Corrections MUST occur through:
* replacement artifacts
* supersession relationships
Historical artifacts MUST remain preserved.
Example:
```text id="vgzfh7"
Artifact B
SUPERSEDES
Artifact A
```
Mutation-in-place is forbidden.
---
# 19. observability requirements
`:core:artifacts` MUST expose metadata hooks for:
* lineage tracing
* artifact provenance
* supersession chains
* validation outcomes
* approval history
* schema evolution
* replay diagnostics
---
# 20. security boundaries
Artifacts are considered:
* untrusted semantic proposals
Artifacts MUST NOT gain execution authority directly.
Execution authority requires:
* validation
* policy approval
* orchestration approval
Sensitive payload handling MUST support:
* redaction
* isolation
* audit-safe serialization
---
# 21. extension model
Extensions MAY define:
* custom schemas
* custom artifact categories
* custom metadata
* custom lineage relationships
Extensions MUST NOT:
* mutate historical artifacts
* bypass validation
* bypass replay guarantees
* introduce hidden mutable state
---
# 22. forbidden patterns
Forbidden:
* mutable artifacts
* freeform orchestration state
* schema-less execution artifacts
* artifact-owned workflow state
* hidden lineage mutation
* in-place correction
* replay-dependent artifact interpretation
---
# 23. persistence expectations
Persistence implementations MUST support:
* immutable storage
* lineage reconstruction
* version-safe retrieval
* replay-safe deserialization
Persistence belongs to infrastructure modules.
---
# 24. testing requirements
`:core:artifacts` MUST support deterministic testing for:
* schema validation
* serialization consistency
* lineage reconstruction
* supersession handling
* replay reconstruction
* version compatibility
---
# 25. philosophy summary
`:core:artifacts` exists to transform probabilistic model outputs into structured replayable workflow objects.
Reliability emerges from:
* immutable schemas
* explicit lineage
* deterministic serialization
* append-only history
* validation boundaries
not from trusting raw model text directly.
+251
View File
@@ -0,0 +1,251 @@
---
name: "Core Context Submodule Spec"
description: "Specification for :core:context context synthesis and compression"
depth: 2
links: ["../index.md", "../architecture/context-layers.md", "./core-artifacts-submodule-spec.md"]
---
# :core:context module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:context` is responsible for synthesizing minimal, relevant, tokenefficient context packs that are fed to models before each inference call.
It owns:
* context layer architecture (L0L4)
* compression strategies
* token budgeting
* relevance ranking
* deduplication
* context pack building
* context event ownership
Context synthesis is the primary defense against context window overflow and degradation of model performance due to irrelevant history.
---
# 2. responsibilities
`:core:context` owns:
* context layer definitions
* compression strategy contracts
* token budget model
* relevance ranking algorithms
* deduplication logic
* context pack structure
* rebuild triggers
* context synthesis events
* router context management (separate L2 for router)
* sessionlevel context cap enforcement
---
# 3. non-responsibilities
`:core:context` MUST NOT own:
* longterm memory persistence (thats infrastructure)
* model execution
* tool execution
* approval decisions
* transition logic
* archiving policy (archival layer L4 is defined, but storage mechanics are external)
---
# 4. architectural role
`:core:context` acts as:
* the information bottleneck
* a stateless synthesizer that transforms raw event history into a compressed, actionable model prompt
* the owner of what the model “sees”
---
# 5. design principles
## 5.1 context is synthesized, not accumulated
Raw events are never fed to models. They are filtered, ranked, compressed, and bounded.
## 5.2 layers separate freshness from history
* L0 live execution stream (current stage inputs/outputs)
* L1 stagelocal context (artifacts from the current stage)
* L2 compressed session memory (summaries of completed stages)
* L3 durable project memory (key decisions, architecture, persistent facts)
* L4 archival history (full event log, used only for deep replay)
Only L0L2 are included in the context pack for a typical inference.
## 5.3 token budgets are enforced
Every context pack has a hard token limit. The budget is configurable per model and per stage. The context processor must trim aggressively.
## 5.4 router context is separate
The router has its own L2 memory, rebuilt from summaries after each stage. It never sees raw execution context unless needed for a specific user query.
---
# 6. context pack model
```kotlin
data class ContextPack(
val layers: Map<ContextLayer, List<ContextEntry>>,
val budgetUsed: Int,
val budgetLimit: Int,
val compressionMetadata: CompressionMetadata
)
```
Context entries are structured records pointing to artifact excerpts, summaries, policy hints, and steering notes.
---
# 7. synthesis pipeline
Pipeline steps (executed in order):
1. Retrieve relevant events from projection store (cursorbased).
2. Deduplicate remove repeated identical tool outputs, duplicate artifact versions.
3. Rank score entries by relevance to current stage goals (may use a quick heuristic or a tiny model).
4. Compress apply layerspecific strategies (summarize tool logs, keep only latest valid artifact, semantic conversation compression).
5. Inject policies insert active constraints relevant to the stage.
6. Tokenize and trim to budget.
7. Assemble final `ContextPack`.
---
# 8. compression strategies
Configdriven, per data type:
| data type | default strategy |
|-----------|------------------|
| tool output | summarize (extract errors, key values) |
| artifacts | latest valid only |
| events | deduplicate + temporal decay |
| conversation | semantic summary (L2 only) |
| approvals | retain all (small) |
| steering notes | retain verbatim |
Semantic compression may use a dedicated small local model, but it must be deterministicenough (same model, same prompt → same compressed output). The harness treats compression as an inference call of its own, recorded as a `CompressionEvent`.
---
# 9. token budget model
Budgets are defined per model and per stage, with enforcement:
* hard limit on total context pack tokens
* reservation for system prompt/policies
* dynamic overflow: if compression cannot fit within limit, oldest L2 entries are dropped first.
---
# 10. sessionlevel token cap
A sessionwide total token cap exists for L2 memory. When exceeded, older L2 entries are merged into L3 project memory, and L2 is truncated. This prevents silent memory bloat in long sessions.
---
# 11. event ownership
`:core:context` emits:
* `ContextBuildingStarted`
* `ContextPackBuilt`
* `CompressionApplied`
* `LayerTruncated`
These events carry causation from the preceding stage schedule event.
---
# 12. consumed events
Consumes:
* `StageScheduled` (trigger)
* All domain events that feed the projection needed for context retrieval.
---
# 13. replay semantics
During replay, context compressions are either replayed from compression events (if available) or reexecuted deterministically. For inferenceskipping replay, context packs are still built to validate budget logic but not fed to models.
---
# 14. threading/concurrency
Context building is a CPUbound operation that runs within the orchestration coroutine. It must be cancellable and should not block the event loop for extreme histories (use batching/sampling if needed).
---
# 15. failure semantics
If context building fails (e.g., compression model unavailable), the stage cannot proceed. Event `ContextBuildingFailed` is emitted, and the transition engine may retry or fail the session.
---
# 16. observability requirements
* token usage per stage
* compression effectiveness (e.g., compression ratio)
* L2 memory size over time
* context building duration
* deduplication hit rate
---
# 17. security boundaries
Context packs may contain sensitive data. The module must support redaction/secret scrubbing before delivery to models (plugin point). No model should see raw secrets.
---
# 18. extension model
Extensions may provide:
* custom rankers
* custom compressors
* additional context layers (if needed)
All extensions must produce valid `ContextEntry` types and respect the token budget.
---
# 19. forbidden patterns
* raw event accumulation in context pack
* unbounded context growth
* mutable context state (context packs are ephemeral, built per stage)
* crosssession context leaking
* hidden injection of unauthorized data
---
# 20. testing requirements
* determinism of deduction/ranking (given fixed input)
* token budget compliance
* compression quality metrics
* replay of context building
* router context isolation
---
# 21. philosophy
The context processor is the harnesss memory manager. It ensures that models never drown in their own history, and that every inference receives a sharp, purposeful slice of the past—nothing more, nothing less.
+566
View File
@@ -0,0 +1,566 @@
---
name: "Core Events Submodule Spec"
description: "Specification for :core:events event sourcing backbone"
depth: 2
links: ["../index.md", "../architecture/event-model.md", "./core-module-spec.md"]
---
# :core:events module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:events` defines the canonical event sourcing model for correx.
It is the authoritative subsystem for:
* immutable event contracts
* event lifecycle semantics
* causation/correlation tracking
* replay semantics
* projection contracts
* snapshot contracts
* event ordering guarantees
`:core:events` is the foundational source of truth for all system state.
All persistent workflow state MUST originate from events defined by this module.
---
# 2. responsibilities
`:core:events` owns:
* base event contracts
* event category contracts
* event metadata semantics
* event ordering semantics
* replay contracts
* projection contracts
* snapshot contracts
* event versioning semantics
* causation/correlation semantics
* append-only guarantees
* event serialization contracts
---
# 3. non-responsibilities
`:core:events` MUST NOT own:
* database implementations
* sqlite/postgres access
* projection persistence
* websocket/event streaming transport
* telemetry exporters
* UI event rendering
* provider-specific events
* business workflow orchestration
Implementations belong to infrastructure modules.
---
# 4. architectural role
`:core:events` acts as:
* canonical state authority
* replay foundation
* audit foundation
* projection foundation
* execution history authority
All mutable runtime state MUST ultimately derive from events.
---
# 5. design principles
## 5.1 events are truth
Events are the only authoritative persistent state.
Everything else is derived.
---
## 5.2 append-only model
Events are immutable.
Existing events MUST NEVER be:
* modified
* deleted
* reordered
* rewritten
Corrections occur through compensating events only.
---
## 5.3 replay-first architecture
All workflows MUST be reconstructable exclusively from:
* event streams
* snapshots
* configs
Replayability is a mandatory architectural guarantee.
---
## 5.4 deterministic reconstruction
Given:
* identical events
* identical configs
* identical replay strategy
projection rebuild MUST produce identical results.
---
# 6. event model
## base event contract
All events MUST contain:
```kotlin
sealed interface Event {
val id: EventId
val sessionId: SessionId
val timestamp: Instant
val type: EventType
val payload: EventPayload
val causationId: EventId?
val correlationId: CorrelationId?
val sequence: Long
val version: Int
}
```
---
## field semantics
### id
Globally unique immutable identifier.
---
### sessionId
Logical execution session ownership.
---
### timestamp
Creation time only.
Never mutated during replay.
---
### causationId
Direct parent event.
Represents:
"what caused this event to exist?"
---
### correlationId
Shared execution lineage identifier.
Used for:
* tracing
* replay grouping
* workflow reconstruction
* observability
---
### sequence
Strict append ordering within session scope.
Sequence gaps are forbidden.
---
### version
Schema evolution support.
---
# 7. event categories
Mandatory top-level categories:
```text
DomainEvents
LifecycleEvents
InferenceEvents
ToolEvents
ValidationEvents
ApprovalEvents
CompressionEvents
TransitionEvents
ProjectionEvents
SystemEvents
```
---
# 8. canonical event flow
Minimum execution flow:
```text
UserInputReceived
SessionCreated
StageScheduled
ContextBuilt
InferenceStarted
ArtifactProduced
ArtifactValidated
ApprovalRequested
TransitionExecuted
SessionCompleted
```
Real workflows may branch but MUST remain replayable.
---
# 9. ordering guarantees
## required guarantees
Within a session:
* ordering MUST be deterministic
* append order MUST be preserved
* replay order MUST match append order
---
## forbidden behavior
Forbidden:
* out-of-order mutation
* concurrent sequence conflicts
* nondeterministic replay ordering
---
# 10. event ownership rules
Every event MUST have exactly one:
* producer
* ownership boundary
Example:
```text
ToolEvents
owned by :core:tools
ApprovalEvents
owned by :core:approvals
```
Cross-module event mutation is forbidden.
---
# 11. replay model
Supported replay modes:
* full replay
* replay from cursor
* replay until condition
* deterministic simulation
* projection-only replay
* inference-skipping replay
Replay MUST function without:
* live models
* live tools
* provider access
---
# 12. projection model
## projection definition
Projection:
deterministic derived state built from events.
---
## projection guarantees
Projections MUST be:
* disposable
* rebuildable
* deterministic
* side-effect free
---
## projection restrictions
Projections MUST NOT:
* mutate events
* emit side effects
* perform orchestration
* own workflow authority
---
# 13. snapshot model
Snapshots exist only to optimize replay.
Snapshots are:
* optimization artifacts
* rebuildable
* disposable
Snapshots MUST NEVER become authoritative state.
---
## snapshot guarantees
Snapshots MUST contain:
* originating event sequence
* projection version
* snapshot timestamp
---
# 14. versioning model
Event schemas MUST support forward evolution.
Rules:
* old events remain replayable
* incompatible mutations forbidden
* event meaning immutable after release
Schema migrations MUST occur through:
* versioned deserialization
* compensating events
* projection migration logic
Never through historical mutation.
---
# 15. serialization requirements
Events MUST support deterministic serialization.
Requirements:
* stable field ordering
* explicit schema versions
* portable encoding
* replay-safe decoding
Recommended:
* kotlinx.serialization
Forbidden:
* reflection-dependent serialization
* provider-specific encoding
---
# 16. concurrency model
Event append semantics MUST remain:
* atomic
* ordered
* idempotent
Concurrent appends MUST NOT create:
* duplicate sequence numbers
* replay ambiguity
* partial visibility
---
# 17. idempotency guarantees
Replay MUST be idempotent.
Reapplying identical events MUST produce:
* identical projections
* identical state transitions
Duplicate event processing MUST be detectable.
---
# 18. observability requirements
`:core:events` MUST expose tracing metadata for:
* causation chains
* correlation chains
* replay timelines
* projection rebuild timing
* event append latency
* snapshot timing
---
# 19. failure semantics
Event append failures MUST:
* fail atomically
* emit structured failures
* never partially commit
Projection rebuild failures MUST:
* preserve original events
* isolate projection corruption
* support rebuild retries
---
# 20. security boundaries
Events are trusted as historical records but not as semantic truth.
Semantic correctness MUST still be validated externally.
Sensitive payload handling MUST support:
* redaction policies
* secret isolation
* audit-safe serialization
---
# 21. extension model
Extensions MAY:
* introduce new event types
* introduce projections
* introduce replay consumers
Extensions MUST NOT:
* mutate existing events
* rewrite history
* bypass append ordering
* bypass replay semantics
---
# 22. forbidden patterns
Forbidden:
* mutable events
* in-place updates
* hidden side-channel state
* projection-owned truth
* replay-dependent side effects
* event deletion
* unordered append semantics
* timestamp-based replay ordering
---
# 23. persistence expectations
Persistence implementations MUST support:
* append-only writes
* ordered reads
* replay scans
* snapshot storage
* cursor-based replay
* optimistic concurrency
Storage engines are infrastructure concerns.
---
# 24. testing requirements
`:core:events` MUST support deterministic testing for:
* replay correctness
* ordering guarantees
* idempotency
* snapshot rebuild
* projection rebuild
* sequence integrity
* version compatibility
---
# 25. philosophy summary
`:core:events` exists to externalize all workflow state into immutable observable history.
Reliability emerges from:
* append-only history
* deterministic replay
* rebuildable projections
* explicit causality
* immutable execution lineage
not from mutable runtime memory.
@@ -0,0 +1,234 @@
---
name: "Core Inference Submodule Spec"
description: "Specification for :core:inference model provider abstraction"
depth: 2
links: ["../index.md", "./core-module-spec.md", "./core-context-submodule-spec.md"]
---
# :core:inference module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:inference` abstracts model execution behind a stable contract. It owns:
* inference provider interfaces
* inference request/response model
* model capability model
* model lifecycle management contracts
* GPU residency hints
* inference isolation
* retry/detokenization handling
Models are treated as stateless compute engines; this module ensures they are interchangeable, locally or remotely, without affecting orchestration.
---
# 2. responsibilities
`:core:inference` owns:
* `InferenceProvider` contract
* model capability definitions
* inference request schema (context pack + generation config)
* inference response schema (raw text + finish reason)
* provider registry interface
* model scheduling (which model for which stage)
* inference event definitions
* token accounting (prompt/completion tokens)
* timeout and cancellation contracts
---
# 3. non-responsibilities
`:core:inference` MUST NOT own:
* actual provider implementations (llama.cpp, ollama, etc.)
* context pack construction
* artifact parsing (that's orchestration/validation)
* model weight management (infrastructure handles storage)
* UI rendering of inference progress
---
# 4. architectural role
`:core:inference` acts as:
* the only point of contact for models
* the provider abstraction layer
* the enforcer of concurrency limits and GPU residency policies
---
# 5. design principles
## 5.1 models are stateless
Every inference call receives a full context pack. No state is retained on the model side between calls.
## 5.2 capabilitybased routing
Stages request capabilities (e.g., coding, tool_calling). The inference module selects the best available model from the registry, considering local GPU budget and fallback providers.
## 5.3 deterministicenough configuration
Inference parameters (temperature, top_p, etc.) are part of the stage config and must be reproduced identically for replay.
## 5.4 isolation
Inference runs in a separate coroutine with strict time limits. Models may be forcibly unloaded after a swap timeout.
---
# 6. model provider contract
```kotlin
interface InferenceProvider {
val name: String
suspend fun infer(request: InferenceRequest): InferenceResponse
suspend fun healthCheck(): ProviderHealth
fun capabilities(): Set<ModelCapability>
fun tokenize(text: String): List<Token>
}
```
---
# 7. inference request/response
```kotlin
data class InferenceRequest(
val contextPack: ContextPack,
val generationConfig: GenerationConfig,
val stageId: StageId,
val sessionId: SessionId
)
data class InferenceResponse(
val text: String,
val finishReason: FinishReason,
val tokensUsed: TokenUsage,
val latencyMs: Long
)
```
---
# 8. capability negotiation
Models declare capabilities with optional scores. The inference module uses a configurable strategy (e.g., highest score first, then fallback to remote if local below threshold) to select the model for a stage.
---
# 9. model lifecycle management
Inference module defines contracts for:
* loading a model (provider specific)
* unloading
* health checks
* swap scheduling (ephemeral, dynamic, persistent residency modes)
It does not implement these; it exposes interfaces implemented by infrastructure providers.
---
# 10. inference events
`:core:inference` emits:
* `InferenceStarted`
* `InferenceCompleted`
* `InferenceFailed`
* `InferenceTimeout`
* `ModelLoaded` / `ModelUnloaded`
All carry causation back to the stage scheduling event.
---
# 11. consumed events
Consumes:
* `StageScheduled` (to know which capability to invoke)
* `ContextPackBuilt` (to receive the actual pack)
* system resource events (GPU availability)
---
# 12. invariants
* Every inference call is idempotent from the harness perspective (same context → same response… eventually, but replay uses recorded artifacts).
* Token usage always tracked.
* No crosssession model state leakage.
---
# 13. replay semantics
During replay, inference can be skipped. Recorded `InferenceCompleted` events containing the artifact text are used instead. If inference is replayed (e.g., for evaluation), the same config and context pack must be used.
---
# 14. threading/concurrency
Inference calls are suspending and may run on a dedicated dispatcher. Concurrency is limited by model-level `max_parallel_sessions`; the inference module enforces this limit using semaphores.
---
# 15. failure semantics
Inference failures (timeout, model crash) emit `InferenceFailed` with a typed reason. The transition engine may then retry with a different provider or fail the stage.
---
# 16. observable requirements
* inference latency
* token consumption
* model residency time
* fallback event count
* GPU utilization (via provider)
---
# 17. security boundaries
Models are untrusted. Inference runs sandboxed: no filesystem access, no network access unless explicitly configured. Artifacts are treated as untrusted text.
---
# 18. extension model
New providers are added by implementing `InferenceProvider` and registering with the provider registry. Plugins cannot alter the core inference contract.
---
# 19. forbidden patterns
* direct model state reuse between calls
* capability bypass (using a model directly without capability check)
* hidden fallback that circumvents audit
* inference without context pack
---
# 20. testing requirements
* mock provider for deterministic tests
* capability routing logic
* cancel/timeout behavior
* replay with recorded artifacts
---
# 21. philosophy
Inference is a utility, not a partner. This module treats language models like an accelerator card: it submits a wellformed job, waits for a result, and never assumes the result is anything but a candidate.
+521
View File
@@ -0,0 +1,521 @@
---
name: "Core Module Spec"
description: "Overall :core module responsibilities and boundaries"
depth: 2
links: ["../index.md", "../architecture/overview.md", "./core-events-submodule-spec.md", "./core-sessions-submodule-spec.md"]
---
# :core module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core` is the deterministic orchestration and domain foundation of correx.
It defines:
* domain contracts
* orchestration primitives
* workflow semantics
* event ownership rules
* validation boundaries
* execution abstractions
* replay guarantees
`:core` contains the canonical execution model of the system.
It is the authoritative source of:
* workflow state semantics
* event semantics
* transition semantics
* artifact semantics
* approval semantics
`:core` MUST remain infrastructure-independent.
---
# 2. responsibilities
`:core` owns:
* orchestration contracts
* event contracts
* transition semantics
* session lifecycle semantics
* artifact contracts
* validation contracts
* context synthesis contracts
* approval semantics
* policy contracts
* tool contracts
* inference contracts
* replay semantics
* deterministic workflow behavior
`:core` defines:
* what may happen
* what is valid
* what transitions are legal
* what state means
---
# 3. non-responsibilities
`:core` MUST NOT own:
* persistence implementation
* sqlite/postgres integration
* websocket transport
* REST APIs
* shell execution
* filesystem access
* model process management
* llama.cpp integration
* provider-specific logic
* frontend/UI concerns
* CLI rendering
* telemetry exporters
`:core` defines contracts only.
Implementations belong to infrastructure modules.
---
# 4. architectural role
`:core` acts as:
* deterministic orchestration kernel
* domain model authority
* replay authority
* execution policy authority
All external systems interact with correx through contracts defined by `:core`.
---
# 5. submodules
## mandatory submodules
```text
:core:events
:core:context
:core:validation
:core:transitions
:core:orchestration
:core:artifacts
:core:sessions
:core:approvals
:core:policies
:core:tools
:core:inference
```
---
# 6. architectural principles
## 6.1 event sourcing mandatory
All state MUST be reconstructable from immutable events.
Projections are disposable derived state.
Events are the sole source of truth.
---
## 6.2 append-only semantics
The following are immutable:
* events
* artifacts
* approvals
* tool receipts
* summaries
Mutation occurs only through new events.
---
## 6.3 deterministic orchestration
`:core` MUST behave deterministically given:
* identical event stream
* identical config
* identical transition graph
Inference nondeterminism MUST remain externalized.
---
## 6.4 infrastructure independence
`:core` MUST NOT depend on:
* infrastructure modules
* interfaces modules
* apps modules
Dependency direction is strictly inward.
---
## 6.5 explicit state ownership
Every state transition MUST have:
* originating event
* causation id
* correlation id
Hidden mutable state is forbidden.
---
# 7. dependency rules
## allowed dependencies
`:core:*` modules MAY depend on:
* kotlin stdlib
* kotlinx.coroutines
* kotlinx.serialization
* other lower-level `:core:*` modules
---
## forbidden dependencies
`:core:*` modules MUST NEVER depend on:
* `:infrastructure:*`
* `:interfaces:*`
* `:apps:*`
* frontend code
* provider implementations
---
# 8. threading and concurrency model
`:core` uses structured concurrency exclusively.
Requirements:
* coroutine-based execution
* explicit cancellation propagation
* bounded execution scopes
* deterministic lifecycle ownership
Forbidden:
* global mutable state
* unmanaged thread pools
* detached background tasks
---
# 9. state model
## authoritative state
Authoritative state exists only as:
* immutable event streams
---
## derived state
Derived state exists as:
* projections
* summaries
* context packs
* metrics
Derived state MUST be rebuildable.
---
# 10. replay guarantees
`:core` MUST support:
* full replay
* replay from cursor
* inference-skipping replay
* deterministic projection rebuild
* transition tracing
Replay MUST NOT require:
* original model availability
* original tool availability
* external provider access
---
# 11. orchestration guarantees
`:core` guarantees:
* explicit workflow transitions
* bounded retries
* approval-aware execution
* validation-first progression
* deterministic transition evaluation
`:core` MUST reject:
* invalid transitions
* invalid artifacts
* policy violations
* unauthorized escalations
---
# 12. validation guarantees
No artifact may advance workflow state unless:
1. routing validation passes
2. schema validation passes
3. semantic validation passes
4. approval validation passes
Validation failures MUST emit events.
---
# 13. approval guarantees
All risky operations MUST be classified by approval tier.
Approval semantics MUST remain:
* explicit
* replayable
* auditable
* append-only
Approval bypasses MUST emit events.
---
# 14. tool guarantees
`:core` defines:
* tool contracts
* capability contracts
* receipt contracts
* isolation expectations
Tools MUST NOT mutate workflow state directly.
All side effects MUST be represented through receipts and events.
---
# 15. inference guarantees
Models are treated as:
* stateless semantic processors
Models MUST NOT own:
* memory
* permissions
* workflow state
* transition authority
Inference outputs are proposals only.
Harness validation determines legality.
---
# 16. context guarantees
Raw context accumulation is forbidden.
All context MUST be:
* filtered
* deduplicated
* compressed
* relevance-ranked
* token-budgeted
Context packs are ephemeral synthesized views.
---
# 17. observability requirements
`:core` MUST expose structured observability hooks for:
* event tracing
* transition tracing
* replay diagnostics
* token accounting
* stage timing
* approval history
* artifact lineage
---
# 18. security boundaries
`:core` defines trust boundaries for:
* models
* tools
* providers
* plugins
* user steering
* remote execution
`:core` assumes:
* models may hallucinate
* tools may fail
* providers may become unavailable
* plugins may be untrusted
Validation and approvals are mandatory security boundaries.
---
# 19. extension model
`:core` MUST support extension through contracts/interfaces only.
Extension points include:
* validators
* compressors
* providers
* tools
* transition conditions
* policies
Extensions MUST NOT bypass:
* validation pipeline
* approval system
* event sourcing
---
# 20. persistence expectations
`:core` defines persistence contracts but not implementations.
Persistence layer MUST support:
* append-only event storage
* snapshot storage
* projection rebuild
* artifact storage
* approval audit history
---
# 21. lifecycle expectations
All runtime components MUST have explicit lifecycle ownership.
Required lifecycle semantics:
* initialization
* active execution
* cancellation
* teardown
* recovery
Zombie execution is forbidden.
---
# 22. failure semantics
Failures MUST be explicit and evented.
No silent recovery allowed.
Required failure categories:
* validation failure
* transition failure
* inference failure
* tool failure
* policy failure
* provider failure
* replay failure
All failures MUST emit structured events.
---
# 23. plugin boundaries
Plugins interact with correx only through:
* stable contracts
* DTOs
* extension interfaces
Plugins MUST NOT:
* mutate internal state directly
* bypass orchestration
* access projections unsafely
---
# 24. anti-goals
`:core` intentionally avoids:
* hidden memory
* implicit orchestration
* unrestricted autonomy
* mutable projections
* provider-specific logic
* agent personalities
* recursive uncontrolled execution
* conversationally-driven state mutation
---
# 25. philosophy summary
`:core` exists to provide deterministic orchestration around probabilistic cognition.
Reliability emerges from:
* event sourcing
* validation
* replayability
* constrained execution
* explicit approvals
* synthesized context
not from trusting model reasoning itself.
@@ -0,0 +1,227 @@
---
name: "Core Orchestration Submodule Spec"
description: "Specification for :core:orchestration execution kernel"
depth: 2
links: ["../index.md", "./core-module-spec.md", "./core-sessions-submodule-spec.md", "./core-transitions-submodule-spec.md"]
---
# :core:orchestration module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:orchestration` is the execution kernel of correx. It coordinates the entire workflow lifecycle by composing:
* session management
* stage scheduling
* context building
* inference execution
* validation
* approvals
* transitions
It is the "brain" that wires together all other core modules and ensures work progresses deterministically according to the configured graph.
---
# 2. responsibilities
`:core:orchestration` owns:
* workflow execution loop
* stage scheduling and sequencing
* orchestration state machine (separate from session state)
* retry coordination
* cancellation propagation
* concurrency control within a session
* orchestration event aggregation (orchestration-level events)
* replay orchestration (decides which components to re-invoke)
* servicelevel observability (the "big picture" metrics)
---
# 3. non-responsibilities
`:core:orchestration` MUST NOT own:
* domain logic (thats in events, transitions, validation, etc.)
* persistence
* inference provider implementation
* user interaction (router handles that)
* plugin execution
* UI updates
It coordinates; it does not implement lowlevel mechanics.
---
# 4. architectural role
`:core:orchestration` acts as:
* the toplevel orchestrator
* the only component that directly calls other core modules in a defined sequence
* the guardian of workflow integrity
It is the closest thing to a “main loop” of the harness.
---
# 5. design principles
## 5.1 stateless orchestration
The orchestrator itself holds no persistent state. All state lives in events and projections. The orchestrator loads current projection at start, executes steps, emits events, and exits.
## 5.2 deterministic coordination
Given the same initial projection and the same event history, the orchestration sequence (which stage to run next, when to retry) is fully deterministic.
## 5.3 explicit composition
Every step (context, inference, validation, transition) is called explicitly and synchronously within a coroutine scope. No hidden sideeffects.
## 5.4 cancellation ownership
The orchestrator owns the cancellation token for a session and ensures it propagates to all child jobs (inference, tools, etc.).
---
# 6. execution loop
```
while session is active:
determine next stage (from transition engine + current projection)
build context pack
schedule inference
wait for artifact
validate artifact
if approval needed: wait for decision
evaluate transition rules
emit TransitionExecuted event
update projection
```
Each iteration is a transaction in the event stream.
---
# 7. orchestration events
`:core:orchestration` emits highlevel events:
* `WorkflowStarted`
* `WorkflowCompleted`
* `WorkflowFailed`
* `OrchestrationPaused`
* `OrchestrationResumed`
* `RetryAttempted`
It does not own domain events but links them via correlation.
---
# 8. consumed events
Orchestration listens to all domain events through a projection, but specifically reacts to:
* `SessionCreated` (trigger start)
* `UserInput` (steering, approvals)
* `ArtifactValidated` / `ArtifactRejected`
* `ApprovalGranted`
* system events for health/timeouts
---
# 9. state model
The orchestration loop tracks an ephemeral `OrchestrationState` (inmemory during execution) that holds:
* current stage
* retry count
* pause reason
* pending approval flag
This state is never persisted directly; it is rebuilt from events.
---
# 10. retry coordination
Orchestration evaluates retry policies after failures (validation, inference). It may:
* reexecute the same stage with adjusted context (failure reason injected)
* branch to a recovery stage
* terminate
Retries are bounded and emit `RetryAttempted`.
---
# 11. replay mode support
During replay, the orchestrator runs the same loop but can skip inference (using recorded artifacts) or skip validation (trusting recorded outcomes). It follows a replay strategy configured per session.
---
# 12. concurrency model
All orchestration for a session runs in a single coroutine scope. No parallel stage execution (v1). Concurrency is limited to inference and tool calls within a stage being asynchronous but serialized from the orchestrators viewpoint.
---
# 13. failure semantics
If orchestration encounters an unrecoverable error, it emits `WorkflowFailed` and terminates the session safely. Partial state is preserved via events.
---
# 14. observable requirements
Must expose:
* workflow duration
* stagelevel timing
* retry frequency
* bottlenecks (idle time in approval)
* cancellation triggers
---
# 15. security boundaries
Orchestration does not directly access external resources. It receives validated data only. It enforces no security beyond coordination: all gates are handled by validation/approvals/policies.
---
# 16. extension model
Orchestration logic is not pluggable in v1 (to preserve determinism), but hook points for custom stage scheduling strategies may be added later.
---
# 17. forbidden patterns
* direct manipulation of projections
* skipping validation steps
* hidden retry loops
* mutable orchestration state persisted outside events
---
# 18. testing requirements
* full workflow simulation with mock inference
* retry path coverage
* replay consistency
* cancellation during each phase
---
# 19. philosophy
Orchestration is the conductor, not the musician. It knows the score, calls in each section at the right time, and ensures the performance follows the plan—even when the musicians occasionally improvise.
@@ -0,0 +1,491 @@
---
name: "Core Sessions Submodule Spec"
description: "Specification for :core:sessions lifecycle FSM and projection"
depth: 2
links: ["../index.md", "../architecture/replay-model.md", "./core-module-spec.md"]
---
# :core:sessions module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:sessions` defines the canonical execution lifecycle model for correx sessions.
It is the authoritative subsystem for:
* session lifecycle semantics
* execution ownership
* runtime state transitions
* cancellation semantics
* recovery semantics
* session-scoped coordination
* execution isolation boundaries
A session represents:
* one bounded orchestration lifecycle
* one authoritative execution timeline
* one isolated event stream scope
---
# 2. responsibilities
`:core:sessions` owns:
* session lifecycle FSM
* session identity contracts
* session state semantics
* execution ownership rules
* cancellation semantics
* pause/resume semantics
* recovery semantics
* session projections
* session-scoped concurrency guarantees
* session termination semantics
---
# 3. non-responsibilities
`:core:sessions` MUST NOT own:
* orchestration execution logic
* transition evaluation
* persistence implementations
* websocket session management
* user authentication
* provider lifecycle management
* model execution
* UI session rendering
Implementations belong to other modules.
---
# 4. architectural role
`:core:sessions` acts as:
* execution boundary authority
* lifecycle authority
* session isolation authority
* runtime ownership authority
All workflow execution MUST occur inside a valid session lifecycle.
---
# 5. design principles
## 5.1 sessions are bounded
Sessions are finite execution scopes.
Sessions MUST:
* begin explicitly
* terminate explicitly
* remain replayable
* remain isolated
Infinite implicit execution is forbidden.
---
## 5.2 sessions own orchestration scope
Everything occurring during workflow execution MUST belong to:
* exactly one session
Cross-session mutation is forbidden.
---
## 5.3 lifecycle is deterministic
Session state transitions MUST be:
* explicit
* evented
* replayable
* validated
Hidden lifecycle mutation is forbidden.
---
## 5.4 cancellation is first-class
Cancellation MUST propagate deterministically through:
* orchestration
* inference
* tools
* transitions
* approvals
Zombie execution is forbidden.
---
# 6. session model
## base session contract
```kotlin
sealed interface Session {
val id: SessionId
val state: SessionState
val createdAt: Instant
val updatedAt: Instant
val correlationId: CorrelationId
}
```
---
# 7. session states
Mandatory lifecycle states:
```text
CREATED
INITIALIZING
ACTIVE
PAUSED
AWAITING_APPROVAL
CANCELLING
CANCELLED
FAILED
COMPLETED
RECOVERING
```
---
# 8. lifecycle guarantees
## required guarantees
Sessions MUST:
* have exactly one active lifecycle state
* emit events for all state transitions
* terminate deterministically
* preserve replay consistency
---
## forbidden behavior
Forbidden:
* silent state mutation
* implicit recovery
* orphaned execution
* detached execution scopes
* state mutation without events
---
# 9. lifecycle transition rules
Example lifecycle graph:
```text
CREATED
INITIALIZING
ACTIVE
├──→ PAUSED
├──→ AWAITING_APPROVAL
├──→ FAILED
├──→ CANCELLING
└──→ COMPLETED
```
Recovery paths MUST be explicit.
Invalid transitions MUST fail validation.
---
# 10. session ownership model
A session owns:
* execution scope
* orchestration scope
* workflow scope
* event stream scope
* approval scope
* context synthesis scope
Everything executed within a session MUST reference:
* sessionId
* correlationId
---
# 11. session projections
Mandatory projections:
```text
SessionStateProjection
SessionLifecycleProjection
SessionExecutionProjection
SessionApprovalProjection
SessionFailureProjection
```
Projections MUST remain:
* rebuildable
* disposable
* deterministic
---
# 12. concurrency model
## required guarantees
Within a session:
* execution ordering MUST remain deterministic
* cancellation MUST propagate transitively
* lifecycle transitions MUST be atomic
---
## session isolation
Sessions MUST remain isolated from each other.
Forbidden:
* shared mutable orchestration state
* cross-session context mutation
* shared execution ownership
---
# 13. cancellation semantics
Cancellation MUST:
* emit events
* propagate recursively
* terminate child execution scopes
* interrupt pending orchestration safely
Cancellation MUST support:
* graceful cancellation
* forced termination
* timeout escalation
---
# 14. pause/resume semantics
Paused sessions MUST:
* preserve replay integrity
* preserve event ordering
* suspend active execution safely
Resuming MUST emit explicit lifecycle events.
---
# 15. approval suspension semantics
When awaiting approval:
* execution MUST suspend
* transition scheduling MUST pause
* inference MUST stop
Only approval decisions may resume execution.
---
# 16. recovery semantics
Recovery MUST be event-driven.
Recovery MAY occur after:
* crash
* restart
* provider failure
* infrastructure interruption
Recovery MUST NOT require:
* original process state
* in-memory orchestration state
* active model residency
---
# 17. replay guarantees
Session replay MUST support:
* lifecycle reconstruction
* transition reconstruction
* cancellation reconstruction
* approval reconstruction
* failure reconstruction
Replay MUST deterministically reproduce:
* session state
* projections
* orchestration decisions
---
# 18. observability requirements
`:core:sessions` MUST expose telemetry hooks for:
* lifecycle transitions
* session duration
* cancellation propagation
* failure timelines
* replay reconstruction
* approval waiting time
* execution suspension timing
---
# 19. failure semantics
Session failures MUST:
* emit structured failure events
* preserve historical integrity
* preserve replayability
* preserve partial execution history
Failures MUST NOT:
* corrupt event streams
* bypass lifecycle transitions
* silently terminate execution
---
# 20. timeout semantics
Sessions MAY define:
* execution timeout
* inactivity timeout
* approval timeout
* recovery timeout
Timeout expiration MUST emit lifecycle events.
---
# 21. security boundaries
Sessions define execution isolation boundaries.
Session isolation MUST apply to:
* orchestration
* context synthesis
* approvals
* tools
* inference execution
Unauthorized cross-session access is forbidden.
---
# 22. extension model
Extensions MAY:
* define additional session metadata
* define custom projections
* define lifecycle observers
Extensions MUST NOT:
* bypass lifecycle validation
* mutate session state directly
* bypass cancellation semantics
* introduce hidden execution state
---
# 23. forbidden patterns
Forbidden:
* global orchestration state
* implicit session resurrection
* detached execution
* hidden lifecycle mutation
* orphaned child scopes
* mutable session history
* replay-dependent lifecycle behavior
---
# 24. persistence expectations
Persistence implementations MUST support:
* durable session lifecycle history
* replay-safe reconstruction
* snapshot-compatible recovery
* deterministic session rebuild
Persistence mechanics belong to infrastructure modules.
---
# 25. testing requirements
`:core:sessions` MUST support deterministic testing for:
* lifecycle transitions
* cancellation propagation
* pause/resume behavior
* timeout handling
* recovery flows
* replay reconstruction
* concurrency isolation
---
# 26. philosophy summary
`:core:sessions` exists to provide deterministic execution boundaries around orchestration workflows.
Reliability emerges from:
* explicit lifecycle ownership
* bounded execution
* deterministic cancellation
* replayable state transitions
* isolated execution scopes
not from long-lived mutable runtime state.
+235
View File
@@ -0,0 +1,235 @@
---
name: "Core Tools Submodule Spec"
description: "Specification for :core:tools external sideeffect execution"
depth: 2
links: ["../index.md", "./core-module-spec.md", "./core-approvals-submodule-spec.md"]
---
# :core:tools module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:tools` defines the contract and orchestration model for external sideeffect execution (shell, git, filesystem, network, etc.).
It owns:
* tool contracts
* tool execution lifecycle
* tool receipt model
* sandboxing expectations
* tool capability declarations
* toolrelated events
All external side effects required by a stage are channelled through this module, ensuring they are auditable, replayable, and governed by approval tiers.
---
# 2. responsibilities
`:core:tools` owns:
* `Tool` interface
* tool execution lifecycle (prepare, execute, validate, receipt)
* tool receipt schema (structured output of tool runs)
* tool registration/capability mapping
* sandboxing contracts
* tool event definitions
* deterministic replay guidance for tools
---
# 3. non-responsibilities
`:core:tools` MUST NOT own:
* actual tool implementations (these live in infrastructure or plugins)
* approval decisions (uses `:core:approvals`)
* artifact generation directly (tools produce receipts, which may be wrapped into artifacts later)
* UI for tool output viewing
* persistence of receipts (events store does that)
---
# 4. architectural role
`:core:tools` acts as:
* the gatekeeper for all sideeffects
* the translator between model intentions ("run pytest") and validated, isolated executions
* the owner of the tool audit trail
---
# 5. design principles
## 5.1 structured receipts only
Tool outputs must be typed. Raw text output is not allowed as a firstclass result. A receipt must include structured data (e.g., exit code, affected files, key metrics) in addition to a summary.
## 5.2 tier assignment
Every tool call has a tier (T0T4). The tool itself declares its tier, and the approval subsystem checks it.
## 5.3 sideeffects are externalized
Tools mutate the outside world. The harness records what was done (receipt) and what was requested (invocation event), but never implies the world state changed exactly as intended—semantic validation compares receipts against expected changes later.
## 5.4 replay with simulated tools
During replay, actual tool execution is skipped; recorded receipts and events are replayed. For full replay or testing, deterministic mock tools can be used.
---
# 6. tool contract
```kotlin
interface Tool {
val name: String
val tier: ApprovalTier
val requiredCapabilities: Set<ToolCapability>
suspend fun execute(request: ToolRequest): ToolReceipt
fun validateRequest(request: ToolRequest): ValidationResult
}
```
---
# 7. tool invocation lifecycle
1. Model output (or stage config) contains a proposed `ToolInvocation`.
2. `:core:tools` validates the invocation against the tool contract.
3. Approval check (tier vs. session mode).
4. If approved, tool executes in a sandboxed environment.
5. A `ToolReceipt` is produced.
6. Receipt is wrapped into a `ToolResultArtifact` for further validation.
---
# 8. tool receipt model
```kotlin
data class ToolReceipt(
val invocationId: String,
val toolName: String,
val exitCode: Int,
val outputSummary: String,
val structuredOutput: JsonObject?,
val affectedEntities: List<String>,
val durationMs: Long,
val tier: ApprovalTier,
val timestamp: Instant
)
```
Structured output is mandatory for common tools but may be minimal for userdefined tools.
---
# 9. event ownership
`:core:tools` emits:
* `ToolInvocationRequested`
* `ToolExecutionStarted`
* `ToolExecutionCompleted` (with receipt)
* `ToolExecutionFailed`
* `ToolExecutionRejected`
All linked to the parent artifact or stage event.
---
# 10. consumed events
Consumes:
* `ArtifactProduced` (may contain suggested tool calls)
* `ApprovalGranted` (for tool execution)
* `StageScheduled` (for predefined tool sequences)
---
# 11. invariants
* Receipts are immutable and appendonly.
* No tool may execute without an approval event matching its tier.
* Every tool execution is scoped to a session and stage.
* Receipts are replayable without reexecution.
---
# 12. replay semantics
During replay, tool execution events are replayed from history. If a tool is marked as nondeterministic, its receipt is simply reused. Deterministic simulation may replay tool logic with the same inputs and compare receipts.
---
# 13. threading/concurrency
Tool execution is suspending and may use dedicated dispatchers. Longrunning tools are cancellable via the orchestration token. Concurrent tool executions within a stage are allowed only if explicitly configured and still serialized in event order.
---
# 14. failure semantics
Tool failures are captured in `ToolExecutionFailed` with structured error. They contribute to stage failure and trigger retry/recovery paths.
---
# 15. observable requirements
* tool invocation counts
* success/failure rates
* execution duration
* tier escalation frequencies
* sandbox escape attempts (detected by policy)
---
# 16. security boundaries
Tools are the most dangerous part of the system. The module ensures:
* sandboxing (via infrastructure) is enforced
* network access is gated by tier
* filesystem mutations are allowlistcontrolled
* secrets are never exposed to tool input
All tool requests are inspected before execution against active policies.
---
# 17. extension model
New tools can be added as plugins implementing the `Tool` interface. They register their name, tier, capabilities, and execution logic. Plugins are sandboxed as much as possible.
---
# 18. forbidden patterns
* tools that mutate event store directly
* bypassing approval tier via hidden tool code
* mutable receipts
* tools that keep persistent state across invocations
* tool output that is freeform text without structured data
---
# 19. testing requirements
* mock tool execution
* tier enforcement
* receipt validation
* replay with recorded receipts
* cancellation/timeout handling
---
# 20. philosophy
Tools are the harnesss hands, but the hands are clumsy and dangerous. This module ensures every grasp is planned, logged, and bounded, turning blunt instruments into precise, auditable actions.
@@ -0,0 +1,503 @@
---
name: "Core Transitions Submodule Spec"
description: "Specification for :core:transitions workflow graph engine"
depth: 2
links: ["../index.md", "./core-module-spec.md", "./core-validation-submodule-spec.md"]
---
# :core:transitions module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:transitions` defines the deterministic workflow transition engine for correx.
It is the authoritative subsystem for:
* workflow graph semantics
* transition evaluation
* stage progression
* condition evaluation
* retry semantics
* branching semantics
* deadlock/cycle detection
* execution progression guarantees
`:core:transitions` determines:
* what execution path is legal
* when workflow state may advance
* how failures propagate
* how retries are controlled
---
# 2. responsibilities
`:core:transitions` owns:
* workflow graph contracts
* transition contracts
* transition evaluation semantics
* condition evaluation
* retry policies
* branching semantics
* terminal state semantics
* cycle detection
* deadlock detection
* transition replay semantics
* execution progression guarantees
---
# 3. non-responsibilities
`:core:transitions` MUST NOT own:
* model inference
* tool execution
* persistence implementations
* websocket streaming
* projection persistence
* approval implementation
* context synthesis
* provider management
`:core:transitions` decides legality of progression only.
---
# 4. architectural role
`:core:transitions` acts as:
* deterministic workflow state machine
* execution progression authority
* orchestration legality validator
* workflow graph evaluator
All workflow progression MUST pass through this subsystem.
---
# 5. design principles
## 5.1 transitions are deterministic
Transition evaluation MUST depend only on:
* current projections
* current workflow config
* current event history
Transition evaluation MUST NOT depend on:
* hidden runtime state
* provider internals
* model memory
* nondeterministic mutable state
---
## 5.2 workflow graphs are explicit
All execution paths MUST be explicitly declared.
Implicit execution flow is forbidden.
---
## 5.3 transitions are validated
All transitions MUST be validated before execution.
Invalid transitions MUST fail explicitly.
---
## 5.4 retries are state-aware
Retries MUST evaluate:
* current projections
* side effects
* prior failures
* retry policies
Blind retries are forbidden.
---
# 6. workflow graph model
## graph definition
A workflow graph consists of:
```text id="3d3shm"
Stages
Transitions
Conditions
Terminal states
Retry rules
Failure rules
Approval gates
```
---
## graph guarantees
Workflow graphs MUST be:
* deterministic
* acyclic unless explicitly declared cyclic
* statically validated
* replay-safe
---
# 7. stage model
## stage definition
A stage represents:
* one bounded execution unit
* one orchestration checkpoint
* one validation boundary
Stages MUST have:
* unique identifier
* declared inputs
* declared outputs
* declared transition rules
---
# 8. transition model
## transition definition
A transition represents:
* legal movement between stages
Transitions MUST define:
* source stage
* target stage
* condition set
* retry behavior
* failure behavior
---
## transition guarantees
Transitions MUST:
* emit events
* remain replayable
* remain deterministic
* remain validation-aware
---
# 9. condition evaluation model
Conditions MAY evaluate:
* artifact fields
* projections
* approvals
* validation outcomes
* policy outcomes
* retry counters
---
## condition guarantees
Condition evaluation MUST be:
* side-effect free
* deterministic
* replay-safe
---
## forbidden condition behavior
Forbidden:
* network access
* filesystem mutation
* model execution
* tool execution
* hidden mutable state access
---
# 10. transition DSL requirements
Transition definitions MUST support:
```yaml id="6dqarf"
when:
all:
- artifact.status == "valid"
- projection.open_risks < 2
- approval.tier <= T2
```
Required features:
* boolean composition
* projection queries
* artifact queries
* retry conditions
* approval conditions
---
# 11. retry model
Retries MUST be:
* bounded
* explicit
* evented
* replayable
Retries MUST evaluate:
* prior failures
* side effects
* policy restrictions
* retry budget
---
## retry guarantees
Retries MUST NOT:
* loop infinitely
* ignore state mutation
* bypass validation
* bypass approvals
---
# 12. failure propagation model
Failures MAY:
* retry current stage
* branch to recovery stage
* escalate approval
* terminate session
* pause workflow
Failure behavior MUST be explicitly declared.
---
# 13. branching semantics
Supported branching:
* linear progression
* conditional branching
* recovery branching
* retry branching
* terminal branching
Parallel execution MAY be introduced later but is not required initially.
---
# 14. terminal state semantics
Mandatory terminal outcomes:
```text id="avqvsv"
COMPLETED
FAILED
CANCELLED
BLOCKED
```
Terminal states MUST:
* stop progression
* emit lifecycle events
* preserve replay integrity
---
# 15. cycle detection
Workflow validation MUST detect:
* unintended cycles
* unreachable stages
* dead transitions
* infinite retry loops
Explicit cycles MUST require:
* explicit configuration
* bounded termination conditions
---
# 16. deadlock detection
Transition validation MUST detect:
* approval deadlocks
* retry deadlocks
* dependency deadlocks
* unreachable terminal states
Invalid graphs MUST fail at config load time.
---
# 17. transition execution guarantees
Transitions MUST:
* occur atomically
* emit events
* preserve ordering
* preserve replay consistency
Partial transitions are forbidden.
---
# 18. replay guarantees
Transition replay MUST reproduce:
* stage progression
* branching decisions
* retry decisions
* terminal outcomes
Replay MUST NOT require:
* live models
* live tools
* provider access
---
# 19. observability requirements
`:core:transitions` MUST expose telemetry hooks for:
* transition evaluation
* branching decisions
* retry timelines
* deadlock detection
* graph traversal
* stage duration
* failure propagation
---
# 20. security boundaries
Transition logic defines execution legality boundaries.
Transitions MUST NOT:
* bypass approvals
* bypass validation
* bypass policies
* bypass session lifecycle constraints
Untrusted plugins MUST NOT gain direct transition authority.
---
# 21. extension model
Extensions MAY define:
* custom conditions
* custom retry policies
* custom transition evaluators
* custom branching strategies
Extensions MUST remain:
* deterministic
* replay-safe
* side-effect free
---
# 22. forbidden patterns
Forbidden:
* implicit workflow progression
* hidden branching
* infinite retries
* nondeterministic evaluation
* transition mutation during execution
* replay-dependent branching
* provider-dependent transition legality
---
# 23. persistence expectations
Transition persistence MUST support:
* transition history
* retry history
* branching history
* replay reconstruction
Persistence implementations belong to infrastructure modules.
---
# 24. testing requirements
`:core:transitions` MUST support deterministic testing for:
* graph validation
* condition evaluation
* retry handling
* deadlock detection
* cycle detection
* branching correctness
* replay reconstruction
---
# 25. philosophy summary
`:core:transitions` exists to constrain orchestration into deterministic legal workflow progression.
Reliability emerges from:
* explicit graphs
* deterministic conditions
* bounded retries
* validated branching
* replayable execution flow
not from trusting model autonomy.
@@ -0,0 +1,299 @@
---
name: "Core Validation Submodule Spec"
description: "Specification for :core:validation layered validation pipeline"
depth: 2
links: ["../index.md", "./core-module-spec.md", "./core-approvals-submodule-spec.md"]
---
# :core:validation module specification
version: 0.1-draft
status: foundational specification
---
# 1. purpose
`:core:validation` defines the layered validation pipeline responsible for determining whether an artifact may advance workflow state.
It is the authoritative subsystem for:
* validation pipeline composition
* routing validation semantics
* schema validation rules
* semantic validation contracts
* approval validation integration
* validation event ownership
* deterministic rejection rules
All artifacts produced by models or tools are considered untrusted proposals until they pass all configured validation layers.
---
# 2. responsibilities
`:core:validation` owns:
* validation pipeline contracts
* validation stage definitions
* validation outcome model
* layer composition rules
* validation event definitions
* rejection reason semantics
* pipeline execution ordering
* deterministic validation guarantees
* integration points for semantic validators
* validation telemetry hooks
---
# 3. non-responsibilities
`:core:validation` MUST NOT own:
* actual semantic validation implementations (those belong to configured plugins or infrastructure)
* model execution
* approval decisions
* artifact persistence
* transition execution
* context synthesis
* UI rendering
* policy enforcement (but it invokes policy checks)
---
# 4. architectural role
`:core:validation` acts as:
* hard gatekeeper for all workflow progression
* deterministic validation pipeline executor
* shared contract for all validation layers
No artifact may become active workflow state without passing through this subsystem.
---
# 5. design principles
## 5.1 validation is mandatory
Every artifact must be validated before it can trigger a transition.
## 5.2 validation is layered
Validation occurs in a fixed order:
1. routing validation
2. payload validation
3. semantic validation
4. approval validation
If any layer rejects, subsequent layers are skipped and the artifact is rejected.
## 5.3 validation is deterministic at the pipeline level
The pipeline itself (ordering, short-circuiting, rejection semantics) is deterministic and replay-safe. Individual semantic validators may be nondeterministic, but their outcomes are recorded as events, so the pipeline decision becomes deterministic from history.
## 5.4 validation failures are events
Every validation outcome (pass/reject/needs_approval) emits a corresponding event, enabling replay and audit.
---
# 6. validation pipeline model
The pipeline is defined as an ordered sequence of `ValidationStage` instances.
```
sealed interface ValidationStage {
val name: String
suspend fun evaluate(context: ValidationContext): ValidationOutcome
}
```
Pipeline execution:
1. Build `ValidationContext` containing artifact, session, policies, current projection, event stream cursor.
2. Execute each stage in order.
3. On first rejection, stop and emit `ArtifactRejected`.
4. If all pass, emit `ArtifactValidated`.
5. If any stage requires approval escalation, emit `ApprovalRequired` and pause.
---
# 7. validation context
```kotlin
data class ValidationContext(
val artifact: Artifact,
val sessionId: SessionId,
val stageId: StageId,
val currentProjection: ProjectionSnapshot,
val policies: ActivePolicies,
val eventHistory: Sequence<Event>,
val replayMode: Boolean = false
)
```
---
# 8. layer definitions
### routing validation
Checks:
* artifact belongs to a valid stage in the current workflow
* transition from current stage to subsequent stage is allowed
* required capabilities are available
* no policy routing violations
Owner: `:core:transitions` + `:core:validation` together; routing validation is implemented here but queries the transition graph.
### payload validation
Validates artifact structure against its declared schema using pydantic/kotlinx.serialization.
* field completeness
* type correctness
* version compatibility
Failure is always deterministic.
### semantic validation
Examines artifact content for consistency, safety, and correctness:
* hallucinated file paths
* contradictory claims
* unsafe commands
* policy violations beyond structure
Semantic validators are pluggable. They may use small deterministic checkers or even other models, but their outputs are captured as events and become part of the replayable judgment.
### approval validation
Checks:
* does the artifact fall under an auto-approved tier?
* does it require user approval?
* has the user already granted session-level auto-approve?
* are there escalate/deny policies?
If approval is required, the pipeline suspends and emits `ApprovalRequested`. Only after a positive approval decision does validation succeed.
---
# 9. validation outcomes
```kotlin
sealed interface ValidationOutcome {
data object Passed : ValidationOutcome
data class Rejected(val reasons: List<ValidationError>) : ValidationOutcome
data class NeedsApproval(val tier: ApprovalTier, val message: String) : ValidationOutcome
}
```
---
# 10. event ownership
`:core:validation` emits:
* `ArtifactValidationStarted`
* `ArtifactValidated`
* `ArtifactRejected`
* `ApprovalRequired` (delegated to approval subsystem, but emitted here)
All validation events carry causation from the artifact event.
---
# 11. consumed events
`:core:validation` consumes:
* `ArtifactProduced` (to start validation)
* `ApprovalDecision` (to resume from approval wait)
---
# 12. invariants
* Validation pipeline ordering is immutable for a given session config.
* Validation outcomes are idempotent given identical inputs.
* Rejected artifacts may never be used for state progression.
* All validation decisions are recorded as events before any transition.
---
# 13. replay semantics
During replay, validation outcomes are read from events, not re-executed, ensuring determinism.
If replay mode is `inference-skipping`, semantic validators are not invoked; instead, previously recorded outcomes are applied.
Validation events themselves must be replayable.
---
# 14. threading/concurrency
The validation pipeline runs within the orchestration coroutine scope of the current session. No concurrent validation of the same artifact is allowed. Pipeline execution must be cancellable.
---
# 15. failure semantics
If the pipeline itself fails (e.g., a bug in a validator), the artifact is rejected with a system error. The session enters a failed or recovery state. No partial acceptance is allowed.
---
# 16. observable requirements
Must expose:
* validation duration per layer
* rejection reasons
* approval wait times
* semantic validator invocations
* pipeline completions
---
# 17. security boundaries
Validation is a security boundary. Validators, especially semantic ones, may be untrusted plugins. They must not mutate state or access external services directly. They operate in a sandboxed context with read-only access to the artifact and a frozen projection.
---
# 18. extension model
Extensions may register custom semantic validators or even additional validation layers via the plugin system. Extensions must abide by the deterministic pipeline contract and produce `ValidationOutcome`.
---
# 19. forbidden patterns
* bypassing validation by direct artifact propagation
* validation that depends on mutable global state
* ordering inversion
* silent acceptance of invalid artifacts
* replay that re-executes approval decisions
---
# 20. testing requirements
* pipeline ordering determinism
* layer short-circuit behavior
* replay consistency (with and without inference)
* approval escalation/rejection paths
* integration with all artifact types
---
# 21. philosophy
Validation is the harnesss immune system. It does not trust any model output; it verifies structure, safety, and policy compliance before allowing state to advance. The pipeline turns probabilistic model suggestions into trustworthy workflow building blocks.
+321
View File
@@ -0,0 +1,321 @@
---
name: "Modules And Spec"
description: "Guide to module organisation and documentation standards"
depth: 2
links: ["../index.md", "./core-module-spec.md", "../design/structure.md"]
---
yes. and good catch — consistency matters here because the structure itself becomes architecture documentation.
id standardize on nested gradle modules only:
```text id="bllgjv"
:apps
:apps:cli
:apps:server
:core
:core:events
:core:context
:core:validation
:core:transitions
:core:orchestration
:core:artifacts
:core:sessions
:core:approvals
:core:policies
:core:tools
:core:inference
:infrastructure
:infrastructure:persistence
:infrastructure:providers
:infrastructure:tools
:interfaces
:interfaces:api
:interfaces:cli
```
i would add:
* `:core:orchestration`
* `:core:artifacts`
* `:core:sessions`
immediately.
because those are foundational.
without them, responsibilities leak everywhere.
and yes — writing specs/design docs module-by-module is the correct approach.
BUT:
you need two document types per module:
1. contract/spec
defines:
* responsibilities
* invariants
* boundaries
* public interfaces
* forbidden dependencies
* event ownership
* lifecycle guarantees
2. implementation/design
defines:
* concrete architecture
* classes
* flow
* persistence
* threading
* algorithms
* data structures
this separation matters a lot.
recommended documentation structure
```text id="3ktksg"
docs/
├── architecture/
│ ├── system-overview.md
│ ├── event-model.md
│ ├── replay-model.md
│ ├── context-layers.md
│ └── security-boundaries.md
├── modules/
│ ├── core-events/
│ │ ├── spec.md
│ │ └── design.md
│ │
│ ├── core-context/
│ │ ├── spec.md
│ │ └── design.md
│ │
│ ├── core-validation/
│ │ ├── spec.md
│ │ └── design.md
│ │
│ └── ...
└── decisions/
├── adr-0001-event-sourcing.md
├── adr-0002-kotlin-choice.md
└── ...
```
VERY important:
use ADRs from the beginning.
Architecture Decision Records
because you WILL forget later:
* why replay works this way
* why approvals are append-only
* why projections are disposable
* why router is isolated
future-you will otherwise rewrite old mistakes.
recommended order for specs
this order minimizes architectural drift:
1.
`:core:events`
first because:
everything depends on event semantics.
must define:
* event contracts
* causation/correlation ids
* append guarantees
* replay guarantees
* snapshotting
* versioning
2.
`:core:sessions`
defines:
* lifecycle FSM
* ownership boundaries
* session projections
* cancellation semantics
3.
`:core:transitions`
defines:
* graph execution
* rule evaluation
* deadlock/cycle handling
* retry semantics
4.
`:core:artifacts`
defines:
* artifact contracts
* lineage
* validation ownership
* immutability guarantees
5.
`:core:validation`
defines:
* layered validation pipeline
* semantic validators
* policy interaction
* approval interaction
6.
`:core:context`
probably hardest subsystem after validation.
must define:
* layering
* token budgeting
* compression contracts
* dedup semantics
* rebuild rules
7.
`:core:approvals`
must be isolated and heavily specified.
8.
`:core:orchestration`
only AFTER the primitives exist.
because orchestration composes:
* events
* transitions
* approvals
* context
* inference
9.
`:core:inference`
provider abstraction.
10.
`:core:tools`
tool contracts + receipts.
11.
infrastructure modules
ONLY after contracts stabilize.
this is important:
do NOT start with providers/tools/ui.
thats how orchestration architectures rot early.
for each module spec, define these sections
mandatory template:
```text id="n9z2y6"
1. purpose
2. responsibilities
3. non-responsibilities
4. invariants
5. public contracts
6. owned events
7. consumed events
8. state model
9. threading/concurrency model
10. failure semantics
11. replay semantics
12. persistence requirements
13. observability requirements
14. security boundaries
15. extension points
16. forbidden dependencies
17. open questions
```
this will massively reduce ambiguity later.
especially:
“non-responsibilities”
and
“forbidden dependencies”
those prevent architecture erosion.
example:
```text id="a1qoqm"
:core:context
non-responsibilities:
- model execution
- persistence
- tool execution
forbidden dependencies:
- infrastructure modules
- websocket interfaces
- provider implementations
```
that sounds bureaucratic now.
it becomes life-saving later.
one more recommendation:
define module dependency rules EARLY.
example:
```text id="2vwe0o"
core modules may depend on:
- contracts
- lower-level core modules
core modules may never depend on:
- infrastructure
- interfaces
- apps
```
enforce this automatically eventually with:
* archunit
* detekt custom rules
* dependency analysis plugin
because modular architectures silently decay otherwise.