# Release 0.4.6 — Detect an engine/core artifact mismatch before compaction runs

**Coordinated packages:** `ds4-context-core`, `ds4-context-reference-adapter`, and `ds4-context-engine` 0.4.6.
**Implementation commit:** `225078f`.

## Summary

Diagnostic and packaging patch. The core now exports `CORE_VERSION` and the
extension verifies, at session start and at the beginning of every compaction
attempt, that the core it actually loaded matches its own version and exposes the
entry points it calls. A mismatch — typically a core rebuilt in a checkout while
Pi kept the previously loaded module instance, which a `/reload` does not
replace — no longer surfaces deep inside summary generation as
`(0 , _summaryContract.x) is not a function`. It reports one actionable line,
keeps the DS4 compaction layer inert instead of failing mid-generation, and
leaves Pi compacting with its own default. Validation strictness, the
eight-bullet and 25% repair bounds, the fail-closed fallback, the SQLite schema,
canonical JSONL history and every provider-facing default are unchanged.

## Changes

- `packages/core/src/version.ts` (new): `CORE_VERSION`, re-exported from the core
  package root and bumped with the two adapters by the coordinated release
  process.
- `src/pi-adapter/core-compatibility.ts` (new): `inspectCoreCompatibility`
  (pure), `coreCompatibilityIssues` (real probe), `coreCompatibilityMessage` and
  `assertCoreCompatibility`. The probe compares `CORE_VERSION` with
  `EXTENSION_VERSION` and checks that `buildSummaryPrompt` and
  `classifyUnsupportedExactValueSpans` are functions, naming the exact missing
  entry point.
- `src/extension/runtime.ts`: session start runs the probe once. On a mismatch it
  logs `runtime.core_incompatible`, notifies a single line and sets the runtime
  `lastError`; the compaction coordinator is then not created, so `/context
  compaction` reports `enabled: false` with that reason instead of a half-run
  batch. `RuntimeDependencies` gained an optional `coreCompatibility` seam for
  tests.
- `src/pi-adapter/compaction-coordinator.ts`: the same guard runs as the first
  statement of the guarded compaction attempt, so the existing coordinator catch
  turns it into the ordinary `compaction.custom_fallback` warning. The
  coordinator gained an optional `checkCoreCompatibility` seam.
- `tests/unit/core-compatibility.test.ts` (new, 6 cases): synchronized core
  accepted, older version named on both sides, missing `CORE_VERSION` reported,
  missing entry point named instead of an `is not a function`, single-line remedy,
  and the real probe passing against the core this repository resolves.
- `tests/unit/compaction-optimizations.test.ts`: a simulated stale core reaches
  `beforeCompact` as a fallback warning with no provider call.
- `tests/integration/extension.test.ts`: with a simulated stale core, session
  start warns with the remedy, `/context compaction` diagnostics report
  `enabled: false` and the reason, and the compaction hook stays inert.
- `docs/COMPACTION.md`, `docs/ADR/067-core-version-guard.md` and the ADR index
  record the decision.

## Why

A production machine reported, immediately after a Pi `/reload`:

```text
Warning: DS4 compaction unavailable; using Pi default.
(0 , _summaryContract.classifyUnsupportedExactValueSpans) is not a function
```

Every artifact on disk was current: the checkout's `packages/core/dist` and the
npm-installed `ds4-context-core@0.4.3` both export the symbol. Pi loads extension
sources through jiti and re-imports the extension entry when its cache generation
changes, while modules already evaluated for that process keep their loaded
instance, so an extension source newer than the core module it resolved calls a
symbol the loaded core does not have. The failure consumed the whole compaction
attempt and pointed at DS4 rather than at the process state.

