kcode-session-control-journal 0.1.0

Durable checksummed session-control record file mechanics
Documentation
  • Coverage
  • 72.73%
    8 out of 11 items documented0 out of 7 items with examples
  • Size
  • Source code size: 28.46 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 492.08 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 11s Average build duration of successful builds.
  • all releases: 11s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • DavidVorick

kcode-session-control-journal

kcode-session-control-journal owns only the durable record-file mechanics for one checksummed append-only .session-control file. It does not interpret record kinds or values.

API

use std::path::PathBuf;

use anyhow::Result;
use kcode_session_control_journal::{Journal, Record};
use serde_json::Value;

impl Journal {
    pub fn create(path: PathBuf) -> Result<Self>;
    pub fn open(path: PathBuf) -> Result<Option<Self>>;
    pub fn records(&self) -> &[Record];
    pub fn append(
        &mut self,
        kind: impl Into<String>,
        recorded_at: impl Into<String>,
        value: Value,
    ) -> Result<()>;
    pub fn replace(
        &mut self,
        records: impl IntoIterator<Item = Record>,
    ) -> Result<()>;
}

Record is the complete public data shape:

#[serde(rename_all = "camelCase")]
pub struct Record {
    pub kind: String,
    pub recorded_at: String,
    pub value: serde_json::Value,
}

Journal is opaque. Its path and in-memory records are private.

Encoding and opening

Each record is compact JSON encoded as Record, prefixed by the lowercase SHA-256 hex digest of those exact JSON bytes and one ASCII space, and terminated by one newline:

<lowercase SHA-256 hex><space><JSON><newline>

create uses create-new semantics and fails if the target already exists. It synchronizes the new file and then its parent directory before returning.

open returns Ok(None) only when the path is absent. Every complete, newline-terminated line must have a valid checksum, UTF-8 JSON, and the exact Record shape. Any malformed or corrupt complete line rejects the whole open. A final tail without a newline is treated as an interrupted append: opening truncates to the start of that tail and synchronizes the file, preserving all complete records.

records returns records in durable file order.

Mutation and durability

append writes one encoded record and synchronizes the file before adding the record to the in-memory slice. A serialization, write, or synchronization failure leaves memory unchanged. A later open applies the incomplete-tail rule to any interrupted partial append.

replace is the storage primitive for domain-selected compaction. It writes the supplied records in iteration order to a unique create-new temporary file in the target directory, applies the target file's current permissions, synchronizes the temporary file, atomically renames it over the target, and synchronizes the parent directory. It removes the temporary file after failure when possible. In-memory records change only after all replacement steps succeed.

The caller must treat an error after a filesystem operation as potentially having changed durable state and reopen before retrying. In particular, a parent-directory synchronization failure can occur after a rename installed the replacement while the current Journal still retains its prior in-memory records.

Ownership boundary

Session History owns all domain decisions: which lifecycle, command, stop, or other records survive compaction, when compaction is appropriate, and how record values are interpreted. Session History also owns process locks and all coordination around readers, appenders, replacement, and deletion.

This crate has no lifecycle, command, stop, ingress, Session History record, kcode-session-log, Chatend, Kweb, HTTP, catalog, locking, or deletion policy. It does not create parent directories and does not coordinate concurrent processes. Callers must ensure the parent directory exists and must not append or replace the same path concurrently without external coordination.