`one-memory capture <host>` ran as a separate short-lived process on every
hook and, on every call, constructed `EvidenceStore` (re-creating the retired
evidence/FTS tables on an SDK-authority home), put Evidence rows and assembled
write jobs: three write transactions outside Core's single writer, contending
for SQLite's file lock with Core and with other hosts' hooks.
The hook process now never opens the database. It checks the migration fence,
reads the hook JSON and posts it to the running Core over loopback with the
runtime token (`POST /api/v1/live-capture/{source}`, 1.5 s budget); any
failure drops the turn silently with no local fallback. Core applies the
grant, sync switch, rejection counting, automated-session and Cursor/Claude
rules and stages the lines in-process through the live file-sync path
(`materialize_write_input` -> `stage_sdk_input` -> `finalize_sdk_file`, live
priority). No Evidence table is involved.
The hook and live file sync gave one message different identities (the hook
has no workspace and often no message id) and separate assembly rows, so a
turn both saw was written to the SDK twice. Hook input for a source live sync
reads from its own files is now left to that path; only a source without
file polling is staged from its hook.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under a long live-sync history, writes stalled behind "database is locked"
refusals, durable leases lapsed, and the App stopped answering for tens of
seconds at a time.
- import_jobs is bounded: finished (completed/cancelled) sync jobs are
pruned to the newest 20 per (user, source), with their issues and skip
counts, in bounded batches at startup and every 10 minutes. History jobs
and every unfinished job are kept.
- Job lookups are SQL (find_jobs / latest_job) instead of reading the whole
table, served by new indexes in schema migration 63. GET
/api/v1/import-jobs keeps its shape and order.
- The durable write queue runs claim, settle and maintenance in its own pool
and lease renewal in a dedicated one, so bulk work cannot starve a lease.
The single writer and its line are unchanged.
- abandon, resume, enqueue, pause, cancel, shutdown and startup resume make
their database calls off the loop; the file watcher resolves changed
paths off the loop; revoke reads and writes its grant off the loop.
- The WAL cadence checkpoint is requested from the write path and run by one
checkpointer thread instead of inline on the writing thread.
- The durable drain is supervised: an unexpected exit is reported with its
stack and the drain restarts with capped backoff under a new lease owner.
memory-processing and memhub status show write_drain and
write_drain_error. Contained per-job failures are reported with stacks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Lite context search, recall and the Host Bridge return every raw vector
hit above the floor, ranked by score, over active and shadow raws. The
turn view shows the turns containing the query, or else the hit's
closest turn, instead of dropping semantic hits. Pro and ultra raw
search stays active-only.
A new test runs the raw routes in a child interpreter against the
installed hy-memory wheel, and the route-test fake SDK now rejects
search kwargs the pinned release does not accept.
The lite raw-turn page projects only raws newly put on top instead of
re-listing the whole raw layer on every poll.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>