Skip to content

Add kernel state backend (internal/statebackend) - #3

Merged
scrothers merged 7 commits into
mainfrom
feat/statebackend
Jul 24, 2026
Merged

Add kernel state backend (internal/statebackend)#3
scrothers merged 7 commits into
mainfrom
feat/statebackend

Conversation

@scrothers

Copy link
Copy Markdown
Member

Summary

  • Implements the kernel state backend per docs/specifications/state-backend.md: sqlite-per-session persistence with the five-table schema reproduced verbatim (append-only events, session_meta, cost_ledger, plan_items, producers), PRAGMA user_version schema versioning with per-step transactional migrations, and ULID session files that sort chronologically.
  • Single concrete package by design — the spec forbids pluggability, so no interface/drivers split. Pure-Go modernc.org/sqlite keeps the three-OS race CI cgo-free; sole-writer semantics are enforced mechanically via SetMaxOpenConns(1) so commit order is sequence order.
  • Write side: AppendEvent / AppendMessage / AppendPlan each run in one transaction with their cost/plan/producer rows; session_meta is the only mutable table. Read side: sequence-ordered Events replay iterator, deduplicated Producers set, TotalCostUSD, CostLedger, PlanItems.
  • Corruption recovery on Open: PRAGMA integrity_check, damaged files renamed to .corrupt (never deleted), table-by-table salvage into a fresh 0600 schema-correct file preserving sequence values, noisy slog WARN reporting, ErrUnrecoverable (with wrapped cause) when salvage fails.
  • Telemetry: StartStateBackend* span helpers added to internal/telemetry, wired through all I/O paths.
  • Docs: package godoc/README/CLAUDE.md documenting the decisions the spec left open, plus fix-forward spec alignment — producer_category vocabulary enumerated in state-backend.md, and the stale "queryable parent→children index" claims in subagents.md, conformance.md, and turn-algorithm.md corrected to the authoritative session_meta scan / live in-memory tree model.

Test plan

  • go build ./..., go vet ./..., gofmt -l -s ., go mod tidy no-op — clean
  • go test -race -shuffle=on -covermode=atomic ./... — pass; internal/statebackend at ~86% coverage (floor 80%), including concurrent-appender sequence-density race tests, WAL concurrent-reader tests, corruption/recovery tests, and migration tests
  • Fuzz: FuzzValidateSessionID and FuzzEventRoundTrip — 10s runs, no crashes
  • golangci-lint run — 0 issues; gosec -exclude-generated ./... — 0 issues; govulncheck ./... — clean; buf lint / buf format --diff — clean

Add package doc, sentinel errors, and ULID session-id helpers with
unit and fuzz coverage, per docs/specifications/state-backend.md.
Adds github.com/oklog/ulid/v2.
Implement the five-table DDL verbatim from state-backend.md, PRAGMA
user_version handling with per-step transactional migrations, and the
Store lifecycle: Create, Open (version check before any table access,
ErrSchemaTooNew on newer files), List and Children via metadata-only
directory scans that never migrate as a side effect.
Adds modernc.org/sqlite as a direct dependency.
Implement sole-writer append transactions: AppendEvent with same-tx
producer upsert, AppendMessage with cost_ledger row, AppendPlan with
plan_items rows, SetStatus, and idempotent Close with WAL checkpoint.
Event kinds, session statuses, plan decisions, and producer categories
encode to the spec's lowercase text vocabulary; unspecified enum values
are rejected. Add StartStateBackend* span helpers to internal/telemetry
and instrument Create/Open. Race tests assert dense 1..N sequences
under concurrent appenders.
Implement the read-side API: sequence-ordered Events replay iterator,
deduplicated Producers set, TotalCostUSD, CostLedger, PlanItems, and
Meta. Wire Open through a real integrity check: corrupt or unopenable
files are renamed to .corrupt (never deleted), salvaged table-by-table
into a fresh schema-correct file preserving sequence values, with slog
WARN reporting; unsalvageable files return ErrUnrecoverable. Add an
event round-trip fuzz target and query/recovery span helpers.
Expand the package godoc with the design decisions the spec left open,
add README and package CLAUDE.md, enumerate producer_category's text
vocabulary in state-backend.md, and fix forward the stale parent-to-
children index claims in subagents.md, conformance.md, and
turn-algorithm.md: parent linkage lives in session_meta, child lookup
is a session_meta scan, and cost-rollup, depth threading, and
cancellation are live in-memory mechanisms, not state-backend reads.
Pre-create the recovery scratch file at 0600 so recovered session
files keep the documented mode instead of SQLite's 0644 default, move
foreign_keys enforcement into the DSN so every pooled connection gets
it rather than only the first, and chain the salvage failure cause
through ErrUnrecoverable so callers keep both errors.Is matching and
the underlying reason.
Copilot AI review requested due to automatic review settings July 24, 2026 16:24
@github-actions

Copy link
Copy Markdown

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 4 package(s) with unknown licenses.
  • ⚠️ 1 packages with OpenSSF Scorecard issues.
See the Details below.

License Issues

go.mod

PackageVersionLicenseIssue Type
github.com/dustin/go-humanize1.0.1NullUnknown License
github.com/mattn/go-isatty0.0.20NullUnknown License
modernc.org/libc1.74.1NullUnknown License
modernc.org/sqlite1.54.0NullUnknown License

