Documentation
¶
Overview ¶
Package store persists clarity watch's session history (projects, worktrees, sessions, commits, snapshots) to a per-repo SQLite database, so it survives a process restart or crash. See the "ER: Persisted Session History" and "Session Lifecycle" design artifacts (Strata, Clarity project) for the schema and its rationale.
Index ¶
- func AppendSnapshot(db *sql.DB, sessionID int64, position int, source, format, kind string, ...) error
- func CloseRun(db *sql.DB, runID int64) error
- func CloseSessionCommitted(db *sql.DB, sessionID int64, commits []CommitRecord) error
- func CloseSessionDiscarded(db *sql.DB, sessionID int64) error
- func CloseSessionStale(db *sql.DB, sessionID int64) error
- func CloseSessionWorktreeRemoved(db *sql.DB, sessionID int64) error
- func EnsureProject(db *sql.DB, repoOrigin string) (string, error)
- func LockPathFor(worktreePath string) (string, error)
- func MarkWorktreeDisposed(db *sql.DB, id string) error
- func MarkWorktreeHidden(db *sql.DB, id string) error
- func Migrate(db *sql.DB) error
- func Open(path string) (*sql.DB, error)
- func OpenOrResumeSession(db *sql.DB, worktreeID, currentSource string, runID int64) (sessionID int64, nextPosition int, matched bool, err error)
- func OpenRun(db *sql.DB, projectID string, pid int) (int64, error)
- func OpenSession(db *sql.DB, worktreeID string, runID int64) (int64, error)
- func PathFor(worktreePath string) (string, error)
- func RegisterWorktree(db *sql.DB, id, projectID, path string, kind protocol.WorktreeKind, ...) error
- func ResolveRepoOrigin(worktreePath string) (string, error)
- type CommitRecord
- type SessionDetail
- type SessionSummary
- type SnapshotRecord
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendSnapshot ¶
func AppendSnapshot(db *sql.DB, sessionID int64, position int, source, format, kind string, createdAt time.Time) error
AppendSnapshot writes one snapshot into sessionID's snapshot stream, called as each snapshot is produced (not batched) so a crash or kill loses at most the single write in flight, never the whole session.
func CloseRun ¶
CloseRun sets ended_at on runID, marking it as having shut down cleanly. A run whose ended_at is still NULL crashed or was killed rather than exiting through its own defer chain — the same "NULL means unclean exit" convention CloseSessionStale relies on for a session left open.
func CloseSessionCommitted ¶
func CloseSessionCommitted(db *sql.DB, sessionID int64, commits []CommitRecord) error
CloseSessionCommitted closes sessionID as committed: sets closed_at and closed_reason='committed', and records commits. Requires at least one commit — a session closed by a real commit always has one, per the design; a session with none belongs to CloseSessionDiscarded, CloseSessionWorktreeRemoved, or CloseSessionStale instead.
func CloseSessionDiscarded ¶
CloseSessionDiscarded closes sessionID as discarded: the working tree returned to a clean state with no commit (stash, checkout -- ., reset with no reachable new commits) while clarity watch was actively watching. No commits are recorded.
func CloseSessionStale ¶
CloseSessionStale closes sessionID as stale: it was left open by a process that exited without closing it (a crash, a kill, a machine restart — clarity watch doesn't know which), and at the next relaunch its last recorded snapshot no longer matched the freshly rebuilt graph, so it was closed rather than resumed. No commits are recorded. Called by OpenOrResumeSession — not normally called directly.
func CloseSessionWorktreeRemoved ¶
CloseSessionWorktreeRemoved closes sessionID as worktree_removed: the underlying git worktree was physically removed while the session still had uncommitted snapshots. No commits are recorded.
func EnsureProject ¶
EnsureProject returns the id of the projects row for repoOrigin, creating one (with a fresh UUID) if it doesn't exist yet. Idempotent: calling it again for the same repoOrigin always returns the same id, never inserts a duplicate row — including under a race, since repo_origin is UNIQUE and a conflicting insert falls back to re-reading the winning row.
func LockPathFor ¶
LockPathFor resolves the path to the repo-wide advisory lock file that gates a single clarity watch process per repository (see CLR-91). It sits beside the session-history database, sharing the same directory and the same one-per-clone guarantee.
func MarkWorktreeDisposed ¶
MarkWorktreeDisposed sets disposed_at on worktree id: its underlying git worktree was physically removed. The row is never deleted.
func MarkWorktreeHidden ¶
MarkWorktreeHidden sets hidden_at on worktree id: the user closed its already-disposed tab. The row is never deleted.
func Migrate ¶
Migrate applies every pending migration embedded in this package to db. Applying it twice is a safe no-op: migrate.ErrNoChange is swallowed, not treated as a failure. A migration that fails partway is left by golang-migrate's sqlite3 driver marked "dirty" rather than silently applied — Migrate reports that as an error rather than pretending the schema is usable.
func Open ¶
Open opens the SQLite database at path with the pragmas this package relies on (foreign key enforcement, since the schema depends on it) and runs any pending migrations. Callers should PathFor(worktreePath) to get path.
The connection pool is limited to one connection: SQLite serializes writers anyway, and Migrate needs a guarantee that the connection it toggles PRAGMA foreign_keys on is the same one golang-migrate later runs its transaction on (see migrate.go).
func OpenOrResumeSession ¶
func OpenOrResumeSession(db *sql.DB, worktreeID, currentSource string, runID int64) (sessionID int64, nextPosition int, matched bool, err error)
OpenOrResumeSession is the entry point for the first snapshot of a worktree's lifetime in this process — the restart-hydration decision. runID is this process's watch_runs row, used only if a fresh session ends up being opened (see OpenSession) — a resumed session keeps the run_id of the run that originally opened it, not runID.
If no session was left open for worktreeID, this is exactly OpenSession: a fresh session opens, matched is false, nextPosition is 0.
If a session WAS left open (a prior process run never got to close it — crash, kill, machine restart), it's a resume candidate. currentSource is the freshly rebuilt graph for this worktree, always available for free since attaching to a worktree already rebuilds it to seed the tab. If it matches that session's last recorded snapshot exactly, the gap was invisible to what we actually track, so the session is resumed: matched is true, telling the caller currentSource is already recorded and must not be written again, and nextPosition is where the next *new* snapshot should go. If it doesn't match, the orphaned session is closed via CloseSessionStale (never resumed, never silently left open) and a fresh session opens normally.
func OpenRun ¶
OpenRun creates a new watch_runs row for the clarity watch process identified by pid, watching the repo identified by projectID, and returns its id.
A run's boundary is deliberately the same one CLR-91's repo lock already enforces: one process holds the lock for its whole lifetime, watching the entire repo (main worktree plus every linked worktree) under that single hold. OpenRun should be called once per process, right after that lock is acquired and persistence is otherwise set up — every session opened afterward is stamped with this run's id (see OpenSession), so which `clarity watch` invocation produced a given session becomes recoverable without inferring it from timestamps.
func OpenSession ¶
OpenSession creates a new open session (closed_at NULL) for worktreeID, numbered one past the highest number ever used for that worktree — closed or still open, so a stale open session left behind by an earlier process run is never renumbered or reused — and returns its id. runID is the calling process's watch_runs row (see OpenRun), stamped once and never touched again: a session's run_id always names the run that opened it, even if a later run resumes it (see OpenOrResumeSession) — resuming is a continuation, not a re-parenting.
Each call always creates a fresh session; it never looks for or resumes a previously-open one. Deciding what to do with a session left open by a prior process run (resume vs. CloseSessionStale) is restart-hydration's job, not this one's.
Numbering is computed as MAX(number)+1 inside a transaction and retried on a unique-constraint conflict against idx_sessions_worktree_id_number, so it stays correct under concurrent writers regardless of what CLR-91 concludes about process-level coordination.
func PathFor ¶
PathFor resolves the session-history database path for the repository containing worktreePath. It does not create the database itself, only the containing directory, so callers can open/migrate it immediately after.
func RegisterWorktree ¶
func RegisterWorktree(db *sql.DB, id, projectID, path string, kind protocol.WorktreeKind, lastKnownLabel string) error
RegisterWorktree upserts a worktrees row for id. On first sight it's inserted with first_seen_at set to now. On a later re-registration (e.g. clarity watch relaunched against the same worktree, which is why id is deterministic) it refreshes last_known_label and clears disposed_at and hidden_at: the supervisor calling this at all means the worktree is verifiably live right now, which contradicts any disposed/hidden marker left over from a prior lifecycle at this same id. first_seen_at, path, and kind are left untouched on conflict — "first" stays first.
func ResolveRepoOrigin ¶
ResolveRepoOrigin returns the stable identity this package uses for projects.repo_origin: the repo's "origin" remote URL, or — for a repo with no remote configured, the normal state for a fresh `git init` that hasn't been pushed anywhere — a synthetic identity derived from its common git dir, prefixed so it can never collide with a real remote URL.
Types ¶
type CommitRecord ¶
CommitRecord is one commit to record against a session being closed as committed.
type SessionDetail ¶
type SessionDetail struct {
SessionSummary
Snapshots []SnapshotRecord
Commits []CommitRecord
}
SessionDetail is a session's full content: its summary plus every snapshot and commit recorded against it, ordered by position.
func GetSessionDetail ¶
GetSessionDetail returns sessionID's full content: its summary, every snapshot, and every commit, ordered by position. found is false if no session with that id exists.
type SessionSummary ¶
type SessionSummary struct {
ID int64
WorktreeID string
RunID int64
Number int
CreatedAt time.Time
ClosedAt *time.Time
ClosedReason string
SnapshotCount int
CommitCount int
}
SessionSummary is one session's metadata, with no snapshot/commit content — see ListSessions. Kept as this package's own type, independent of the wire format (mirrored by protocol.PersistedSessionSummary).
func ListSessions ¶
func ListSessions(db *sql.DB, projectID string) ([]SessionSummary, error)
ListSessions returns every persisted session across the whole project identified by projectID — every worktree, every run — ordered by worktree then number. No snapshot/commit content, only counts: cheap enough to call unconditionally on attach.
Scoped to the project, not a single worktree: a watch_runs row (CLR-97) already spans every worktree the process watches, so a worktree-scoped listing would force the caller to fetch per-worktree and stitch runs back together itself.