ds4-context-engine 0.1.1 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,90 @@
1
+ # Learned Ranking
2
+
3
+ M18 adds an optional metadata-only linear ranker while preserving the deterministic static ranker as the universal fallback.
4
+
5
+ ## Modes
6
+
7
+ ```json
8
+ {
9
+ "ranking": {
10
+ "mode": "shadow",
11
+ "modelPath": "ds4-context/ranking-model.json",
12
+ "minimumTrainingSamples": 20,
13
+ "maxTrainingSamples": 10000,
14
+ "maxLatencyMs": 10
15
+ }
16
+ }
17
+ ```
18
+
19
+ - `off` does not load or evaluate a learned model.
20
+ - `shadow` evaluates a valid model, records only aggregate rank disagreement, and keeps static selection unchanged.
21
+ - `active` changes supplemental-candidate ordering only when the checksummed artifact contains a successful promotion report. Missing, incompatible, corrupt, unpromoted, or regressing artifacts fall back to static ranking.
22
+
23
+ `off` is the upgrade default. Privacy filtering, mandatory pins, current-request retention, category budgets, atomic groups, and hard input limits remain authoritative in every mode.
24
+
25
+ ## Bounded feature schema
26
+
27
+ `ranking-features-v1` contains only a source-kind enum and ten finite normalized numbers:
28
+
29
+ - static score;
30
+ - exact-match score;
31
+ - FTS score;
32
+ - vector score;
33
+ - recency;
34
+ - active-branch relation;
35
+ - symbol relation;
36
+ - classification eligibility;
37
+ - token cost;
38
+ - prior selection outcome.
39
+
40
+ All numbers are bounded to `[0, 1]`. Candidate text, excerpts, prompts, file paths, symbols, claims, provider payloads, and credentials are not model features. Stable candidate and repository identities are SHA-256 hashes in canonical labels.
41
+
42
+ ## Canonical labels and local training
43
+
44
+ Explicit feedback is appended through Pi as a classified `ds4-context-ranking-feedback-v1` custom entry:
45
+
46
+ ```text
47
+ /context ranking feedback useful CANDIDATE_ID --classification internal
48
+ /context ranking feedback irrelevant CANDIDATE_ID --classification local-only
49
+ ```
50
+
51
+ Only candidates from the latest managed context are accepted. A feedback entry contains schema/version, feedback ID, timestamp, classification, label source, label, two hashes, and the bounded feature vector. It contains no candidate text. Sanitized replay labels use the same schema with `labelSource: "replay"`.
52
+
53
+ Train a local shadow artifact from the active canonical Pi branch:
54
+
55
+ ```text
56
+ /context ranking train
57
+ ```
58
+
59
+ Training is deterministic for the same unique labels and timestamp, requires both useful and irrelevant examples, and is bounded by `minimumTrainingSamples` and `maxTrainingSamples`. The artifact is written with mode `0600` where supported. Training never calls a provider and does not make the resulting artifact active.
60
+
61
+ ## Artifact integrity and deterministic inference
62
+
63
+ `ranking-model.json` uses schema version `1`, feature version `ranking-features-v1`, algorithm `bounded-linear-centroid-v1`, bounded weights, training counts, a deterministic model ID, and a SHA-256 checksum over its stable JSON payload. Inference uses rounded finite arithmetic and resolves equal scores by static score and then candidate ID.
64
+
65
+ The model artifact is local derived state. Deleting it preserves Pi JSONL labels and restores static ranking. A newly trained artifact can be reconstructed from canonical labels.
66
+
67
+ ## Promotion gate
68
+
69
+ `evaluateRankingPromotion()` in `ds4-context-core/ranking/learned-ranker` evaluates sanitized held-out fixtures. `withRankingPromotion()` seals the resulting report into a new checksummed artifact. Promotion succeeds only when all of these conditions hold:
70
+
71
+ - primary quality score improves;
72
+ - exact-identifier recall does not regress;
73
+ - privacy violations do not increase;
74
+ - atomicity failures do not increase;
75
+ - overflow does not increase;
76
+ - measured p95 latency stays within budget;
77
+ - repeated inference yields identical ordering;
78
+ - the configured minimum number of held-out repositories is represented.
79
+
80
+ An artifact without an eligible report can run in shadow mode but cannot alter context in active mode.
81
+
82
+ ## Diagnostics
83
+
84
+ ```text
85
+ /context ranking
86
+ /context health
87
+ /context manifest
88
+ ```
89
+
90
+ Ranking diagnostics include mode/status, versions, model identity, promotion state, label counts, malformed/duplicate counts, candidate count, top-rank disagreement, pairwise disagreements, mean rank shift, inference duration, and fallback reason. Shadow diagnostics and Context Manifests contain aggregate comparison only—never candidate IDs, labels, features, or text.
@@ -1,6 +1,6 @@
1
1
  # Memory and Persistent Pins
2
2
 
3
- M9 separates durable, user-curated state from conversation history while keeping Pi JSONL canonical.
3
+ M9 separates durable, user-curated state from conversation history while keeping Pi JSONL canonical. M17 optionally reconstructs explicit project-scoped mutations from sibling Pi sessions for the same trusted canonical project.
4
4
 
