@kaged/storage

SQLite adapter via bun:sqlite with schema migrations, CRUD for sessions/messages/providers/compactions/task instances, and transcript persistence

5
source files
8
test files
~11.2k
lines
✓ 312 pass
tests
pass
typecheck
clean
lint

Test results 312

sqlite storage issues > createIssue + getIssue round-trip [5.59ms]
sqlite storage issues > getIssue returns null for nonexistent id [3.86ms]
sqlite storage issues > getIssueByNumber round-trip [3.59ms]
sqlite storage issues > getIssueByNumber returns null when absent [3.53ms]
sqlite storage issues > createIssue duplicate id throws ConstraintError [3.95ms]
sqlite storage issues > createIssue duplicate project/number throws ConstraintError [3.67ms]
sqlite storage issues > listIssues by projectId [4.09ms]
sqlite storage issues > listIssues filtered by status [3.79ms]
sqlite storage issues > listIssues filtered by createdBy [4.10ms]
sqlite storage issues > listIssues orders by updatedAt descending [3.72ms]
sqlite storage issues > listIssues paginates with cursor + limit [3.97ms]
sqlite storage issues > updateIssue updates title [3.74ms]
sqlite storage issues > updateIssue updates body [3.90ms]
sqlite storage issues > updateIssue updates status assignment resolution fields [3.64ms]
sqlite storage issues > updateIssue preserves originalBody on first edit [3.64ms]
sqlite storage issues > updateIssue does not overwrite originalBody when omitted later [3.72ms]
sqlite storage issues > updateIssue can clear assignment [3.60ms]
sqlite storage issues > updateIssue nonexistent throws NotFoundError [3.62ms]
sqlite storage issues > deleteIssue success [3.67ms]
sqlite storage issues > deleteIssue nonexistent throws NotFoundError [3.59ms]
sqlite storage issues > deleteIssue cascades to issue_updates [3.84ms]
sqlite storage issues > nextIssueNumber starts at 1 [3.54ms]
sqlite storage issues > nextIssueNumber increments per project [3.72ms]
sqlite storage issues > countIssues counts by project [3.69ms]
sqlite storage issues > createIssueUpdate + getIssueUpdate round-trip [3.89ms]
sqlite storage issues > getIssueUpdate returns null for nonexistent id [3.53ms]
sqlite storage issues > createIssueUpdate duplicate id throws ConstraintError [3.69ms]
sqlite storage issues > createIssueUpdate missing issue throws ConstraintError [5.12ms]
sqlite storage issues > listIssueUpdates ordered by created_at ASC [3.86ms]
sqlite storage issues > listIssueUpdates paginates [3.96ms]
sqlite storage issues > listIssueUpdates only returns rows for requested issue [3.75ms]
sqlite storage issues > deleteIssueUpdate success [3.62ms]
sqlite storage issues > deleteIssueUpdate nonexistent throws NotFoundError [3.57ms]
sqlite storage issues > metadata round-trip JSON [3.77ms]
sqlite storage issues > visibility values persist for all and operator_only [4.14ms]
sqlite storage guest activity > listGuestActivity returns issues opened by the guest [5.66ms]
sqlite storage guest activity > listGuestActivity returns comments made by the guest [2.93ms]
sqlite storage guest activity > listGuestActivity returns grant events for the guest [3.02ms]
sqlite storage guest activity > listGuestActivity filters by projectId [2.96ms]
sqlite storage guest activity > listGuestActivity paginates with cursor + limit [3.29ms]
sqlite storage users > migrates v14 guest schema into v15 user schema [11.83ms]
sqlite storage users > createUser and lookup methods round-trip new fields [5.45ms]
sqlite storage users > listUsers filters by status and role [5.53ms]
sqlite storage users > updateUser updates email avatar provider and role [5.35ms]
sqlite storage users > lookupUsers fetches users in requested order and skips missing ids [5.57ms]
sqlite storage users > listPendingUsers returns only pending users [5.37ms]
sqlite storage users > reapPendingSsoUsers deletes only stale pending sso users without invites [5.85ms]
sqlite storage compactions > createCompaction + getCompaction round-trip [5.22ms]
sqlite storage compactions > getCompaction returns null for nonexistent id [3.20ms]
sqlite storage compactions > createCompaction duplicate id throws ConstraintError [3.34ms]
sqlite storage compactions > round-trips all trigger types [3.44ms]
sqlite storage compactions > round-trips all strategy types [3.44ms]
sqlite storage compactions > round-trips supersededMessageIds as JSON array [3.22ms]
sqlite storage compactions > round-trips empty supersededMessageIds [3.18ms]
sqlite storage compactions > round-trips pluginsFired with entries [3.27ms]
sqlite storage compactions > round-trips pluginCost when present [3.21ms]
sqlite storage compactions > round-trips pluginCost as null [3.20ms]
sqlite storage compactions > round-trips fallbackOccurred boolean [3.18ms]
sqlite storage compactions > round-trips summary fields [3.21ms]
sqlite storage compactions > round-trips checkpoint linkage [3.23ms]
sqlite storage compactions > round-trips operator feedback fields [3.21ms]
sqlite storage compactions — listCompactions > lists compactions for a session ordered by created_at [3.41ms]
sqlite storage compactions — listCompactions > returns empty list for session with no compactions [3.24ms]
sqlite storage compactions — listCompactions > paginates with cursor [3.63ms]
sqlite storage compactions — listCompactions > does not return compactions from other sessions [3.35ms]
sqlite storage compactions — updateCompaction > updates afterEstimate [3.39ms]
sqlite storage compactions — updateCompaction > updates operator feedback [3.32ms]
sqlite storage compactions — updateCompaction > updates fallback fields [3.87ms]
sqlite storage compactions — updateCompaction > updates supersededMessageIds [3.26ms]
sqlite storage compactions — updateCompaction > updates summary fields [3.24ms]
sqlite storage compactions — updateCompaction > updates checkpointId [3.24ms]
sqlite storage compactions — updateCompaction > no-op update does nothing [3.20ms]
sqlite storage compactions — updateCompaction > throws NotFoundError for nonexistent id [3.15ms]
sqlite storage compactions — updateCompaction > preserves unchanged fields on partial update [3.24ms]
sqlite storage compactions — migration v9 > schema version is 9 [3.23ms]
session boundIssue > sqlite storage issue todos and links > create session with boundIssue and getSession returns it [6.36ms]
session boundIssue > sqlite storage issue todos and links > update session boundIssue persists new issue id [5.36ms]
session boundIssue > sqlite storage issue todos and links > update session boundIssue can clear to null [5.24ms]
issue_todos > sqlite storage issue todos and links > create and get issue todo [5.66ms]
issue_todos > sqlite storage issue todos and links > get non-existent issue todo returns null [5.42ms]
issue_todos > sqlite storage issue todos and links > duplicate issue todo id throws ConstraintError [5.62ms]
issue_todos > sqlite storage issue todos and links > list issue todos returns position order ascending [5.83ms]
issue_todos > sqlite storage issue todos and links > list issue todos breaks position ties by id [5.66ms]
issue_todos > sqlite storage issue todos and links > list issue todos filters by status [5.74ms]
issue_todos > sqlite storage issue todos and links > list issue todos filters by kind [5.61ms]
issue_todos > sqlite storage issue todos and links > list issue todos filters by phase [5.57ms]
issue_todos > sqlite storage issue todos and links > list issue todos combines status kind and phase filters [5.50ms]
issue_todos > sqlite storage issue todos and links > update issue todo persists mutable fields [21.22ms]
issue_todos > sqlite storage issue todos and links > update non-existent issue todo throws NotFoundError [5.34ms]
issue_todos > sqlite storage issue todos and links > delete issue todo removes it [5.45ms]
issue_todos > sqlite storage issue todos and links > delete non-existent issue todo throws NotFoundError [5.26ms]
issue_todos > sqlite storage issue todos and links > count issue todos counts only matching issue [5.56ms]
issue_todos > sqlite storage issue todos and links > nextIssueTodoPosition starts at one for empty issue [5.29ms]
issue_todos > sqlite storage issue todos and links > nextIssueTodoPosition uses max position plus one [6.24ms]
issue_todos > sqlite storage issue todos and links > storage allows multiple in_progress (handler enforces single-in_progress) [5.61ms]
issue_todos > sqlite storage issue todos and links > another todo can become in_progress after current one completes [5.54ms]
issue_links > sqlite storage issue todos and links > create and get issue link [5.75ms]
issue_links > sqlite storage issue todos and links > get non-existent issue link returns null [5.43ms]
issue_links > sqlite storage issue todos and links > duplicate issue link id throws ConstraintError [5.59ms]
issue_links > sqlite storage issue todos and links > listIssueLinksFrom returns links ordered by createdAt [5.80ms]
issue_links > sqlite storage issue todos and links > listIssueLinksTo returns links ordered by createdAt [5.73ms]
issue_links > sqlite storage issue todos and links > listIssueLinksForProject returns only matching project links [5.83ms]
issue_links > sqlite storage issue todos and links > listIssueLinksForProject paginates by cursor [5.92ms]
issue_links > sqlite storage issue todos and links > delete issue link removes it [5.68ms]
issue_links > sqlite storage issue todos and links > delete non-existent issue link throws NotFoundError [5.52ms]
cascade delete > sqlite storage issue todos and links > deleting an issue cascades to issue_todos [5.72ms]
cascade delete > sqlite storage issue todos and links > deleting an issue cascades to outgoing and incoming issue_links [5.86ms]
session kind filter > createSession stores kind and getSession returns it [9.90ms]
session kind filter > createSession defaults kind to chat [5.14ms]
session kind filter > listSessions filters by kind [6.15ms]
session kind filter > listSessions without kind filter returns all sessions [5.25ms]
workflow invocations > createWorkflowInvocation and getWorkflowInvocation round-trip [6.12ms]
workflow invocations > createWorkflowInvocation with no steps [5.32ms]
workflow invocations > createWorkflowInvocation with session FK [5.34ms]
workflow invocations > createWorkflowInvocation duplicate id throws ConstraintError [5.39ms]
workflow invocations > createWorkflowInvocation is transactional — duplicate step PK rolls back invocation [5.32ms]
workflow invocations > getWorkflowInvocation returns null for missing id [5.07ms]
workflow invocations > getWorkflowInvocation returns steps ordered by idx [5.35ms]
workflow invocations > listWorkflowInvocations returns invocations for project [8.95ms]
workflow invocations > listWorkflowInvocations filters by workflow name [5.43ms]
workflow invocations > listWorkflowInvocations filters by invokerKind [5.32ms]
workflow invocations > listWorkflowInvocations filters by invokerId [5.44ms]
workflow invocations > listWorkflowInvocations filters by state [5.36ms]
workflow invocations > listWorkflowInvocations paginates [5.69ms]
workflow invocations > listWorkflowInvocations returns empty for unknown project [5.16ms]
workflow invocations > listWorkflowInvocations combines filters [5.50ms]
workflow invocations > updateWorkflowInvocation updates state [5.80ms]
workflow invocations > updateWorkflowInvocation updates all fields [5.39ms]
workflow invocations > updateWorkflowInvocation can clear nullable fields [5.39ms]
workflow invocations > updateWorkflowInvocation with empty updates is a no-op [5.20ms]
workflow invocations > updateWorkflowInvocation throws NotFoundError for missing id [5.19ms]
workflow invocations > updateWorkflowInvocationStep updates status [5.44ms]
workflow invocations > updateWorkflowInvocationStep updates all fields [5.37ms]
workflow invocations > updateWorkflowInvocationStep can set error [5.30ms]
workflow invocations > updateWorkflowInvocationStep with empty updates is a no-op [5.20ms]
workflow invocations > updateWorkflowInvocationStep throws NotFoundError for missing id [5.12ms]
workflow invocations > countActiveInvocations counts non-terminal states [5.86ms]
workflow invocations > countActiveInvocations scopes to project [5.38ms]
workflow invocations > countActiveInvocations returns 0 for unknown project [5.04ms]
workflow invocations > countActiveInvocationsByInvoker counts by invoker identity [5.57ms]
workflow invocations > countActiveInvocationsByInvoker excludes all terminal states [15.58ms]
workflow uploads > createWorkflowUpload and getWorkflowUpload round-trip [5.46ms]
workflow uploads > createWorkflowUpload duplicate token throws ConstraintError [5.31ms]
workflow uploads > getWorkflowUpload returns null for missing token [5.18ms]
workflow uploads > consumeWorkflowUpload sets consumed_by [5.40ms]
workflow uploads > consumeWorkflowUpload is idempotent-safe — already consumed throws NotFoundError [5.48ms]
workflow uploads > consumeWorkflowUpload throws NotFoundError for missing token [5.18ms]
workflow uploads > deleteExpiredWorkflowUploads removes expired unconsumed uploads [5.69ms]
workflow uploads > deleteExpiredWorkflowUploads skips consumed uploads even if expired [5.61ms]
workflow uploads > deleteExpiredWorkflowUploads returns 0 when nothing to delete [5.19ms]
workflow uploads > deleteExpiredWorkflowUploads boundary — exactly at cutoff not deleted [5.40ms]
listNonTerminalWorkflowInvocations > returns empty array when no invocations [5.45ms]
listNonTerminalWorkflowInvocations > returns only non-terminal invocations [6.07ms]
listNonTerminalWorkflowInvocations > returns invocations across projects [5.90ms]
initialization > sqlite storage > creates database with WAL mode [8.65ms]
initialization > sqlite storage > creates schema_version table with current version [5.85ms]
initialization > sqlite storage > creates all 28 tables [5.93ms]
initialization > sqlite storage > idempotent — opening same DB twice does not fail [5.67ms]
initialization > sqlite storage > foreign keys are enforced [5.39ms]
sessions > sqlite storage > create and get session [5.25ms]
sessions > sqlite storage > get non-existent session returns null [5.15ms]
sessions > sqlite storage > duplicate session id throws ConstraintError [5.28ms]
sessions > sqlite storage > update session state [5.24ms]
sessions > sqlite storage > update session endedAt [5.24ms]
sessions > sqlite storage > update session name [5.43ms]
sessions > sqlite storage > clear session name with null [5.59ms]
sessions > sqlite storage > create session with name [5.50ms]
sessions > sqlite storage > update non-existent session throws NotFoundError [5.59ms]
sessions > sqlite storage > list sessions returns all [5.64ms]
sessions > sqlite storage > list sessions filters by projectId [5.73ms]
sessions > sqlite storage > list sessions filters by createdBy [5.59ms]
sessions > sqlite storage > list sessions filters by state [5.71ms]
sessions > sqlite storage > list sessions paginates with cursor [5.90ms]
sessions > sqlite storage > count sessions by project excludes ended sessions [5.95ms]
sessions > sqlite storage > count sessions by operator excludes ended sessions [5.59ms]
sessions > sqlite storage > forkedFrom is persisted [5.62ms]
runs > sqlite storage > create and get run [5.65ms]
runs > sqlite storage > get non-existent run returns null [5.43ms]
runs > sqlite storage > duplicate run id throws ConstraintError [5.60ms]
runs > sqlite storage > update run state and completion [7.93ms]
runs > sqlite storage > update run with error [5.31ms]
runs > sqlite storage > update non-existent run throws NotFoundError [5.34ms]
runs > sqlite storage > list runs for session [5.36ms]
runs > sqlite storage > list runs paginates [5.50ms]
runs > sqlite storage > count runs for session [5.27ms]
runs > sqlite storage > run error round-trips through JSON [5.15ms]
runs > sqlite storage > getProjectStats returns session aggregates, 24h activity, and recent runs [7.00ms]
messages > sqlite storage > create and list messages [5.94ms]
messages > sqlite storage > supersede messages after cursor [6.02ms]
messages > sqlite storage > messages paginate with cursor [5.98ms]
messages > sqlite storage > message metadata round-trips through JSON [5.75ms]
messages > sqlite storage > message with runId [5.59ms]
messages > sqlite storage > created_by round-trips for operator messages [5.72ms]
messages > sqlite storage > created_by defaults to null when not set [5.69ms]
checkpoints > sqlite storage > create and get checkpoint [8.37ms]
checkpoints > sqlite storage > get non-existent checkpoint returns null [5.29ms]
checkpoints > sqlite storage > update checkpoint resumed [5.44ms]
checkpoints > sqlite storage > update checkpoint rolled back [5.40ms]
checkpoints > sqlite storage > update checkpoint superseded [5.34ms]
checkpoints > sqlite storage > update non-existent checkpoint throws NotFoundError [5.27ms]
checkpoints > sqlite storage > list checkpoints for session [5.48ms]
checkpoints > sqlite storage > count checkpoints [5.36ms]
checkpoints > sqlite storage > rolledBack round-trips as boolean [5.25ms]
checkpoints > sqlite storage > createdBy values persist correctly [5.28ms]
subagent invocations > sqlite storage > create and get subagent invocation [5.39ms]
subagent invocations > sqlite storage > get non-existent returns null [5.35ms]
subagent invocations > sqlite storage > update subagent invocation state [5.72ms]
subagent invocations > sqlite storage > update non-existent throws NotFoundError [5.64ms]
subagent invocations > sqlite storage > list subagent invocations for run [5.86ms]
subagent invocations > sqlite storage > cageId null when uncaged [26.38ms]
tool calls > sqlite storage > create and get tool call [5.77ms]
tool calls > sqlite storage > get non-existent returns null [5.48ms]
tool calls > sqlite storage > update tool call completion [5.77ms]
tool calls > sqlite storage > update non-existent throws NotFoundError [5.56ms]
tool calls > sqlite storage > list tool calls for run [8.51ms]
tool calls > sqlite storage > tool calls paginate [5.62ms]
pty transcripts > sqlite storage > create and list pty transcripts [5.51ms]
pty transcripts > sqlite storage > empty list for unknown run [5.37ms]
pty transcripts > sqlite storage > multiple transcripts per run [5.41ms]
prompt edits > sqlite storage > create and list prompt edits [5.44ms]
prompt edits > sqlite storage > empty list for unknown checkpoint [5.29ms]
prompt edits > sqlite storage > multiple edits per checkpoint [5.39ms]
edge cases > sqlite storage > empty updates are no-ops (runs) [5.26ms]
edge cases > sqlite storage > empty updates are no-ops (checkpoints) [5.27ms]
edge cases > sqlite storage > page limit clamped to max 200 [5.20ms]
edge cases > sqlite storage > page limit minimum 1 [5.22ms]
edge cases > sqlite storage > close is idempotent [5.41ms]
edge cases > sqlite storage > supersedeMessagesAfter returns 0 when no messages match [5.51ms]
errors module > sqlite storage > StorageError has correct name [5.50ms]
errors module > sqlite storage > NotFoundError includes entity info [5.39ms]
errors module > sqlite storage > ConstraintError preserves cause [5.45ms]
task instances > sqlite storage > create and get task instance [5.72ms]
task instances > sqlite storage > get returns null for missing instance [5.50ms]
task instances > sqlite storage > duplicate create throws ConstraintError [5.60ms]
task instances > sqlite storage > update task instance state and exit [5.68ms]
task instances > sqlite storage > update nonexistent instance throws NotFoundError [5.59ms]
task instances > sqlite storage > update with empty changes is no-op [5.50ms]
task instances > sqlite storage > update tmux fields [5.67ms]
task instances > sqlite storage > delete task instance [5.60ms]
task instances > sqlite storage > delete nonexistent instance throws NotFoundError [5.63ms]
task instances > sqlite storage > list task instances by project [7.53ms]
task instances > sqlite storage > list task instances by state [5.27ms]
task instances > sqlite storage > list task instances respects pagination limit [5.40ms]
task instances > sqlite storage > count task instances by project [5.36ms]
task instances > sqlite storage > stores and retrieves all fields including nulls [5.18ms]
task instances > sqlite storage > stores and retrieves instance with all null optional fields [5.22ms]
task transcripts > sqlite storage > create and list task transcript [5.34ms]
task transcripts > sqlite storage > empty list for unknown task instance [5.23ms]
task transcripts > sqlite storage > multiple transcripts per task instance [5.63ms]
task transcripts > sqlite storage > duplicate id throws ConstraintError [5.88ms]
task transcripts > sqlite storage > foreign key to nonexistent task instance fails [5.54ms]
task transcripts > sqlite storage > large transcript blob round-trips correctly [7.95ms]
guests > sqlite storage > createGuest + getGuest round-trip [5.66ms]
guests > sqlite storage > getGuestByHandle [5.60ms]
guests > sqlite storage > listGuests with status filter and pagination [5.93ms]
guests > sqlite storage > updateGuest handle, displayName, passwordHash, status changes [5.61ms]
guests > sqlite storage > updateGuest throws ConstraintError on duplicate handle [5.69ms]
guests > sqlite storage > deleteGuest + cascade to invites, sessions, grants [6.09ms]
guests > sqlite storage > createGuest throws ConstraintError on duplicate userId [5.60ms]
guests > sqlite storage > createGuest throws ConstraintError on duplicate handle [5.47ms]
guests > sqlite storage > getGuest returns null for missing [5.34ms]
guest invites > sqlite storage > createGuestInvite + getGuestInvite round-trip [5.52ms]
guest invites > sqlite storage > deleteGuestInvite [5.57ms]
guest invites > sqlite storage > deleteGuestInvitesByUser [5.75ms]
guest invites > sqlite storage > deleteExpiredGuestInvites returns count of deleted [5.80ms]
guest invites > sqlite storage > getGuestInvite returns null for missing [5.37ms]
guest sessions > sqlite storage > createGuestSession + getGuestSession round-trip [5.56ms]
guest sessions > sqlite storage > updateGuestSession lastActiveAt [5.54ms]
guest sessions > sqlite storage > deleteGuestSession [5.52ms]
guest sessions > sqlite storage > deleteGuestSessionsByUser [5.81ms]
guest sessions > sqlite storage > updateGuestSession throws NotFoundError for missing [5.50ms]
guest sessions > sqlite storage > getGuestSession returns null for missing [5.41ms]
project guest grants > sqlite storage > createProjectGuestGrant + getProjectGuestGrant round-trip [5.72ms]
project guest grants > sqlite storage > JSON round-trip for permissionSet [5.57ms]
project guest grants > sqlite storage > listProjectGuestGrants by project [6.03ms]
project guest grants > sqlite storage > listGuestGrants by user [5.74ms]
project guest grants > sqlite storage > updateProjectGuestGrant new permissionSet, notes [5.84ms]
project guest grants > sqlite storage > deleteProjectGuestGrant [5.64ms]
project guest grants > sqlite storage > deleteProjectGuestGrant throws NotFoundError for missing [5.40ms]
project guest grants > sqlite storage > getProjectGuestGrant returns null for missing [5.40ms]
model overrides > sqlite storage > getModelOverrides returns empty for no overrides [5.47ms]
model overrides > sqlite storage > upsert and get single override [5.60ms]
model overrides > sqlite storage > upsert multiple overrides for same model [5.52ms]
model overrides > sqlite storage > upsert replaces existing override (idempotent) [5.49ms]
model overrides > sqlite storage > overrides are isolated per provider [5.45ms]
model overrides > sqlite storage > overrides are isolated per model [5.53ms]
model overrides > sqlite storage > deleteModelOverride removes single field [5.66ms]
model overrides > sqlite storage > deleteModelOverride throws NotFoundError for missing [5.42ms]
model overrides > sqlite storage > deleteAllModelOverrides removes all fields for a model [5.64ms]
model overrides > sqlite storage > deleteAllModelOverrides returns 0 when none exist [5.40ms]
provider spend limits > sqlite storage > getSpendLimit returns null when not set [5.41ms]
provider spend limits > sqlite storage > upsert and get spend limit [5.58ms]
provider spend limits > sqlite storage > upsert replaces existing spend limit [5.53ms]
provider spend limits > sqlite storage > spend limit with percentage-based windows [5.64ms]
provider spend limits > sqlite storage > deleteSpendLimit removes the limit [5.63ms]
provider spend limits > sqlite storage > deleteSpendLimit throws NotFoundError for missing [5.39ms]
provider spend limits > sqlite storage > limits are isolated per provider [5.55ms]
provider spend events > sqlite storage > createSpendEvent and sumSpendByWindow [5.67ms]
provider spend events > sqlite storage > sumSpendByWindow returns null when no events [5.46ms]
provider spend events > sqlite storage > sumSpendByWindow isolates by provider [5.58ms]
provider spend events > sqlite storage > sumSpendByWindow isolates by window key [5.63ms]
provider spend events > sqlite storage > sumSpendByWindow7d with 7-day window [5.51ms]
provider spend events > sqlite storage > sumSpendByWindow7d returns null when no events [5.42ms]
provider usage cache > sqlite storage > getUsageCache returns null when not cached [5.38ms]
provider usage cache > sqlite storage > setUsageCache and getUsageCache [5.57ms]
provider usage cache > sqlite storage > setUsageCache replaces existing cache [5.49ms]
provider usage cache > sqlite storage > deleteUsageCache removes the cache [5.52ms]
provider usage cache > sqlite storage > deleteUsageCache is idempotent for missing provider [5.34ms]
provider usage cache > sqlite storage > usage cache is isolated per provider [5.49ms]
notification storage helpers > stores and lists push subscriptions without exposing secrets [12.26ms]
notification storage helpers > deletes and reaps subscriptions by owner [5.53ms]
notification storage helpers > persists per-session bell values [5.46ms]

Mentioned in

Type Document
adr ADR-0024: Context compaction is kaged-owned, layered, observable, and operator-tunable
adr ADR-0026: Cost management, model metadata overrides, and provider usage tracking
spec Spec: Agent Harness
spec Spec: Issues
spec Spec: LLM Provider Interface
spec Spec: Operational Logging
spec Spec: Session notifications (daemon side)
spec Spec: Session Manager
spec Spec: Users, Roles, and Project Grants
spec Spec: Workflows