# Epic 7 — Context Engine (Deterministic Context Synthesis Layer)

## completed deliverables

### 1. context identity

introduced `ContextPackId` and `ContextEntryId` as type aliases to `TypeId` in `core:events`.

* lives alongside other shared vocabulary types (`SessionId`, `ArtifactId`, etc.)
* available to all modules depending on `:core:events`

---

### 2. context lifecycle events

introduced five context lifecycle events in `core:events`, covering the full pack building pipeline.

events:

* `ContextBuildingStartedEvent(sessionId, stageId)`
* `ContextPackBuiltEvent(contextPackId, sessionId, stageId, budgetUsed, budgetLimit)`
* `CompressionAppliedEvent(contextPackId, layer, entriesRemoved, strategyApplied)`
* `LayerTruncatedEvent(contextPackId, layer, entriesDropped, reason)`
* `ContextBuildingFailedEvent(sessionId, stageId, reason)`

properties:

* all registered in `eventModule` polymorphic block
* emitted during pack assembly — enables deterministic replay of compression decisions
* `layer` and `strategyApplied` carried as `String` — avoids circular dependency with `core:context`

---

### 3. context layer model

introduced `ContextLayer` as a serializable enum with five distinct layers.

```text
L0  live execution      [active request, current tool output, pending approval]
L1  stage-local context [artifacts and receipts from the current stage]
L2  compressed session  [summaries of completed stages; kept under a token cap]
L3  project memory      [persistent facts, architecture decisions, key outputs]
L4  archival history    [full event log; not used for inference]
```

models receive a `ContextPack` built from L0–L2; L3 optionally injected if relevant. L4 is archival only.

---

### 4. context pack contract types

introduced the core domain types for context synthesis.

final structures:

* `ContextEntry(id, layer, content, sourceType, sourceId, tokenEstimate)` — typed reference to an event, artifact excerpt, summary, or policy snippet
* `CompressionMetadata(appliedStrategies, truncatedLayers, entriesDropped)` — audit trail of compression decisions
* `ContextPack(id, sessionId, stageId, layers, budgetUsed, budgetLimit, compressionMetadata)` — the final assembled context artifact
* `TokenBudget(limit, used)` — transient computation value with `remaining`, `consume()`, and `canFit()` helpers; intentionally not serializable

---

### 5. compression pipeline

introduced a content-type-specific, rule-based, deterministic compression pipeline. zero model calls.

final structure:

* `CompressionStrategy` (sealed interface, five content-type-specific implementations):
    * `ToolLog` — deduplicate identical content, drop oldest when over budget
    * `Conversation` — keep last N verbatim, drop oldest first under budget pressure
    * `Artifact` — keep most recent entry per `sourceId`
    * `SteeringNote` — always retained verbatim, never dropped
    * `EventHistory` — always retained; already-compressed DecisionPoints from prior stages
* `ContextCompressor` (interface)
* `DefaultContextCompressor` — applies strategies deterministically; drop order: L2 first, then L1; L0 is never dropped

key invariant:

> same input always produces the same output — compression is replay-safe

---

### 6. context state and projection

introduced the standard event-sourced pattern for context state.

final structures:

* `ContextState(builtPackIds, buildingInProgress)` — fully rebuildable from events; no external data
* `ContextReducer` (interface)
* `DefaultContextReducer` — handles `ContextBuildingStartedEvent`, `ContextPackBuiltEvent`, `ContextBuildingFailedEvent`; passes all others through unchanged
* `ContextProjector` — implements `Projection<ContextState>`; delegates to reducer

---

### 7. context pack builder

introduced a pure, side-effect-free context pack assembly pipeline.

final structures:

* `ContextPackBuilder` (interface)
* `DefaultContextPackBuilder` — compresses entries, groups by layer, tracks budget usage and truncation metadata

key invariant enforced:

> entries with `sourceType` of `"steeringNote"` or `"eventHistory"` are partitioned before compression and always retained, regardless of budget pressure

* `DecisionPointBuilder` (interface)
* `DefaultDecisionPointBuilder` — extracts only L0 and L1 entries from a pack for model inference calls

---

### 8. context repository

introduced `DefaultContextRepository` over `EventReplayer<ContextState>`, following the established repository pattern.

* single method: `getContextState(sessionId): ContextState`
* delegates to `replayer.rebuild(sessionId)`
* no business logic — thin wiring layer

---

### 9. context serialization module

introduced `contextModule: SerializersModule` in `core:context`.

* polymorphic block scaffolded for future extension
* follows the same pattern as `eventModule` and `artifactModule`

---

### 10. test coverage

implemented deterministic and projection tests covering all core behaviors.

deterministic tests (27):

* compression strategies: determinism, layer drop order, never-drop invariants (SteeringNote, EventHistory), artifact deduplication, tool log deduplication
* token budget: arithmetic correctness, immutability, exhaustion, canFit semantics
* pack builder: layer grouping, budget tracking, budget enforcement, decision point filtering, steering note retention under budget pressure, empty entries

projection tests (22):

* reducer: all three context event transitions, pass-through for unrelated events
* projector: initial state, deterministic replay

---

# final architecture after Epic 7

```text
ContextBuildingStartedEvent → ContextPackBuiltEvent (via core:events)
    ↓
ContextState (rebuilt from events via DefaultContextReducer + ContextProjector)
    ↓
DefaultContextPackBuilder (pure function)
 ├── pins: SteeringNote + EventHistory entries (never dropped)
 ├── compresses: remaining entries via DefaultContextCompressor
 │    └── strategy dispatch: ToolLog / Conversation / Artifact / SteeringNote / EventHistory
 │         └── drop order: L2 → L1 (L0 never dropped)
 └── assembles: ContextPack with layer map + budget metadata
    ↓
DefaultDecisionPointBuilder → L0 + L1 entries (sent to model for inference)
```

---

# major architectural outcomes

Epic 7 established:

* deterministic, rule-based context synthesis — zero model calls for compression
* five-layer context model separating live execution from compressed history
* content-type-specific compression strategies with never-drop invariants for critical entries
* token budget enforcement with correct layer eviction priority
* event-sourced context state fully rebuildable from the event log
* pack builder as a pure function — no IO, no side effects, replay-safe

---

# what Epic 7 intentionally does NOT include

not implemented:

* policy injection into context packs (step 5 of the pipeline — deferred)
* event retrieval and projection wiring for pack building (caller provides entries)
* L3/L4 storage and retrieval (infrastructure concern)
* router context isolation (separate L2 memory for the router — deferred)
* semantic summarization — no model-assisted compression of any kind
* cross-session context leaking prevention (enforced structurally by session scoping)
* observability hooks beyond event emission

those are explicitly deferred to later epics.

---

# final state

Correx now has:

> a deterministic, rule-based context synthesis engine that assembles token-budgeted, layered context packs from events and artifacts — with content-type-specific compression strategies, strict never-drop invariants for steering notes and decision history, and full event-sourced state tracking — ensuring models always receive minimal, relevant, reproducible context without any model calls in the compression path.