5
5
  ## Authority and scope
6
6
 
@@ -30,9 +30,12 @@ Pins remain subordinate to system/developer instructions. Memory tells the model
30
30
  /context memory supersede MEMORY_ID [--classification LEVEL] [--source ID,ID] <new claim>
31
31
  /context memory invalidate MEMORY_ID [reason]
32
32
  /context memory expire MEMORY_ID [reason]
33
+ /context memory sources
34
+ /context memory exclude SESSION_ID [reason]
35
+ /context memory include SESSION_ID
33
36
  ```
34
37
 
35
- Arguments support single/double quotes and backslash escaping. `--` ends option parsing. Source entry IDs must be on Pi's active branch. Project scope requires Pi project trust.
38
+ Arguments support single/double quotes and backslash escaping. `--` ends option parsing. Source entry IDs must be on Pi's active branch. Project scope requires Pi project trust. Source exclusion affects only project-scoped contributions and persists until `include`; the active session cannot be newly excluded but can restore a prior exclusion.
36
39
 
37
40
  Mutations are manual-first. Repeating the same normalized pin/claim returns its existing ID without appending another entry.
38
41
 
@@ -60,7 +63,7 @@ No row is silently overwritten. SQLite mutation and materialized tables are disp
60
63
  3. replays all known mutations in timestamp + canonical entry order;
61
64
  4. rebuilds memory, pin, source, lifecycle, and FTS rows transactionally.
62
65
 
63
- Deleting `context.db` and reopening the canonical source session reconstructs its state. Project items from other sessions reappear when those canonical sessions are replayed.
66
+ Deleting `context.db` and reopening the canonical source session reconstructs its state. With `memory.crossSession: true`, DS4 discovers bounded sibling `.jsonl` files, accepts only headers whose `cwd` resolves to the exact trusted canonical project identity, incrementally indexes each source, and reconstructs project items without opening every session manually. No claim is extracted from ordinary conversation text.
64
67
 
65
68
  ## Supersession and contradiction handling
66
69
 
@@ -80,7 +83,7 @@ A conflicting `add` is rejected with the IDs involved. The user must issue expli
80
83
  "Package export mode defaults to SingleFile."
81
84
  ```
82
85
 
83
- The old item remains stored as `superseded` and points to the new active item. During replay, concurrent active records with the same key are both preserved; the deterministic later record is marked `invalid` with a conflict reason rather than replacing the earlier one.
86
+ The old item remains stored as `superseded` and points to the new active item. During replay, records are ordered by timestamp, source session ID, source entry order, mutation ID and mutation entry key. Concurrent active records with the same key are both preserved; the deterministic later record is marked `invalid` with a conflict reason rather than replacing the earlier one. Selected items retain source-session file/ID, mutation entry, creation branch leaf, evidence entries, classification, supersession and contradiction IDs.
84
87
 
85
88
  Pins use the same immutable replacement pattern through `--supersedes`. `/context unpin` records a soft `deleted` lifecycle mutation.
86
89
 
@@ -126,7 +129,7 @@ User text is JSON-quoted. Context Manifests contain IDs, scope, classification,
126
129
 
127
130
  M10 stores an optional classification in the canonical mutation. Before a remote call, a prohibited pin/memory is omitted as a whole and recorded only by ID/classification/reason. Explicit classification cannot be downgraded by markers inside its content. See [`PRIVACY.md`](PRIVACY.md).
128
131
 
129
- ## SQLite schema v9
132
+ ## SQLite schema v9 and v15
130
133
 
131
134
  Schema v9 extends materialized `memory_items` and `pins` with:
132
135
 
@@ -136,6 +139,8 @@ Schema v9 extends materialized `memory_items` and `pins` with:
136
139
 
137
140
  `memory_mutations` and `pin_mutations` reference canonical indexed Pi custom entries. `memory_sources` retains exact scoped entry provenance. `memory_fts` is rebuilt transactionally.
138
141
 
142
+ Schema v15 adds source-branch provenance, per-session project-memory checkpoints, source status and explicit source exclusions. These rows are derived and disposable. Missing, truncated, moved, identity-mismatched or corrupt sibling files are marked unavailable and their unverifiable project-scoped mutations stop contributing; session-scoped state remains isolated and the active session keeps its last transactional projection on refresh failure. Restoration or database deletion causes deterministic replay from JSONL.
143
+
139
144
  Migration preserves legacy materialized rows for inspection. Because they have no canonical mutation entry, a later full replay may discard them; new operations are always event-sourced.
140
145
 
141
146
  ## Diagnostics
@@ -148,6 +153,7 @@ Migration preserves legacy materialized rows for inspection. Because they have n
148
153
  /context excluded
149
154
  /context pins
150
155
  /context memory
156
+ /context memory sources
151
157
  /context health
152
158
  /context rebuild-index