The guard converts that class of mismatch into a single line that names both
versions, the missing entry point and the two remedies — rebuild the checkout
(`npm ci && npm run build:core && npm run build:adapters`) or update the installed
package (`pi update --extensions`) — followed by the step that actually makes a
rebuilt core visible: restart Pi. It is deliberately not on the extension load
path, because Pi treats an extension load error as fatal and a stale core must
never keep Pi from starting, and it is detection only: nothing about validation,
repair bounds or the fail-closed decision changes
([ADR 067](ADR/067-core-version-guard.md)).

## Privacy and safety

- The guard reads module state only: two version strings and the presence of two
  exported functions. It never reads session JSONL, the SQLite projection,
  credentials, provider payloads or prompt text, and the message contains no
  session content.
- `runtime.core_incompatible` and the fallback warning carry the same message
  that the user sees; no span text, file content or provider data is logged.
- No provider call is introduced by this release, and none was made to prepare
  it.

## Compatibility and persistence

- No configuration key is added or default changed. `CORE_VERSION` is additive;
  a core older than 0.4.6 simply fails the version probe, which is what the guard
  reports.
- SQLite schema 16, migrations, the Pi JSONL boundary, tool contracts and the
  reference adapter's public surface are untouched.
- Version equality is strict because the three packages are released in lockstep:
  after bumping versions, the core must be rebuilt before the extension runs.

## Measured scope and limitations

- Detection only. The guard cannot invalidate Pi's module cache: on a machine
  whose running Pi already holds a stale core, the next `/reload` reports the
  mismatch and disables the DS4 compaction layer, and the DS4 core in that
  process is only replaced by restarting Pi.
- The guard covers the entry points the extension already calls. A future core
  symbol the engine starts requiring must be added to `REQUIRED_CORE_EXPORTS`
  (or fail through the version check when versions differ).
- Shipping the extension as a self-contained artifact would remove the
  process-cache dependency entirely; that packaging decision is left open in
  ADR 067.

## Validation

- `npm run check` on the release commit: builds, `tsc --noEmit`, and
  **100 test files / 642 tests passed** (8 new tests: 6 unit guard cases, 1
  coordinator case, 1 extension integration case).
- `npm run pack:check` in a clean consumer: `ds4-context-core@0.4.6`
  (251 files), `ds4-context-reference-adapter@0.4.6` (7 files) and
  `ds4-context-engine@0.4.6` (108 files).
- `npm run quality:compare`: candidate `task-weighted-v0.2-candidate` 0.9875
  against the frozen baseline `static-ranking-v0.1` 0.808156, unchanged from
  0.4.5.
- `npm run schema:context-persistence` (`passed: true`).
- No provider calls are involved in this release procedure. `jev_verify` is not
  available in this environment (project verification disabled), so the checks
  above were run directly.

## Publication and registry verification

Published manually in dependency order from `92912a1`: `ds4-context-core@0.4.6`,
then `ds4-context-reference-adapter@0.4.6`, then `ds4-context-engine@0.4.6`, all
with the default `latest` tag, after `npm run pack:check` on the same commit.

The first two `npm run registry:check -- 0.4.6` attempts, each with a fresh npm
cache, failed with `ETARGET No matching version found for
ds4-context-core@0.4.6` — the known registry propagation delay after a publish,
not a packaging fault. Once both `npm view ds4-context-core@0.4.6 version` and
`npm view ds4-context-engine@0.4.6 version` resolved, the check reported
"Verified all DS4 registry packages at exact version 0.4.6": all three packages
install in a clean consumer, the exact adapter/core dependencies resolve, the
public core and KV exports import, the compiled reference conformance and
packaged quality corpus run, the `ds4-context-storage` CLI shim responds, and the
published Pi extension starts against isolated offline RPC state. 
`npm view <package> dist-tags.latest` resolves to 0.4.6 for all three packages.

Annotated tag `v0.4.6` and the GitHub Release were created from `92912a1`: 
<https://github.com/Alucard24/ds4-context-engine/releases/tag/v0.4.6>. No session
data, credentials, provider payloads or prompt text were read or written while
preparing this release, and no provider call is involved in the release
procedure.