OpenSSF Scorecard

PackageVersionScoreDetails
gomod/github.com/dustin/go-humanize 1.0.1 UnknownUnknown
gomod/github.com/mattn/go-isatty 0.0.20 UnknownUnknown
gomod/github.com/ncruces/go-strftime 1.0.0 🟢 3.4
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review⚠️ 0Found 0/24 approved changesets -- score normalized to 0
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
SAST⚠️ 0no SAST tool detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
gomod/github.com/oklog/ulid/v2 2.1.2 🟢 3.4
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 6Found 19/30 approved changesets -- score normalized to 6
Packaging⚠️ -1packaging workflow not detected
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/remyoudompheng/bigfft 0.0.0-20230129092748-24d4a6f8daec ⚠️ 2.9
Details
CheckScoreReason
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review⚠️ 1Found 3/27 approved changesets -- score normalized to 1
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/modernc.org/libc 1.74.1 UnknownUnknown
gomod/modernc.org/mathutil 1.7.1 UnknownUnknown
gomod/modernc.org/memory 1.11.0 UnknownUnknown
gomod/modernc.org/sqlite 1.54.0 UnknownUnknown

Scanned Files

  • go.mod

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces the kernel’s non-pluggable sqlite-per-session state backend per docs/specifications/state-backend.md, including schema/versioning, append/query APIs, corruption recovery, and end-to-end test coverage. It also extends kernel telemetry spans for state-backend operations and aligns several specifications with the “scan session_meta” tree-walking model.

Changes:

  • Added internal/statebackend implementing per-session sqlite persistence (schema, migrations, append/query APIs, integrity-check + salvage recovery).
  • Added state-backend tracing spans to internal/telemetry.
  • Updated specifications and module dependencies to support the new backend.

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/telemetry/span.go Adds tracing span names and StartStateBackend* helpers for state backend operations.
internal/statebackend/statebackend.go Implements Store and SessionMeta plus create/open/list/children and metadata scanning.
internal/statebackend/statebackend_test.go Tests Store behaviors (create/open/list/children), timestamp/status encoding, and openDB pragmas.
internal/statebackend/sessionid.go Adds ULID-based session ID generation and canonical validation.
internal/statebackend/sessionid_test.go Unit tests for session ID generation, ordering, concurrency uniqueness, and validation.
internal/statebackend/sessionid_fuzz_test.go Fuzzes ValidateSessionID for robustness and round-trip properties.
internal/statebackend/session.go Implements write-path APIs (AppendEvent/Message/Plan, SetStatus, Close) with transactional guarantees.
internal/statebackend/session_test.go Tests write-path behavior, rollback semantics, WAL read/write concurrency, and closed-session behavior.
internal/statebackend/schema.go Defines the spec-verbatim schema and migration scaffolding using PRAGMA user_version.
internal/statebackend/schema_test.go Tests schema initialization and migration transactionality/versioning behavior.
internal/statebackend/README.md Package-level README documenting responsibilities, API sketch, and recovery/testing notes.
internal/statebackend/query.go Implements read-path APIs including replay iterator (Events) and structured queries.
internal/statebackend/query_test.go Tests replay/query methods including ordering, decode errors, and totals/ledgers.
internal/statebackend/integrity.go Implements PRAGMA integrity_check on open and salvage recovery into a new file.
internal/statebackend/integrity_test.go Tests healthy-open, recoverable corruption, unrecoverable cases, and recovery artifact handling.
internal/statebackend/event.go Defines event/cost/plan item types and enum/text encoding/decoding helpers.
internal/statebackend/event_test.go Tests enum encode/decode round-trips and invalid-value rejection.
internal/statebackend/event_fuzz_test.go Fuzzes event append/read round-tripping including payload and timestamp truncation behavior.
internal/statebackend/errors.go Adds typed sentinel errors for state backend operations.
internal/statebackend/doc.go Adds package godoc describing design decisions and how the backend is used.
internal/statebackend/CLAUDE.md Adds agent notes capturing key invariants (spec-verbatim schema, append-only, ordering authority, recovery rules).
go.mod Adds required dependencies for sqlite + ULID support.
go.sum Updates dependency checksums for new direct/transitive deps.
docs/specifications/state-backend.md Clarifies producer_category vocabulary in the schema section.
docs/specifications/agent-loop/turn-algorithm.md Updates cost-rollup wording to reflect in-memory live tree state, not state-backend index.
docs/specifications/agent-loop/subagents.md Updates session-hierarchy bookkeeping and cancellation propagation to the scan-based/no-index model.
docs/specifications/agent-loop/conformance.md Updates conformance table to “session_meta scan (no separate index)”.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/statebackend/sessionid.go
Comment thread internal/statebackend/errors.go
Unix mode bits aren't meaningful on Windows: created files report 666,
directories 777, and read-only directory modes don't block file
creation. Guard the permission assertions per-OS, skip the read-only
directory test on Windows, close the session on an unexpected Create
success so TempDir cleanup can't wedge on an open handle, and note in
the package doc that the 0700/0600 guarantee is Unix-only.
@scrothers
scrothers merged commit ee7b024 into main Jul 24, 2026
15 checks passed
@scrothers
scrothers deleted the feat/statebackend branch July 24, 2026 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants