# Release 0.4.0 — Per-project databases with shared token calibration

**Coordinated packages:** `ds4-context-core`, `ds4-context-reference-adapter`, and `ds4-context-engine` 0.4.0.
**Implementation commit:** `2c2e248`.
**Decision record:** [ADR 064](../ADR/064-per-project-databases-with-shared-calibration.md).

## Summary

Adds the opt-out `storage.scope: "agent" | "project"` setting and defaults it to
`project`. Each trusted canonical project root now gets its own SQLite
projection next to the configured agent database, while token calibration stays
in the agent database and remains shared across projects. `storage.scope:
"agent"` restores the previous single-file layout. The reference adapter and Pi
extension continue to depend exactly on the matching core version.

## Changes

- `storage.scope: "project"` (new default) derives one database per trusted
  canonical project root at `projects/<sha256(root)[0..32]>.db`, next to
  `storage.databasePath`. Untrusted projects, broad roots (home directory,
  filesystem root) and any resolution failure fall back to the agent database.
- Both files receive the same schema and the same migrations; migrations 1–15
  are untouched and there is no schema fork. The project database holds the
  session index, project index, context manifests, summary graph, memory/pin
  projections, embeddings, quality samples and artifact metadata; the agent
  database holds `token_calibration`.
- With the split, a calibration sample is written to the agent database with
  `manifest_id = NULL`, exactly once per manifest. The two writes are
  intentionally not one cross-database transaction: a lost calibration sample is
  harmless, a lost manifest/usage consistency is not. In `agent` scope the
  previous single transaction is unchanged.
- Artifact object bytes move to `projects/artifacts/<project-digest>/` under
  project scope so the orphan garbage collector, which only sees references in
  the current database, can never delete another project's objects.
- `/context storage` and `/context diagnostics` report the active project
  database and, when split, the shared agent database. Storage maintenance
  stays per file: `ds4-context-storage inspect|compact|recover --database <path>`
  must be pointed at each database.
- The previous shared database is left untouched. With the new default, existing
  users cold-start per-project indexes while existing calibration remains
  available in the agent database; project indexes rebuild from canonical Pi
  JSONL, project files and memory/pin `CustomEntry` records.

## Breaking behavior

The default storage layout changes. A pre-existing
`~/.pi/agent/ds4-context/context.db` becomes the agent database and is no longer
the active projection for new sessions. `storage.scope: "agent"` restores the
old single-database behavior. Rows are not migrated between files; the project
databases are derived and rebuildable. Decision D1 of the storage plan ("no
per-session or per-project databases") is superseded by ADR 064 and the plan
keeps the original text with an explicit amendment pointer.

## Measured scope and limitations

`tests/benchmarks/storage-scale.bench.ts` seeds one session with 5,000 /
50,000 / 200,000 entries and measures the paths a session pays. Measured means
on the development machine (Node.js 26.5.1, `node:sqlite`): exact identifier
scan 0.97 / 12.5 / 52.7 ms, exact phrase scan 0.98 / 12.8 / 53.2 ms, FTS
common token 0.14 / 2.3 / 9.0 ms, per-session stats 0.33 / 4.8 / 21.8 ms,
storage diagnostics flat at 0.10 ms, unchanged re-check 1.4 / 2.9 / 7.2 ms.
Growth is real but bounded and tracks single-session size, not file size:
project scope bounds physical growth, lock scope and reset per project, but does
not by itself change the per-session exact-scan profile. See
[storage growth measurements](../STORAGE.md#growth-measurements).

These are local measurements on one host, not portable guarantees. No provider
calls are involved in this release procedure.

## Compatibility

No provider-facing default changes: `chars-v1` remains the default estimator,
`modelAwareness.autoTune` and DS4 native continuation stay disabled. No SQLite
migration, no change to canonical Pi JSONL, privacy consent, native continuation
or the portable runtime-adapter contract. Restart Pi after upgrading so the new
compiled core and session configuration are loaded.

## Validation and publication

On Node 26.5.1, the coordinated release passed `npm run check` (99 Vitest files,
615 tests, TypeScript builds and root typecheck), deterministic
`npm run quality:compare`, the `npm run schema:context-persistence` size bound,
and `npm run pack:check` in a clean consumer after synchronizing both exported
runtime version constants. `git diff --check` was clean and tarball review
contained 247 core files, 7 reference-adapter files and 99 extension files,
none including untracked local state. All three packages were then published to
npm at 0.4.0 in dependency order (`ds4-context-core`, then
`ds4-context-reference-adapter`, then `ds4-context-engine`). After registry
propagation, `npm run registry:check -- 0.4.0` verified the exact-version
artifacts, exact adapter/core dependencies and the packaged extension in a
fresh consumer.