153
159
  ```
@@ -1,6 +1,6 @@
1
1
  # Portable Core
2
2
 
3
- M13 extracts the runtime-neutral implementation into the independently buildable `ds4-context-core` workspace package. The root `ds4-context-engine` package remains the Pi integration.
3
+ M13 extracts the runtime-neutral implementation into the independently buildable `ds4-context-core` workspace package. The root `ds4-context-engine` package remains the Pi integration. M19 adds the versioned adapter contract/conformance kit in core and a separately compiled non-Pi callback/JSONL reference adapter.
4
4
 
5
5
  ## Dependency rule
6
6
 
@@ -14,7 +14,7 @@ ds4-context-core
14
14
 
15
15
  Core never imports an adapter or runtime SDK. The Pi adapter imports core through its public ESM exports.
16
16
 
17
- The core may use Node.js standard-library facilities such as `node:sqlite`, filesystem APIs and cryptographic hashing. Portable means independent of Pi and reusable by another Node-based agent runtime; it does not mean browser-compatible.
17
+ The core may use Node.js standard-library facilities such as `node:sqlite`, filesystem APIs and cryptographic hashing. Portable means independent of every agent runtime SDK and reusable by another Node-based agent runtime; it does not mean browser-compatible.
18
18
 
19
19
  ## Package contents
20
20
 
@@ -44,7 +44,7 @@ The root adapter owns all Pi-specific behavior:
44
44
 
45
45
  ## Adapter responsibilities
46
46
 
47
- A future runtime adapter must:
47
+ Every `runtime-adapter-v1` implementation must:
48
48
 
49
49
  1. preserve its runtime's canonical history and expose stable source identifiers;
50
50
  2. convert native messages to DS4 canonical messages without losing tool-call/result atomicity;
@@ -57,14 +57,18 @@ A future runtime adapter must:
57
57
  9. discard or rebuild SQLite and artifact projections safely;
58
58
  10. fall back to native runtime behavior when operational integration fails.
59
59
 
60
+ The executable contract, independent capability negotiation and framework-neutral seven-case conformance runner are exported from `ds4-context-core/adapter/runtime-adapter` and `ds4-context-core/adapter/conformance`. See [Runtime Adapter Kit](RUNTIME_ADAPTER_KIT.md).
61
+
60
62
  ## Build and exports
61
63
 
62
64
  ```bash
63
65
  npm run build:core
66
+ npm run build:adapters
64
67
  npm run typecheck
65
68
  npm test
66
69
  npm run pack:check
67
70
  npm pack --dry-run --workspace ds4-context-core
71
+ npm pack --dry-run --workspace ds4-context-reference-adapter
68
72
  ```
69
73
 
70
74
  TypeScript sources compile to `packages/core/dist` as ESM JavaScript, source maps and declaration files. The npm package exports a top-level API and fine-grained subpaths such as:
@@ -74,11 +78,11 @@ import { calculateContextBudget } from "ds4-context-core";
74
78
  import { planManagedContext } from "ds4-context-core/planner/context-planner";
75
79
  ```
76
80
 
77
- The Pi package declares an exact same-release dependency on `ds4-context-core`. Release order is therefore core first, adapter second. `npm run pack:check` verifies both tarball inventories, installs them together in a clean temporary consumer, probes core ESM exports and starts the packaged adapter with isolated Pi RPC state. See [Releasing DS4](RELEASING.md) for the publication checklist.
81
+ The Pi and reference packages declare exact same-release dependencies on `ds4-context-core`. Release order is core, reference adapter, then Pi adapter. `npm run pack:check` verifies all three tarball inventories, installs them together in a clean temporary consumer, probes core ESM exports, runs compiled reference conformance and starts the packaged Pi adapter with isolated RPC state. See [Releasing DS4](RELEASING.md) for the publication checklist.
78
82
 
79
83
  ## Enforcement
80
84
 
81
- `tests/unit/portable-core-boundary.test.ts` recursively rejects Pi SDK and adapter imports from core source, then imports the compiled package and exercises portable model/budget policy. Existing integration tests consume core through package exports, so the Pi adapter is tested across the actual package boundary.
85
+ `tests/unit/portable-core-boundary.test.ts` recursively rejects Pi SDK and adapter imports from core source, then imports the compiled package and exercises portable model/budget policy. Runtime-adapter unit tests validate capability isolation and canonical tool groups; the reference package passes the shared conformance runner. Existing integration tests consume core through package exports, so the Pi adapter is tested across the actual package boundary.
82
86
 
83
87
  ## State guarantees
84
88
 
@@ -1,6 +1,6 @@
1
1
  # Project Knowledge
2
2
 
3
- M7 indexes trusted project files as a disposable SQLite projection and injects only task-relevant, hash-current snippets. Live files remain canonical.
3
+ M7 indexes trusted project files as a disposable SQLite projection and injects only task-relevant, hash-current snippets. M15 adds runtime-neutral structural symbol parsing and exact symbol lookup. M16 optionally adds vectors over those structural/text chunks while preserving exact and FTS retrieval. Live files remain canonical.
4
4
 
5
5
  ## Trust boundary
6
6
 
@@ -16,7 +16,9 @@ This is independent of global `project.enabled`: a global setting cannot overrid
16
16
 
17
17
  ## Discovery and exclusions
18
18
 
