kcode-session-log 0.2.1

Durable append-ordered session transcripts with checksummed pending objects
Documentation
# API

`kcode-session-log` stores one durable, append-ordered transcript per session.
Construct a `SessionStore` with the directory that will hold active session
files, then create or reopen sessions by their validated ID.

```rust
use kcode_session_log::{Role, SessionStore};

let store = SessionStore::new("./data/sessions");
let mut session = store.create_session(
    "session-42",
    "2026-07-24T00:00:00Z",
)?;

let position = session.add_event(Role::UserMessage, "Hello")?;
assert_eq!(position.index(), 0);

let snapshot = session.list();
assert_eq!(snapshot.events.len(), 1);

session.seal()?;
# Ok::<(), anyhow::Error>(())
```

The caller supplies the session ID and creation-time text. Session IDs are
nonempty ASCII alphanumeric, `-`, or `_` strings of at most 255 bytes.
Creation-time text is retained exactly and must be nonempty.

## Stores and sessions

- `SessionStore::create_session` creates a new `<id>.session-log` file and
  fails if it already exists.
- `SessionStore::open_session` verifies the durable log, repairs only an
  incomplete trailing frame, removes unreferenced pending-object files, and
  rejects referenced objects that are missing or invalid.
- `SessionStore::session_ids` returns sorted IDs derived from valid
  `.session-log` filenames.
- `Session::list` returns the header and ordered events as a snapshot.
- `Session::add_event` appends and synchronizes an ordinary role/text event.
  `Role::PendingObject` is rejected here.
- `Session::add_pending_object` durably installs object bytes before appending
  their `PendingObject` event. Its returned `EventPosition` identifies both
  the event and the sidecar file.
- `Session::read_pending_object` verifies and returns a referenced object.
- `Session::seal` verifies referenced objects, appends a synchronized footer,
  and idempotently prevents later events.
- `Session::delete_committed` and `Session::delete_abandoned` consume the
  handle and remove only the exact session log and recognized object files.

`SealedSession::list` borrows the immutable transcript snapshot.
`SealedSession::pending_objects` verifies and loads all pending objects in
event order.

## Logical values

`SessionHeader` contains `format_version`, `session_id`, and `created_at`.
`SessionLog` contains that header and a `Vec<SessionEvent>`. Each event contains
only `role` and `text`; its zero-based array position is its stable identity.

`Role` is a rendering classification:

- `SystemMessage`
- `SystemError`
- `UserMessage`
- `KennedyMessage`
- `KennedyToolCall`
- `ToolResult`
- `ToolError`
- `Object`
- `PendingObject`

The crate serializes roles as kebab-case JSON values and headers with
camel-case field names. It does not interpret event text, pair tool calls with
results, construct model context, or perform database transactions.

## Durability boundary

The format version is `0.2.1`. Session frames and pending-object bytes are
SHA-256 checksummed. Successful appends, object installation, sealing, and
deletion synchronize the affected files and directory.

Mutation is serialized between handles opened through this crate within one
process. Applications must ensure that other processes do not concurrently
modify the same session files.