Our M168 session registry runs on the built-in node:sqlite (Node β₯22.5), shared by every CC session at ~/.local/state/orchestkit/sessions.db. These three views are the actual correctness rules from session-registry.ts β and what #2006 adds on top. Toggle things and watch them pass or break. π§ͺ
every CC session ββ ββ register / heartbeat / lock / override
primary β β β
worktree β€βββββββββΌββββΌβββββββββββββββββββββββββββββββββββββββββββ
#2004 β ~/.local/state/orchestkit/sessions.db (node:sqlite) β
WAL Β· lock-free reads Β· serialized writes β
001 sessionsΒ·locksΒ·overridesΒ·worktree_links v1 ββββ€
002 skill_suggestion Β· skill_invocation v2 #2006 ββ π
The pragma order is load-bearing. node:sqlite has no default busy handler, unlike better-sqlite3 β so the WAL switch under concurrency throws instantly unless a timeout is already armed.
Each session takes the RESERVED lock at BEGIN IMMEDIATE, so contention surfaces there β not mid-write. Losers see SQLITE_BUSY (errcode 5/261) and retry up to 15Γ with 20β150ms jitter (~1.3s worst case). Sync spin: hooks + DatabaseSync are synchronous.
| skill | suggested | invoked |
|---|
A skill_suggestion row at suggest-time, a skill_invocation row when a /-skill runs. Both keyed by (session_id, skill) so the adoption query is a self-join β impossible against today's append-only skill-usage.log.
skill-suggestions.jsonl writer that doesn't exist on main. smart-suggestions.ts only returns a string (and suggests rules, not skills). Phase 0 must pin the real suggest-side emitter, else these two tables model a ghost. Comment the drift on #2006 first.