19
- When Git is available, discovery combines tracked and non-ignored untracked files under `ctx.cwd`. Outside Git, DS4 walks the project tree deterministically. It never follows symbolic links and rejects paths outside the canonical project root.
19
+ When Git is available, discovery combines tracked and non-ignored untracked files under `ctx.cwd`. Outside Git, DS4 walks the project tree deterministically. Discovery stops as soon as the configured file bound is reached and also bounds visited directories. It never follows symbolic links and rejects paths outside the canonical project root.
20
+
21
+ DS4 skips project indexing when `ctx.cwd` is the filesystem root or the user's home directory. This prevents a normal Pi launch from recursively scanning an entire drive or user profile; start Pi inside the intended project directory to enable project knowledge.
20
22
 
21
23
  Default bounds:
22
24
 
@@ -34,29 +36,37 @@ DS4 excludes VCS metadata, `.pi`, dependencies, build outputs, caches, virtual e
34
36
 
35
37
  ## File and snippet index
36
38
 
37
- SQLite schema v7 stores:
39
+ SQLite schema v7 introduced:
38
40
 
39
41
  - `project_states`: canonical project path, Git root/branch/HEAD, dirty flag, changed paths, index time;
40
42
  - `project_files`: path, SHA-256, bytes, mtime, language, indexed Git HEAD, tracked/modified state, lifecycle;
41
- - `project_snippets`: immutable file hash, line range, source, heuristic declarations, token estimate, stale flag;
43
+ - `project_snippets`: immutable file hash, line range, source, token estimate and stale flag;
42
44
  - `project_snippets_fts`: FTS5 content/path/symbol index.
43
45
 
44
- Files are split into overlapping line windows. Heuristic symbols cover class, interface, enum, namespace, record, struct, trait, type, function, common language declarations, and SQL objects. No parser or LLM is needed.
46
+ Schema v12 adds derived structural metadata to each snippet: chunk kind, parser version, symbol ID/name/kind, qualified name, signature, parent symbol, imports and references. Exact-name indexes remain disposable and rebuild from live project files. Schema v13 stores separately keyed derived vectors; a file-hash change prunes only vectors for no-longer-current chunks, while unrelated source and embedding-profile rows remain intact.
47
+
48
+ `ds4-context-core` exposes a `SymbolParser` interface. The built-in `regex-structural-v1` parser has deterministic coverage for TypeScript, JavaScript, Python and Go without native dependencies. Optional parser adapters run first through `SymbolParserChain`; an unavailable or throwing adapter falls through to the built-in parser. Unsupported languages, malformed delimiter structure, supported files with no declarations and files carrying explicit DS4 classification spans retain the M7 overlapping text-window fallback. Keeping marked spans intact ensures M10 privacy enforcement sees the same boundaries as the 0.1 index.
49
+
50
+ Structural chunks follow declaration boundaries and retain signatures, parent relationships, imports/references and exact line ranges. Large declarations are split into bounded overlapping subchunks while sharing one symbol identity. Symbol IDs are SHA-256 values derived from canonical project identity, relative path, file hash, structural range, symbol kind and qualified name. Text fallback IDs retain their deterministic project/path/hash/range derivation.
45
51
 
46
- A full or incremental sync compares size, mtime, Git revision, and modified state. Source is re-read and SHA-256 hashed whenever metadata changes. Old snippets are marked `stale`; they remain inspectable but all exact and FTS queries require `stale = 0` and a current file row.
52
+ A full or incremental sync compares size, mtime, Git revision and modified state. Source is re-read and SHA-256 hashed whenever metadata changes. Replacing one file marks only that path's prior snippets stale, then transactionally inserts the new file-hash rows and FTS entries; unrelated file rows keep their IDs. Stale rows remain inspectable, but every exact and FTS query requires `stale = 0` and a current file row.
47
53
 
48
54
  ## Retrieval and ranking
49
55
 
50
- The same current-request `TaskDescriptor` used for historical retrieval supplies file paths, symbols, identifiers, errors, quoted phrases, technologies, and keywords. Candidate generation combines case-sensitive literal `instr()` search with escaped FTS5 terms.
56
+ The same current-request `TaskDescriptor` used for historical retrieval supplies file paths, symbols, identifiers, errors, quoted phrases, technologies and keywords. Candidate generation queries literal exact path/basename and exact qualified/simple symbol indexes before generic literal content and escaped FTS5 candidates. Exact lookup does not treat comment, string or reference text as a declaration.
57
+
58
+ When `retrieval.semantic` is enabled, the current embedding profile also contributes a bounded cosine-ranked pool. Deterministic reciprocal-rank fusion combines lexical and vector ranks; exact paths and symbols retain higher score tiers. Source vectors are populated during index sync and query vectors use a bounded volatile cache. Vector/model/privacy failures return the exact/FTS candidates unchanged. See [`HYBRID_RETRIEVAL.md`](HYBRID_RETRIEVAL.md).
51
59
 
52
60
  Deterministic ranking prioritizes:
53
61
 
