Slice 3: session retention that relocates + the generated session index (#795) - #815
Slice 3: session retention that relocates + the generated session index (#795)#815aarontrowbridge wants to merge 7 commits into
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The archive cutoff is a workspace preference, not a constant: $AMICODE_OPS_DIR/session-retention.json, default 30 days, failing safe on absent/malformed/out-of-range files. Plus the deterministic session-index renderer (used by the index verb in the next commit). Issue #795, spec-20260905-045114 D4.
…(D4 slice 3, AC 1) The archive visibility rules the product respects, as CLI verbs over the session table (dry-run-by-default archive, --apply to relocate; restore clears the one field; --archived is the explicit opt-in). node:sqlite stays out of vitest's graph via a lazy import; DB resolution mirrors the open-threads skill (--db → $OPENCODE_DB → XDG default). Issue #795.
The generated index is complete (every DB row exactly once), carries directory provenance (full paths in the distribution header, basenames in the table), reflects per-row archive state, and is deterministic apart from the generated-at stamp. Verified against seeded copy DBs. Issue #795.
…C 5) The default page is bounded (100), --limit is honored up to a hard cap, cursor walking covers the whole store exactly once, and archived rows never leak into a default walk. D4: the boot fetch stays bounded as the active list grows. Issue #795.
…3, AC 2) Archive --apply + restore leave the vault ledger plane, the coordination board, and the claims ledger byte-identical, write no vault-plane files, and change exactly one session column (time_archived) with project rows untouched. Verified by full-row snapshot diffing on a seeded copy DB. Issue #795.
…D4 slice 3, AC 3) prefs --days writes session-retention.json; archive --apply honors it (7-day cutoff verified against a seeded DB); --days overrides per call without writing. Issue #795.
…ode 20 support CI pins node 20 (ci.yml), where node:sqlite does not exist (added 22.5) — the verb and all 11 bundle tests failed on the fast check. Replace the node:sqlite access with a python3 stdlib sqlite3 bridge (sqlite_bridge.ts): zero new dependencies, works on the CI pin and everything newer, and it is the store's existing reader convention (open-threads: file:<db>?mode=ro, timeout=5; AMICO_PYTHON→python3 per pasqal_launch). One python invocation per verb operation, statements batched, JSON over stdio; reads open read-only, writes commit through the real sqlite engine (no whole-file rewrite, unlike a WASM driver). Verified under node 20.20.2 locally (the CI version): 18/18 sessions tests, full amico-run suite 1363 passed (the 1 failure is the pre-existing env-leak in agent_spawn), and a read-only live-DB smoke (list + index). Issue #795.
792c616 to
e1662e2
Compare
CI status after the node-20 fix (evidence trail)This slice's package is green on CI node 20: after the python3-sqlite bridge ( The remaining
So the durable-record design (A2) is working as intended — it's telling us the live boot didn't prove the contract on the runner — and the cleanup race hides why. Suggested follow-ups for #808's owners (not done here, per no-drive-by discipline): a longer timeout on The fixture failure does not gate the slice's acceptance criteria: all five are bound to |
What
The D4 product layer (spec-20260905-045114, slice 3, issue #795): session retention as a CLI contract instead of hand SQL, plus the generated session index that retires the hand-written SESSION-INDEX.md anti-pattern.
New verb on the
amicorouter (packages/amico-run):amico sessionslist [--archived] [--limit] [--cursor] [--db]— the visibility rules the product respects: default excludes archived,--archivedis the explicit opt-in, pages are bounded (default 100, hard cap 1000), recent tail first.archive [--days <n>] [--apply]— relocates, never deletes: stamps the engine'stime_archived. Dry-run by default (an agent running it against the live hub DB without--applymoves nothing). Deletion is out of the vocabulary.restore <id>— clears the one field; idempotent on active sessions, 64 on unknown ids.index [--out] [--db]— regenerates SESSION-INDEX.md from the DB: complete (every row exactly once), directory provenance (full paths + counts in the distribution header, basenames in the table), per-row archive state, deterministic apart from the stamp.prefs [--days]— the archive cutoff as a workspace preference:$AMICODE_OPS_DIR/session-retention.json, default 30 days, failing safe on absent/malformed/out-of-range files.DB resolution mirrors the open-threads skill (the store's other reader):
--db→ $OPENCODE_DB → XDG default. Reads open read-only; the vault ledger plane and the coordination board are never touched (D4 disjointness, tested).Acceptance criteria (issue #795)
sessions_verb.test.tsvisibility-matrix block (bundle, seeded DB)time_archivedcolumnLive smoke (read-only, no writes to the live DB):
amico sessions listandsessions indexagainst the real hub DB — 1504 sessions indexed, 741 visible · 763 archived (the 2026-09-05 consolidation's counts, now generated).CI status (after the node-20 portability fix)
sqlite3bridge (sqlite_bridge.ts), notnode:sqlite. Why: CI pins node 20 (ci.yml, all jobs) wherenode:sqlitedoes not exist (added in 22.5), engines say>= 20, and the product's other DB reader (open-threads) already uses python3 stdlib sqlite3 — zero new dependencies, one code path for node 20 and 22+, and writes go through the real sqlite engine (no whole-file rewrite, unlike a WASM driver). Interpreter resolution reuses the product's existing convention ($AMICO_PYTHON→python3, perpasqal_launch.ts).amico-runsuite at the pre-slice baseline, typecheck green, read-only live-DB smoke (list + index) under node 20.amico-rungreen in the fast job (81 files passed, run 33970818654). The remainingfastred is the Slice 4: posture-aware context injection — the Active mode block #808/feat(mode-block): posture-aware context injection — the Active mode block (#808) #814 session-API fixture (mode_block.test.tsH4), failing on this PR 4/4 while passing on main — evidence it is not this branch: the merge-vs-main delta is 5 amico-run files only; the fixture passes 3/3 locally on both pristine main and this branch's merge state; on CI it recordsrecords_seen: 0(probe plugin never loaded) and dies in a cleanuprmSyncrace (ENOTEMPTY) that masks the real boot timeout. Full evidence trail + suggested Slice 4: posture-aware context injection — the Active mode block #808 follow-ups in the CI comment.Not green / notes
agent_spawn.test.ts(1 test) fails in this environment pre-existing at origin/main: the session env leaksOPENCODE_CONFIG_CONTENT/OPENCODE_DBinto a real-spawn assertion. Unrelated to this branch; suite is otherwise 1363 passed / 1 skipped.restorehere clears the field only. Theprojecttable'sworktreecolumn is what the re-resolution will key on.node:sqlite, so the module graph can't load it; the verb lazy-imports it at call time (tests exercise the esbuild bundle, where node loads it natively). On node < 22.5 the verb degrades to an honest 64 with a message.archivedquery param) already exist in the vendored engine's SDK surface — used as-is, nothing forked.Closes #795 (on review).