# API
This library owns the pure typed meaning of session-control journal records. It performs no filesystem, journal append/replacement, synchronization, locking, timeout, retry, or other I/O.
```rust
pub enum ControlUpdate {
Lifecycle(SessionRecord),
Command(SessionCommand),
StopRequest(SessionStopRequest),
}
impl ControlUpdate {
pub fn projected(self) -> ControlUpdate;
}
pub struct ControlProjection {
pub lifecycle: Option<SessionRecord>,
pub commands: std::collections::BTreeMap<String, SessionCommand>,
pub stop_requests: std::collections::BTreeMap<String, SessionStopRequest>,
}
pub fn encode_update(
update: ControlUpdate,
) -> anyhow::Result<(ControlUpdate, &'static str, serde_json::Value)>;
pub fn project_records(
records: &[kcode_session_control_journal::Record],
) -> ControlProjection;
pub fn compact_records(
records: &[kcode_session_control_journal::Record],
) -> anyhow::Result<Option<Vec<kcode_session_control_journal::Record>>>;
```
`ControlUpdate::projected` removes non-control lifecycle state and leaves command and stop updates unchanged. `encode_update` applies that projection, serializes the typed value, and returns the projected update, its stable sideband kind, and its JSON value. The kinds are `session_lifecycle`, `session_command`, and `session_stop`.
`project_records` selects the latest lifecycle record, plus the latest valid command and stop value per ID. A malformed latest lifecycle record yields no lifecycle rather than falling back to an older value. Malformed command and stop values are ignored.
`compact_records` selects the latest lifecycle record, latest record per command and stop ID, and every unknown-kind record, preserving original survivor order. Later records with the same typed ID replace earlier records. A command or stop record without a string `id` returns an error. Lifecycle state is projected when a `state` value is present, including in an otherwise malformed lifecycle record. The operation returns `Ok(None)` when neither projection nor survivor selection changes any record; otherwise it returns `Ok(Some(records))`. It does not persist the result.
```rust
pub struct SessionRecord {
pub id: String,
pub phase: String,
pub started_at: String,
pub updated_at: String,
pub state: serde_json::Value,
pub provenance_id: Option<String>,
pub version: i64,
pub last_user_message_at: Option<String>,
pub ended_at: Option<String>,
pub ingress_failure_count: i64,
pub ingress_failures: serde_json::Value,
pub ingress_next_attempt_at: Option<String>,
pub summary: bool,
}
pub struct SessionCommand {
pub id: String,
pub conversation_id: String,
pub sequence: i64,
pub kind: String,
pub payload: serde_json::Value,
pub status: String,
pub cancel_requested: bool,
pub outcome: Option<serde_json::Value>,
pub created_at: String,
pub processing_started_at: Option<String>,
pub completed_at: Option<String>,
pub idempotency_id: String,
}
pub struct SessionStopRequest {
pub id: String,
pub session_id: String,
pub scope: String,
pub status: String,
pub outcome: Option<serde_json::Value>,
pub requested_at: String,
pub completed_at: Option<String>,
pub idempotency_id: String,
}
```
The record fields are caller-editable values. This library does not enforce lifecycle phases, command status transitions, stop scopes, optimistic versions, or idempotency policy. `SessionRecord` uses its displayed snake-case JSON field names; command and stop records use camel-case JSON field names. A false `summary` is omitted during serialization and defaults to false during deserialization.
Lifecycle projection recursively retains only these keys when present:
`format`, `version`, `stateVersion`, `sessionId`, `sessionType`, `sourceSessionType`, `channel`, `freeTime`, `selfTimeIntent`, `orchestration`, `provenanceId`, `rustLibSessionId`, `rootNodeIds`, `referenceRootNodeIds`, `startedAt`, `pendingTurn`, `pendingExternalEventId`, `roundsUsed`, `providerAffinity`, `nextThreadResetReason`, `completed`, `sessionObjectId`, `commitReceipt`, `commitAuthor`, `providerModel`, `kwebPlan`, `startIdempotencyId`, `ingressSource`, `firstUserMessage`, `boxCount`, `eventCount`, `chatendMetadata`, `sessionStatus`, `launchContextNodeIds`, `launchProvenance`, and `historyIngress`.
`historyIngress` is filtered recursively by the same allowlist. A null `commitReceipt` is removed at every recursive level. All other listed values, including optional opaque `launchContextNodeIds` and `launchProvenance`, are retained unchanged. Unlisted keys are removed.
All operations accept any record count and JSON value size that fit available memory; there are no library-added caps. For `N` records and `I` distinct command and stop IDs, projection and compaction perform one ordered scan with `O(N log I)` map work. Encoding and lifecycle filtering are linear in the visited JSON object structure. Projection retains up to `I` typed values. Compaction clones retained records and can require `O(N)` additional record storage. The caller owns journal ordering, admission, concurrency, persistence, and any resource limits required by its environment.