Event log unification#188
Merged
Merged
Conversation
Make the per-session event log the source of truth and demote the persisted SessionState to a checkpoint stamped with the log position it reflects (log-authoritative with checkpoints): - halter-protocol: add the pure fold module (apply_event, fold_events, covered_state_matches) reproducing messages, compacted_prefix, and usage_so_far from committed events; ContextCompacted now carries optional state-complete CompactionEventEffects; new SessionResumed payload; Usage::saturating_accumulate shared by runtime and fold. - halter-session: commit() takes expected_head_sequence instead of expected_state (conflicts are now an O(1) head check, not a structural whole-state compare); StoredSession carries state_sequence/head_sequence with StoredSession::new; replay_after for log tails; sqlite migration v2 backfills state_sequence to each session's log head; conformance suite locks in head semantics and the fold(replay()) == checkpoint invariant on every backend. - halter-runtime: turn loop threads a u64 expected head instead of cloning/comparing full SessionState per flush; loaders hydrate lagging checkpoints by folding the log tail; compaction events carry their effects; resume appends SessionResumed; new export_session_trace / HalterSession::export_trace derive the trace-file format from replay(), no traces_dir required. Follow-ups tracked in docs/event-log-unification.md (local): halter trace CLI subcommand, fold-derived usage as the sole accumulator, #172 outcome summaries over the export, BestEffort-event pruning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR makes the append-only per-session event log the authoritative source for session history and treats persisted
SessionStateas a checkpoint at a known log position. Runtime hydration, optimistic concurrency, trace export, and telemetry now derive from the same ordered event stream instead of relying on partially independent persistence paths.The result is a replayable session model with explicit invariants: committed events have gap-free monotonic sequences, checkpoints declare which sequence they cover, lagging checkpoints are hydrated from the log tail, and concurrent writers conflict on the event-log head.
What changed
Canonical event folding and checkpoints
halter_protocol::foldwith pureapply_event,fold_events, andcovered_state_matchesoperations.SessionState, including messages, compacted context, and accumulated usage.state_sequenceandhead_sequencetoStoredSession, plusStoredSession::newfor correctly initialized records.SessionStore::replay_afterso hydration can replay only events newer than a checkpoint; SQLite pushes the sequence bound into its query.Reproducible state transitions
ContextCompactedwith optionalCompactionEventEffects, recording the post-compaction message window and provider-native prefix needed to replay the only history-rewriting operation.SessionResumed, ensuring resume-related state changes also advance the canonical log.Event-head concurrency
SessionStore::committo acceptexpected_head_sequence: Option<u64>instead of an expected state snapshot.SQLite migration
sessions.state_sequence.Trace unification
HalterSession::export_trace()andhalter_runtime::export_session_traceto rebuild traces from persisted events, whether or not live trace recording was configured.generated_attimestamp field.halter traceCLI command out of this PR; this change provides the runtime API it can call.Documentation and compatibility
SessionStoreimplementations because thecommitconcurrency argument changes from expected state to expected head sequence.create_sessionnow rejects records with non-zero state/head sequences.ContextCompactedevents remain readable.CI follow-up included here
The final commits also repair failures exposed by the current CI environment:
playwright-rsexactly to0.12.0so fresh lockfile generation cannot silently change the browser API dependency.1.59.1compile-time version to every CI job that compiles the browser crate. The upstream 0.12.x build script otherwise omits that required value when its build-time driver URL returns 404; runtime driver discovery and installation behavior is unchanged.Test coverage
Verification
cargo +1.97.0 fmt --all -- --checkcargo +1.97.0 clippy --workspace --all-features --all-targets -- -D warningscargo +1.97.0 clippy --workspace --all-targets -- -D warningscargo +stable test --workspace --all-featurescargo +stable test --workspacePLAYWRIGHT_DRIVER_VERSION=1.59.1 cargo +1.88.0 check --workspace --all-features --all-targetscargo +1.88.0 test --workspace --all-features