= core-context

== purpose

Assembles the context pack (a structured, layered representation of session state) that is fed to an LLM at inference time. Defines the layer hierarchy (L0–L4), budgeting and compression strategies for fitting context within token limits, and tracks context build lifecycle as event-sourced state.

== responsibilities

* Defining the context layer hierarchy (L0 live execution, L1 stage-local, L2 compressed session memory, L3 durable project memory, L4 archival history)
* Building `ContextPack` instances from raw entries using `ContextPackBuilder`
* Compressing context entries to fit within a `TokenBudget` using strategy-specific algorithms
* Selecting entries for inference (decision point) from the context pack
* Tracking which context packs have been built for a session
* Defining steering notes — user-provided guidance attached to a session

== non-responsibilities

* Does not produce the entries that go into the context — those are produced by other modules
* Does not interact with inference providers — the built `ContextPack` is consumed by `:core:inference`
* Does not define the content of individual layers — only the structure and assembly
* Does not manage cross-session or durable project memory directly — only models L3/L4 as layer slots

== key types

=== ContextPack
* **kind**: data class
* **purpose**: A complete, layered context ready for inference. Includes budget tracking and compression metadata.
* **fields**: `id`, `sessionId`, `stageId`, `layers` (map of layer to entries), `budgetUsed`, `budgetLimit`, `compressionMetadata`

=== ContextLayer
* **kind**: enum
* **purpose**: Hierarchy level for context entries, from most immediate (L0) to most archival (L4).
* **variants**: `L0` (live execution), `L1` (stage-local), `L2` (compressed session memory), `L3` (durable project memory), `L4` (archival history)

=== ContextEntry
* **kind**: data class
* **purpose**: A single piece of context with source tracking.
* **fields**: `id`, `layer`, `content`, `sourceType`, `sourceId`, `tokenEstimate`

=== TokenBudget
* **kind**: data class
* **purpose**: Tracks token limit and consumption.
* **fields**: `limit`, `used`

=== CompressionMetadata
* **kind**: data class
* **purpose**: Records what compression strategies were applied, which layers were truncated, and how many entries were dropped.

=== ContextState
* **kind**: data class
* **purpose**: Event-sourced projection of context build status.
* **fields**: `builtPackIds`, `buildingInProgress`, `interrupted`

=== ContextPackBuilder
* **kind**: interface
* **purpose**: Builds a `ContextPack` from a list of entries within a budget.

=== DefaultContextPackBuilder
* **kind**: class
* **purpose**: Partitions entries into pinned (never dropped: steering notes, event history) and compressible. Applies per-source-type compression strategies and assembles the final pack.

=== DecisionPointBuilder
* **kind**: interface
* **purpose**: Selects which layers to send to the LLM for inference.

=== DefaultDecisionPointBuilder
* **kind**: class
* **purpose**: Returns only L0 and L1 entries — these are the only layers suitable for direct inference.

=== ContextCompressor
* **kind**: interface
* **purpose**: Compresses a list of entries to fit within a budget using a given strategy.

=== DefaultContextCompressor
* **kind**: class
* **purpose**: Implements five strategies: SteeringNote (retain all), EventHistory (retain all), Artifact (keep latest per sourceId), ToolLog (deduplicate content), Conversation (keep last N entries). Applies layer-based eviction (L2 before L1).

=== CompressionStrategy
* **kind**: sealed interface
* **purpose**: Declares how entries of a given source type should be compressed.
* **variants**:
  * `ToolLog` — deduplicate identical content, drop oldest when over budget
  * `Conversation(keepLast)` — retain last N entries verbatim
  * `Artifact` — keep most recent entry per sourceId
  * `SteeringNote` — always retained verbatim, never dropped
  * `EventHistory` — always retained, already compressed facts

=== SteeringNote
* **kind**: data class
* **purpose**: User-provided guidance for a session, optionally scoped to a stage.

=== ContextReducer / DefaultContextReducer
* **kind**: interface / class
* **purpose**: Transforms `ContextState` given stored events. Handles `ContextBuildingStartedEvent`, `ContextPackBuiltEvent`, `ContextBuildingFailedEvent`, `ContextBuildingInterruptedEvent`.

=== ContextProjector
* **kind**: class
* **purpose**: Wraps `ContextReducer` as a `Projection<ContextState>`.

=== DefaultContextRepository
* **kind**: class
* **purpose**: Rebuilds `ContextState` for a session via `EventReplayer`.

== event flow

*inbound:*
* `ContextBuildingStartedEvent` → sets `buildingInProgress = true`
* `ContextPackBuiltEvent` → appends pack ID, resets building flags
* `ContextBuildingFailedEvent` → resets building flags
* `ContextBuildingInterruptedEvent` → sets `interrupted = true`, resets building in progress

*outbound:*
* None. This module is purely a projection — events are emitted by the orchestrator.

== integration points

* `:core:events` — `StoredEvent`, context lifecycle event types, `ContextPackId`, `ContextEntryId`, `SessionId`, `StageId`
* `:core:artifacts` — (listed in build.gradle but not directly referenced in source files; likely for future artifact-based context entries)
* `:core:sessions` — `Projection`, `EventReplayer`

== invariants

* Steering notes (`sourceType == "steeringNote"`) and event history (`sourceType == "eventHistory"`) are never dropped during compression
* L0, L3, and L4 entries are never evicted by `DefaultContextCompressor` — only L2 (first), then L1
* `CompressionMetadata` is non-authoritative — it records what happened during compression but original events remain the source of truth
* `ContextPack` is built per-stage per-session; it is not persisted independently — it is disposable and rebuilt on demand

== PlantUML diagram

[plantuml, core-context, "png"]
----
include::../../diagrams/core-context.puml[]
----




== known issues

* Build.gradle lists `:core:artifacts` as a dependency, but no artifact types are directly imported in the main source. May be a forward-looking dependency or unused.

== open questions

* Should `ContextPackBuilder` and `DecisionPointBuilder` be merged? They are always used together in the context assembly flow.
* L3 (durable project memory) and L4 (archival history) are defined in the layer enum but no code populates them — are they placeholders for future epics?