54
62
  ```text
55
- exact project-relative path 140
56
- exact basename 125
57
- declared symbol 115
63
+ exact qualified symbol 190
64
+ exact project-relative path 180
65
+ exact simple symbol 170
66
+ exact basename 150
67
+ declared fallback symbol 115
58
68
  exact phrase 90
59
- symbol text 85
69
+ symbol text 65
60
70
  FTS match 60..20
61
71
  working-tree change 10
62
72
  tracked source 3
@@ -121,17 +131,19 @@ Source text is not copied into the Context Manifest or structured logs. It remai
121
131
 
122
132
  ## Fail-open behavior
123
133
 
124
- Project discovery, Git, indexing, FTS, validation, and retrieval errors are isolated from session indexing and context planning. A project failure records local diagnostics and contributes no snippets; Pi and historical retrieval continue. SQLite startup failure retains the existing runtime-wide Pi fallback.
134
+ Project discovery, Git, optional parser adapters, indexing, FTS, validation and retrieval errors are isolated from session indexing and context planning. Parser adapter failure uses deterministic regex fallback; unsupported or invalid source uses bounded text chunks. A project subsystem failure records local diagnostics and contributes no snippets; Pi and historical retrieval continue. SQLite startup failure retains the existing runtime-wide Pi fallback.
135
+
136
+ ## Verification and benchmark
125
137
 
126
- ## Benchmark
138
+ `quality/symbol-corpus-v1.json` is a synthetic, versioned TypeScript/JavaScript/Python/Go corpus with expected and forbidden declarations. Unit coverage verifies that structural parsing produces fewer false symbol matches than the preserved 0.1 regex extractor. Integration coverage verifies exact qualified/path lookup, metadata fields, stable IDs, unsupported/invalid fallback, changed-file invalidation, unrelated-file stability, trust/exclusion behavior and live-hash validation.
127
139
 
128
140
  `tests/benchmarks/project-knowledge.bench.ts` creates and indexes 5,000 source files, then executes exact path/symbol plus FTS retrieval with live hash validation:
129
141
 
130
142
  ```text
131
- mean 12.28 ms
132
- p75 13.12 ms
133
- p99 21.04 ms
134
- max 21.04 ms
143
+ mean 29.99 ms
144
+ p75 31.71 ms
145
+ p99 37.21 ms
146
+ max 37.21 ms
135
147
  ```
136
148
 
137
149
  Command:
package/docs/RELEASING.md CHANGED
@@ -1,21 +1,22 @@
1
1
  # Releasing DS4
2
2
 
3
- DS4 publishes two packages with the same version:
3
+ DS4 publishes three packages with the same version:
4
4
 
5
- 1. `ds4-context-core`, the runtime-neutral compiled package;
6
- 2. `ds4-context-engine`, the Pi adapter.
5
+ 1. `ds4-context-core`, the runtime-neutral compiled package and adapter kit;
6
+ 2. `ds4-context-reference-adapter`, the non-Pi callback/JSONL reference implementation;
7
+ 3. `ds4-context-engine`, the Pi adapter.
7
8
 
8
- The adapter has an exact dependency on the matching core version, so the core package must always be published first.
9
+ Both adapters have an exact dependency on the matching core version, so core must be published first.
9
10
 
10
11
  ## Prerequisites
11
12
 
12
13
  - use a clean `main` checkout synchronized with `origin/main`;
13
- - use a supported Node.js release and npm account authorized for both package names;
14
- - verify that both `package.json` files use the intended version;
15
- - verify that `ds4-context-engine` depends exactly on that version of `ds4-context-core`;
14
+ - use a supported Node.js release and npm account authorized for all three package names;
15
+ - verify that all three `package.json` files use the intended version;
16
+ - verify that both adapters depend exactly on that version of `ds4-context-core`;
16
17
  - do not include session data, `.pi` state, databases, credentials, or provider payloads.
17
18
 
18
- The automated package check enforces matching versions, the exact core dependency, bounded tarball inventories, clean consumer installation, core ESM exports, and packaged Pi extension startup through isolated RPC state.
19
+ The automated package check enforces matching versions, exact core dependencies, runtime-SDK isolation, bounded tarball inventories, clean consumer installation, core ESM exports, compiled reference-adapter conformance, and packaged Pi extension startup through isolated RPC state.
19
20
 
20
21
  ## Validate
21
22
 
@@ -29,26 +30,29 @@ git status --short
29
30
 
30
31
  CI runs the same checks on the minimum supported Node.js version and the current Node.js LTS line. `npm run pack:check` uses a temporary directory and removes it when complete. Set `DS4_KEEP_PACK_TMP=1` only when diagnosing a failed package check.
31
32
 
32
- Review both public tarballs before publishing:
33
+ Review all public tarballs before publishing:
33
34
 
34
35
  ```bash
35
36
  npm pack --dry-run --workspace ds4-context-core
37
+ npm pack --dry-run --workspace ds4-context-reference-adapter
36
38
  npm pack --dry-run
37
39
  ```
38
40
 
39
41
  ## Version
40
42
 
41
- Keep the root package, core workspace, and exact adapter dependency synchronized. For a future version stored in `$VERSION`:
43
+ Keep the root package, both workspaces, and exact adapter dependencies synchronized. For a future version stored in `$VERSION`:
42
44
 
43
45
  ```bash
44
46
  npm pkg set version="$VERSION"
45
47
  npm pkg set version="$VERSION" --workspace ds4-context-core
48
+ npm pkg set version="$VERSION" --workspace ds4-context-reference-adapter
46
49
  npm pkg set dependencies.ds4-context-core="$VERSION"
50
+ npm pkg set dependencies.ds4-context-core="$VERSION" --workspace ds4-context-reference-adapter
47
51
  npm install --package-lock-only
48
52
  npm run pack:check
49
53
  ```
50
54
 
51
- Review `package.json`, `packages/core/package.json`, and `package-lock.json` before committing the release change.
55
+ Review `package.json`, both workspace package manifests, and `package-lock.json` before committing the release change.
52
56
 
53
57
  ## Publish
54
58
 
@@ -57,12 +61,13 @@ Authenticate with npm, verify the active account, and publish in dependency orde
57
61
  ```bash
58
62
  npm whoami
59
63
  npm publish --workspace ds4-context-core --access public
64
+ npm publish --workspace ds4-context-reference-adapter --access public
60
65
  npm publish --access public
61
66
  ```
62
67
 
63
- If core succeeds but adapter publication fails, fix the adapter release and retry it with the same version. Do not rewrite or unpublish a valid core release merely to make the two commands appear atomic.
68
+ If core succeeds but an adapter publication fails, fix that adapter release and retry it with the same version. Do not rewrite or unpublish a valid core release merely to make the commands appear atomic.
64
69
 
65
- After both registry packages are available:
70
+ After all registry packages are available:
66
71
 
67
72
  1. install them in a fresh temporary project and rerun the package smoke check if registry propagation was delayed;
68
73
  2. create and push the signed or annotated `v$VERSION` tag;
package/docs/RETRIEVAL.md CHANGED
@@ -15,7 +15,7 @@ M6 recovers original session evidence that Pi compaction removed from the active
15
15
  9. Deduplicate normalized identical text, preferring the higher-ranked/newer source.
16
16
  10. Build individually bounded evidence messages, enforce the active provider privacy policy, and let the managed planner fit allowed groups after recent turns but before summaries.
17
17
 
18
- No LLM is called during retrieval. `retrieval.semantic: true` produces a diagnostic warning but does not enable embeddings in M6.
18
+ No chat LLM is called during retrieval. Since M16, `retrieval.semantic: true` adds opt-in vectors through the runtime-neutral `EmbeddingPort`; exact and FTS retrieval remain authoritative and any embedding failure falls back to lexical results. See [Hybrid Semantic Retrieval](HYBRID_RETRIEVAL.md).
19
19
 
20
20
  ## Ranking
21
21
 
@@ -49,6 +49,8 @@ M14 is first because adaptive ranking must be measured against a stable baseline
49
49
 
50
50
  ## M14 — Context Quality Metrics
51
51
 
52
+ Status: **implemented on `main` for `0.2.0-alpha.1`**. The active planner remains the 0.1 deterministic baseline; quality collection is opt-in and candidate strategies are replay-only.
53
+
52
54
  ### Deliverables
53
55
 
54
56
  - A sanitized replay corpus with expected evidence source IDs and task descriptors.
@@ -70,6 +72,8 @@ Quality samples store planner/profile versions, source-kind counts, token totals
70
72
 
71
73
  ## M15 — Rich Symbol Indexing
72
74
 
75
+ Status: **implemented on `main` for `0.2.0-alpha.1`**. Structural parsing remains a disposable local projection; unsupported or invalid source retains deterministic text-window behavior.
76
+
73
77
  ### Deliverables
74
78
 
75
79
  - A parser interface in `ds4-context-core` with deterministic regex fallback.
@@ -90,6 +94,8 @@ The parser implementation must not introduce a mandatory native build dependency
90
94
 
91
95
  ## M16 — Hybrid Semantic Retrieval
92
96
 
97
+ Status: **implemented on `main` for `0.2.0-alpha.2`**. Semantic retrieval remains opt-in; exact/FTS ranking and lexical-only failure behavior remain available.
98
+
93
99
  ### Deliverables
94
100
 
95
101
  - A runtime-neutral embedding port; model invocation remains outside core.
@@ -111,6 +117,8 @@ Semantic retrieval does not replace exact matching. Exact paths, symbols, quoted
111
117
 
112
118
  ## M17 — Cross-Session Project Memory
113
119
 
120
+ Status: **implemented on `main` behind `memory.crossSession` for `0.2.0-alpha.3`**. Discovery remains opt-in and exact trusted project identity is mandatory.
121
+
114
122
  ### Deliverables
115
123
 
116
124
  - Discovery of canonical Pi session JSONL files associated with the same trusted canonical project identity.
@@ -131,6 +139,8 @@ Version 0.2.0 does not silently extract new memories from conversation text. A d
131
139
 
132
140
  ## M18 — Learned Ranking
133
141
 
142
+ Status: **implemented on `main` for `0.2.0-beta.1` with `off`, aggregate-only `shadow`, and promotion-gated `active` modes**. Static ranking remains authoritative for missing, corrupt, incompatible, unpromoted or regressing artifacts.
143
+
134
144
  ### Deliverables
135
145
 
136
146
  - A bounded feature schema based on metadata such as source kind, exact/FTS/vector scores, recency, branch relation, symbol relation, classification eligibility, token cost and prior selection outcome.
@@ -153,6 +163,8 @@ If the gate is not met, 0.2.0 ships shadow mode but keeps static ranking active.
153
163
 
154
164
  ## M19 — Runtime Adapter Kit
155
165
 
166
+ Status: **implemented on `main` for `0.2.0-beta.2`**. Core ships `runtime-adapter-v1` plus a framework-neutral conformance runner; Pi exposes contract capability diagnostics, and the separately packaged callback/JSONL reference adapter passes all seven conformance cases.
167
+
156
168
  ### Deliverables
157
169
 
158
170
  - A documented adapter contract for canonical history snapshots, model limits, tool atomicity, trusted project roots, completion, privacy enforcement and lifecycle shutdown.
@@ -0,0 +1,143 @@
1
+ # Runtime Adapter Kit
2
+
3
+ M19 defines `runtime-adapter-v1`, a runtime-neutral boundary between DS4 policy and an agent host. The kit lives in `ds4-context-core/adapter/*`; the non-Pi implementation is published separately as `ds4-context-reference-adapter`. Core imports no runtime SDK.
4
+
5
+ ## Dependency and state boundary
6
+
7
+ ```text
8
+ native agent runtime / provider SDK
9
+ ↓
10
+ runtime adapter package
11
+ ↓
12
+ ds4-context-core/adapter/runtime-adapter
13
+ ```
14
+
15
+ An adapter owns native history conversion, trusted-root discovery, provider completion, final privacy enforcement, optional runtime capabilities, and shutdown. Core owns contract types, deterministic capability negotiation, canonical tool-group validation, and the framework-neutral conformance runner.
16
+
17
+ The runtime's native history remains canonical. A `RuntimeHistorySnapshot` is a read-only projection with:
18
+
19
+ - `runtimeId`, `sessionId`, schema version, and deterministic source revision;
20
+ - one exact trusted canonical project root;
21
+ - ordered `CanonicalMessage` values with stable source-entry provenance;
22
+ - complete tool call/result atomic groups derived from canonical blocks.
23
+
24
+ Applying a DS4 context plan must not write provider-facing synthetic messages back into canonical history. Rebuild deletes or discards only adapter/DS4 projections and reproduces the snapshot from the native source.
25
+
26
+ ## Contract
27
+
28
+ `RuntimeAdapter` requires:
29
+
30
+ | Method | Responsibility | Failure rule |
31
+ |---|---|---|
32
+ | `snapshotHistory()` | Project the active canonical history and tool relations. | Reject an invalid, corrupt, identity-mismatched, or untrusted source. Never invent history. |
33
+ | `rebuildDerivedState()` | Discard adapter caches/projections and replay canonical state. | Preserve canonical files and the previous valid source. |
34
+ | `currentModel()` | Return provider/model limits through `ModelDescriptor`. | Return `undefined` when no model is selected. |
35
+ | `trustedProjectRoot()` | Return the runtime-approved canonical root. | Reject untrusted roots; do not broaden them. |
36
+ | `enforcePrivacy()` | Sanitize a provider payload immediately before transport. | Fail closed and do not invoke transport on error. |
37
+ | `complete()` | Invoke the runtime/provider boundary with the sanitized payload. | Return an explicit fallback result for invalid input, privacy failure, transport failure, or closed lifecycle. |
38
+ | `capabilityDeclarations()` / `negotiateCapabilities()` | Version and independently enable optional host features. | Missing or malformed declarations are unsupported, not fatal to other features. |
39
+ | `diagnostics()` | Return bounded metadata-only state. | Never include prompts, history, credentials, payloads, cache handles, or provider output. |
40
+ | `shutdown()` | Release adapter resources idempotently. | Further writes/completions fall back; history reads are rejected. |
41
+
42
+ Completion output remains runtime-owned and is not automatically canonical. An adapter must append a final runtime-native message through its ordinary canonical history API if the host chooses to persist it.
43
+
44
+ ## Tool atomicity
45
+
46
+ `buildCanonicalToolAtomicGroups()` connects every canonical `toolCall` block to all matching `toolResult` blocks. Calls sharing one assistant message form one component, so parallel tool batches cannot be split. `validateRuntimeHistorySnapshot()` rejects missing, overlapping, unknown, or mismatched groups. An incomplete live call is represented by a group with `complete: false`; it cannot be treated as a complete selectable exchange.
47
+
48
+ ## Capability negotiation
49
+
50
+ The v1 registry is fixed and additive contracts must use a later contract version:
51
+
52
+ - `compaction`;
53
+ - `provider-continuation`;
54
+ - `embeddings`;
55
+ - `local-kv-reuse`.
56
+
57
+ A supported capability requires a non-empty implementation version. Unsupported capabilities require a bounded reason. `negotiateRuntimeCapabilities()` evaluates each request independently:
58
+
59
+ - a supported requested capability is enabled;
60
+ - an unsupported optional capability is disabled with an informational diagnostic;
61
+ - an unsupported required capability is disabled with a warning;
62
+ - a duplicate, missing, or unversioned declaration is malformed and disabled;
63
+ - no failure in one capability disables canonical history, privacy, completion fallback, or another valid capability.
64
+
65
+ M19 only negotiates `local-kv-reuse`; M20 defines its eligibility and handle lifecycle. KV handles are never part of canonical history or these diagnostics.
66
+
67
+ Pi advertises versioned compaction, OpenAI Responses continuation, and embedding-port support. It explicitly reports local KV reuse as unavailable. `/context adapter` shows the complete negotiation; `/context status` shows aggregate enabled/disabled counts.
68
+
69
+ ## Reusable conformance kit
70
+
71
+ The conformance runner has no Vitest/Jest dependency. Adapter packages provide a factory that maps a versioned fixture and injected completion transport into their native runtime:
72
+
73
+ ```ts
74
+ import {
75
+ assertRuntimeAdapterConformance,
76
+ runRuntimeAdapterConformance,
77
+ } from "ds4-context-core/adapter/conformance";
78
+
79
+ const report = await runRuntimeAdapterConformance({
80
+ name: "my-runtime",
81
+ async create(fixture, transport) {
82
+ // Create native canonical history from fixture.messages.
83
+ // Inject transport at the final provider boundary.
84
+ return { adapter, expectedProjectRoot, cleanup };
85
+ },
86
+ });
87
+ assertRuntimeAdapterConformance(report);
88
+ ```
89
+
90
+ The seven checks cover:
91
+
92
+ 1. adapter/contract identity, model limits, and trusted root;
93
+ 2. complete capability declarations and isolated unsupported diagnostics;
94
+ 3. ordered canonical history and tool atomicity;
95
+ 4. deterministic rebuild from canonical state;
96
+ 5. remote privacy filtering plus synthetic sanitizer failure before observed transport;
97
+ 6. safe transport failure with native fallback still available;
98
+ 7. idempotent shutdown and closed-state behavior.
99
+
100
+ Reports contain case IDs, booleans, and fixed failure codes only. The private marker and credential probes never appear in a report. Package smoke tests install core, Pi, and reference tarballs in a clean consumer and rerun reference conformance from compiled exports.
101
+
102
+ ## Reference-adapter compatibility spike
103
+
104
+ M19 compared three reference targets:
105
+
106
+ | Candidate | Strength | M19 risk |
107
+ |---|---|---|
108
+ | another full agent SDK | realistic lifecycle | adds fast-moving SDK/version coupling and obscures which behavior belongs to DS4 versus the SDK |
109
+ | provider-client-only adapter | realistic completion | has no canonical branch, tool-group, or lifecycle contract to validate |
110
+ | callback runtime with append-only JSONL | exercises every adapter responsibility with no vendor SDK | intentionally minimal; not a production orchestration framework |
111
+
112
+ The callback JSONL target was selected because it covers the full contract while keeping the example inspectable and dependency-neutral. `ds4-context-reference-adapter` is therefore a non-Pi executable boundary example, not a claim of production support for a specific third-party agent framework.
113
+
114
+ Its `ds4-runtime-session-v1` file is canonical and append-only. The header binds runtime ID, session ID, and canonical project root. Message records contain DS4 canonical messages. `createReferenceHistory()` refuses overwrite, `appendReferenceHistoryMessage()` checks provenance before append, and `rebuildDerivedState()` discards only the in-memory snapshot. File size and message count are bounded. Files are mode `0600` where supported.
115
+
116
+ The reference adapter provides a callback completion transport, enabled fail-closed privacy by default, optional `EmbeddingPort`, and explicit unsupported declarations for native compaction, provider continuation, and local KV state.
117
+
118
+ ## Packaging rules
119
+
120
+ All release packages use the same version.
121
+
122
+ - `ds4-context-core` has no runtime SDK dependency.
123
+ - `ds4-context-engine` contains the Pi SDK boundary and depends exactly on matching core.
124
+ - `ds4-context-reference-adapter` contains no Pi SDK and depends exactly on matching core.
125
+ - Adapter source is not bundled into the core tarball; core source is not bundled into adapter tarballs.
126
+ - Core and reference TypeScript compile to ESM JavaScript and declarations before packing.
127
+ - Publish core first, then reference, then Pi.
128
+
129
+ Use:
130
+
131
+ ```bash
132
+ npm run check
133
+ npm run pack:check
134
+ npm pack --dry-run --workspace ds4-context-core
135
+ npm pack --dry-run --workspace ds4-context-reference-adapter
136
+ npm pack --dry-run
137
+ ```
138
+
139
+ ## Limitations and rollback
140
+
141
+ The reference adapter is intentionally synchronous-history/callback-completion infrastructure: it does not implement streaming, native compaction, branch editing, provider continuation, or KV reuse. Unsupported features remain disabled and visible rather than emulated.
142
+
143
+ Removing the reference package does not affect Pi or core. A runtime can roll back its adapter by stopping it and returning to native history/context behavior; no canonical migration or SQLite downgrade is required. Deleting adapter caches is safe. Never delete the runtime-owned JSONL file as part of DS4 rollback.