ds4-context-engine 0.4.7 → 0.4.8
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.
- package/README.md +1 -1
- package/docs/ADR/069-retract-quoting-of-every-unsupported-exact-value.md +78 -0
- package/docs/ADR/README.md +1 -0
- package/docs/COMPACTION.md +4 -4
- package/docs/releases/0.4.7.md +23 -0
- package/docs/releases/0.4.8.md +109 -0
- package/package.json +2 -2
- package/src/pi-adapter/summary-generator.ts +23 -33
- package/src/pi-adapter/version.ts +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ bounded active context with provenance
|
|
|
16
16
|
Pi provider
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
> **Project status:** The coordinated `0.4.0` release adds `storage.scope: "agent" | "project"`, now defaulting to per-project SQLite projections with shared token calibration in the agent database (opt out with `storage.scope: "agent"`). The opt-in BPE estimation and bounded auto-tuning from `0.3.10` keep `chars-v1` and disabled auto-tuning as their defaults. The bounded compaction controls from `0.3.9` remain in place; canonical history, SQLite schema 16 and runtime contracts are unchanged. Pi remains pinned to `0.84.3`. Patch `0.4.1` states the contiguous-span rule for compaction summaries in the summarizer prompt while leaving validation strictness, the eight-bullet repair bound and every provider-facing default unchanged. Patch `0.4.2` adds class-only diagnostics for rejected exact-value spans: the existing `custom_fallback` warning carries `unsupportedSpanClasses` as class names and counters, never span text, with validation, repair bounds and provider-facing defaults unchanged. Patch `0.4.3` makes those diagnostics interpretable: every distinct span receives the cheap transformed-form lookups before the bounded near-miss analysis starts, each near-miss candidate may spend only an equal share of what remains, and spans that were not analysed report `not-classified-length`, `not-classified-partial` or `not-classified-budget` instead of `no-near-miss`. Patch `0.4.4` accepts a backticked exact value whose canonical JSON-escaped rendering is literally present in the evidence — the decoded rendering a summarizer produces when it quotes serialized JSON — while absent values, the reverse escape direction, span composition and single-character variants stay rejected; the diagnostics probe budget rises from 4000 to 24000 evidence-source scans. Patch `0.4.5` grades the summarizer quoting fallback: the prompt requires one contiguous excerpt per backticked span, tells the model to backtick only the fragments that are themselves contiguous or to keep the fact as ordinary text without backticks instead of composing a span, and reserves bullet omission for facts with no support in the evidence; diagnostics split composition into `composed-adjacent-present` (both parts next to each other in one source, so the span may be a re-rendering of a contiguous region) and `composed-two-present-parts` (parts found at unrelated positions), with validation strictness, the eight-bullet and 25% repair bounds and every provider-facing default unchanged. Patch `0.4.6` makes an engine/core artifact mismatch visible instead of a missing function: the core exports `CORE_VERSION` and the engine verifies at session start and at every compaction attempt that the loaded core matches its own version and exposes the entry points it calls, so a core rebuilt under a running Pi — which a `/reload` does not pick up — reports one actionable line, keeps the DS4 compaction layer inert instead of failing mid-generation, and never blocks Pi; validation strictness, repair bounds and every provider-facing default stay unchanged. Patch `0.4.7` stops the recurrent fail-closed fallback at its source: when the summarizer re-renders a value the evidence holds in another form — JSON-escaped or unescaped, collapsed whitespace, stripped typographic characters, or two parts adjacent in one source — the repair retracts only the backticks and keeps the fact, so those spans no longer consume the eight-bullet bound; invented values, unrelated compositions, one-character deviations, case changes and unanalysed spans keep the existing fail-closed bullet removal, validation strictness is unchanged, and both effects are recorded as counters (`unsupported-exact-bullets-pruned`, `unsupported-exact-spans-unquoted`). See the [0.4.7 release record](docs/releases/0.4.7.md), the [0.4.6 release record](docs/releases/0.4.6.md), the [0.4.5 release record](docs/releases/0.4.5.md), the [0.4.4 release record](docs/releases/0.4.4.md), the [0.4.3 release record](docs/releases/0.4.3.md), the [0.4.2 release record](docs/releases/0.4.2.md), the [0.4.1 release record](docs/releases/0.4.1.md) and the [0.4.0 release record](docs/releases/0.4.0.md), [ADR 068](docs/ADR/068-downgrade-rendering-equivalent-spans.md), [ADR 067](docs/ADR/067-core-version-guard.md), [ADR 066](docs/ADR/066-quoting-downgrade-and-span-adjacency.md), [ADR 065](docs/ADR/065-exact-value-escaped-equivalence.md), [ADR 064](docs/ADR/064-per-project-databases-with-shared-calibration.md) and [model-awareness validation](docs/MODEL_AWARENESS.md).
|
|
19
|
+
> **Project status:** The coordinated `0.4.0` release adds `storage.scope: "agent" | "project"`, now defaulting to per-project SQLite projections with shared token calibration in the agent database (opt out with `storage.scope: "agent"`). The opt-in BPE estimation and bounded auto-tuning from `0.3.10` keep `chars-v1` and disabled auto-tuning as their defaults. The bounded compaction controls from `0.3.9` remain in place; canonical history, SQLite schema 16 and runtime contracts are unchanged. Pi remains pinned to `0.84.3`. Patch `0.4.1` states the contiguous-span rule for compaction summaries in the summarizer prompt while leaving validation strictness, the eight-bullet repair bound and every provider-facing default unchanged. Patch `0.4.2` adds class-only diagnostics for rejected exact-value spans: the existing `custom_fallback` warning carries `unsupportedSpanClasses` as class names and counters, never span text, with validation, repair bounds and provider-facing defaults unchanged. Patch `0.4.3` makes those diagnostics interpretable: every distinct span receives the cheap transformed-form lookups before the bounded near-miss analysis starts, each near-miss candidate may spend only an equal share of what remains, and spans that were not analysed report `not-classified-length`, `not-classified-partial` or `not-classified-budget` instead of `no-near-miss`. Patch `0.4.4` accepts a backticked exact value whose canonical JSON-escaped rendering is literally present in the evidence — the decoded rendering a summarizer produces when it quotes serialized JSON — while absent values, the reverse escape direction, span composition and single-character variants stay rejected; the diagnostics probe budget rises from 4000 to 24000 evidence-source scans. Patch `0.4.5` grades the summarizer quoting fallback: the prompt requires one contiguous excerpt per backticked span, tells the model to backtick only the fragments that are themselves contiguous or to keep the fact as ordinary text without backticks instead of composing a span, and reserves bullet omission for facts with no support in the evidence; diagnostics split composition into `composed-adjacent-present` (both parts next to each other in one source, so the span may be a re-rendering of a contiguous region) and `composed-two-present-parts` (parts found at unrelated positions), with validation strictness, the eight-bullet and 25% repair bounds and every provider-facing default unchanged. Patch `0.4.6` makes an engine/core artifact mismatch visible instead of a missing function: the core exports `CORE_VERSION` and the engine verifies at session start and at every compaction attempt that the loaded core matches its own version and exposes the entry points it calls, so a core rebuilt under a running Pi — which a `/reload` does not pick up — reports one actionable line, keeps the DS4 compaction layer inert instead of failing mid-generation, and never blocks Pi; validation strictness, repair bounds and every provider-facing default stay unchanged. Patch `0.4.7` stops the recurrent fail-closed fallback at its source: when the summarizer re-renders a value the evidence holds in another form — JSON-escaped or unescaped, collapsed whitespace, stripped typographic characters, or two parts adjacent in one source — the repair retracts only the backticks and keeps the fact, so those spans no longer consume the eight-bullet bound; invented values, unrelated compositions, one-character deviations, case changes and unanalysed spans keep the existing fail-closed bullet removal, validation strictness is unchanged, and both effects are recorded as counters (`unsupported-exact-bullets-pruned`, `unsupported-exact-spans-unquoted`). Patch `0.4.8` ends the recurrent exact-value fallback at its root: an unsupported backticked value no longer costs its bullet or the whole compaction — the repair retracts the quoting of every rejected span, keeps the text as prose and re-validates, so exact-value failures cannot end a compaction while every surviving backticked value is still verified literally or as its canonical JSON-escaped rendering; the eight-bullet and 25% removal bounds no longer apply to this path, structural, transport and budget failures still fall back to Pi, and the class report remains class-only diagnostics. See the [0.4.8 release record](docs/releases/0.4.8.md), the [0.4.7 release record](docs/releases/0.4.7.md), the [0.4.6 release record](docs/releases/0.4.6.md), the [0.4.5 release record](docs/releases/0.4.5.md), the [0.4.4 release record](docs/releases/0.4.4.md), the [0.4.3 release record](docs/releases/0.4.3.md), the [0.4.2 release record](docs/releases/0.4.2.md), the [0.4.1 release record](docs/releases/0.4.1.md) and the [0.4.0 release record](docs/releases/0.4.0.md), [ADR 069](docs/ADR/069-retract-quoting-of-every-unsupported-exact-value.md), [ADR 068](docs/ADR/068-downgrade-rendering-equivalent-spans.md), [ADR 067](docs/ADR/067-core-version-guard.md), [ADR 066](docs/ADR/066-quoting-downgrade-and-span-adjacency.md), [ADR 065](docs/ADR/065-exact-value-escaped-equivalence.md), [ADR 064](docs/ADR/064-per-project-databases-with-shared-calibration.md) and [model-awareness validation](docs/MODEL_AWARENESS.md).
|
|
20
20
|
|
|
21
21
|
**Current compaction defaults:** `compaction.directUpdate=true`, `compaction.inputBudget="context"`, `compaction.segmentTargetTokens=30000`, `compaction.maxRequestInputTokens=64000`, `compaction.maxOperationInputTokens=2000000`, `compaction.maxConcurrentSegments=2`. Every DS4 provider attempt is bounded by the effective request limit, and the operation limit includes retries; `inputBudget="summary"` remains an explicit throughput-oriented opt-in. Existing compaction/master switches still apply. See [latency controls and compatibility](docs/COMPACTION.md#latency-controls). No real-provider speedup is claimed from mock tests. The five optional editing/reading/artifact/job features introduced in `0.3.4` remain default-off.
|
|
22
22
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 069 — Retract the quoting of every unsupported exact value instead of failing the compaction
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-09-28
|
|
4
|
+
**Status:** Accepted
|
|
5
|
+
**Related:** [065](065-exact-value-escaped-equivalence.md), [066](066-quoting-downgrade-and-span-adjacency.md), [068](068-downgrade-rendering-equivalent-spans.md)
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Six coordinated releases (0.4.1–0.4.7) reduced, but never removed, the recurrent
|
|
10
|
+
`compaction.custom_fallback` with `unsupported-exact-value;
|
|
11
|
+
repair=too-many-bullets`. The affected-bullet series from production was 30/20 →
|
|
12
|
+
23/19 → 19/15 → 17/11 → 16/12, and the report that closed the case carried 25
|
|
13
|
+
spans across 15 bullets.
|
|
14
|
+
|
|
15
|
+
That report shows why the class-by-class repair cannot converge:
|
|
16
|
+
|
|
17
|
+
| Relation | Count |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `composed-two-present-parts` | 11 |
|
|
20
|
+
| `not-classified-partial` | 5 |
|
|
21
|
+
| `not-classified-length` | 4 |
|
|
22
|
+
| `composed-adjacent-present` | 3 |
|
|
23
|
+
| `no-near-miss` | 2 |
|
|
24
|
+
|
|
25
|
+
`spansClassifiedCheap` was 0: not one span was a rendering variant of contiguous
|
|
26
|
+
evidence, so the escape path was exhausted. The 0.4.7 repair could retract the
|
|
27
|
+
quoting of at most the three adjacent spans; the remaining 22 spans kept the
|
|
28
|
+
bullet-removal path, and 15 − 3 = 12 bullets still exceeded the eight-bullet
|
|
29
|
+
bound. On that input 0.4.7 would have fallen back by construction.
|
|
30
|
+
|
|
31
|
+
The classes are not a finite list of odd renderings to eliminate one release at a
|
|
32
|
+
time. They are one behaviour: the summarizer composes and paraphrases spans. The
|
|
33
|
+
validator cannot accept `composed-two-present-parts` — that association is
|
|
34
|
+
precisely what the evidence does not contain — and no rendering normalization
|
|
35
|
+
turns a composed span into a contiguous excerpt.
|
|
36
|
+
|
|
37
|
+
## Decision
|
|
38
|
+
|
|
39
|
+
- Validation is unchanged. A backticked value that the evidence does not hold
|
|
40
|
+
literally, or as its canonical JSON-escaped rendering, is still invalid.
|
|
41
|
+
- The repair retracts the two backticks of **every** unsupported span in place,
|
|
42
|
+
keeps the text, and the repaired summary is re-validated. No bullet is deleted
|
|
43
|
+
for an exact-value failure, so the eight-bullet and 25% removal bounds no
|
|
44
|
+
longer apply to this path.
|
|
45
|
+
- The repair no longer consults the span classification. The class-only report
|
|
46
|
+
stays as diagnostics and is still attached to the fallback warning, which now
|
|
47
|
+
fires only for structural, transport or budget failures.
|
|
48
|
+
- Fallback remains for missing, duplicate or empty sections, unsupported file
|
|
49
|
+
paths, unknown sections or headings, malformed content, transport and budget
|
|
50
|
+
failures, and any summary that is still invalid after the retraction
|
|
51
|
+
(`post-downgrade-invalid`).
|
|
52
|
+
- Outcomes are counters, never span text: `unsupported-exact-spans-unquoted`
|
|
53
|
+
records the retracted spans, and `unsupported-exact-bullets-pruned` no longer
|
|
54
|
+
exists.
|
|
55
|
+
|
|
56
|
+
## Consequences
|
|
57
|
+
|
|
58
|
+
- The dominant production failure mode cannot fail the compaction any more. The
|
|
59
|
+
fact stays as prose, the exactness claim goes, and every value that remains
|
|
60
|
+
backticked is still verified literally or as its canonical JSON-escaped
|
|
61
|
+
rendering. This supersedes the exclusion list of
|
|
62
|
+
[ADR 068](068-downgrade-rendering-equivalent-spans.md).
|
|
63
|
+
- The trade is explicit: a value the evidence does not carry — including an
|
|
64
|
+
invented one — is no longer deleted, and the eight-bullet and 25% bounds no
|
|
65
|
+
longer protect it. Losing a fact, or losing the whole DS4 compaction to Pi's
|
|
66
|
+
default, was judged worse; the fallback this replaces does not check exact
|
|
67
|
+
values at all.
|
|
68
|
+
- An unsupported value remains visible in the summary as prose and in the
|
|
69
|
+
recorded counter, so the operator can review it instead of relying on the
|
|
70
|
+
bullet removal.
|
|
71
|
+
- The public core repair API changes: `analyzeUnsupportedExactValueDowngrade`
|
|
72
|
+
and `downgradeUnsupportedExactValues` replace
|
|
73
|
+
`analyzeUnsupportedExactValueBullets` and `pruneUnsupportedExactValueBullets`,
|
|
74
|
+
and `ExactValueDowngradeResult`/`ExactValueDowngradeAttempt` replace the
|
|
75
|
+
`ExactValuePrune*` types. The engine/core compatibility guard turns a mixed
|
|
76
|
+
artifact pair into one actionable line instead of a missing function.
|
|
77
|
+
- No configuration key, no SQLite migration, no schema change, and no
|
|
78
|
+
provider-facing default change.
|
package/docs/ADR/README.md
CHANGED
|
@@ -72,5 +72,6 @@ The initial decisions from the development plan are accepted:
|
|
|
72
72
|
| [066](066-quoting-downgrade-and-span-adjacency.md) | Grade the summarizer quoting fallback and separate adjacent from unrelated span composition | Accepted |
|
|
73
73
|
| [067](067-core-version-guard.md) | Detect an engine/core artifact mismatch before compaction runs | Accepted |
|
|
74
74
|
| [068](068-downgrade-rendering-equivalent-spans.md) | Downgrade rendering-equivalent spans instead of spending the bullet budget | Accepted |
|
|
75
|
+
| [069](069-retract-quoting-of-every-unsupported-exact-value.md) | Retract the quoting of every unsupported exact value instead of failing the compaction | Accepted |
|
|
75
76
|
|
|
76
77
|
Each decision will receive a dedicated record when implementation pressure introduces alternatives or consequences not already covered by the development plan.
|
package/docs/COMPACTION.md
CHANGED
|
@@ -32,17 +32,17 @@ Fan-out and fan-in are bounded to 32 segment requests, 64 aggregate requests, an
|
|
|
32
32
|
## Critical Exact Values
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Every section must occur once, in order, and contain content or `- None`. DS4 replaces each unique `Files Read` and `Files Modified` section with one exact path per bullet from Pi's sanitized file-operation inventory before validation; missing or duplicate sections still fail. Backticked exact values must occur literally in the serialized segment source, ordered child-summary content, or those known file-operation paths, either as written or in the canonical JSON-escaped rendering of the value. A decoded value whose encoded text is present in the evidence is accepted ([ADR 065](ADR/065-exact-value-escaped-equivalence.md)); the reverse direction — an escaped span whose raw form is present — remains unsupported and is reported as `unescaped-form-present`.
|
|
35
|
+
Every section must occur once, in order, and contain content or `- None`. DS4 replaces each unique `Files Read` and `Files Modified` section with one exact path per bullet from Pi's sanitized file-operation inventory before validation; missing or duplicate sections still fail. Backticked exact values must occur literally in the serialized segment source, ordered child-summary content, or those known file-operation paths, either as written or in the canonical JSON-escaped rendering of the value. A decoded value whose encoded text is present in the evidence is accepted ([ADR 065](ADR/065-exact-value-escaped-equivalence.md)); the reverse direction — an escaped span whose raw form is present — remains unsupported and is reported as `unescaped-form-present`. Every unsupported span is repaired the same way: the two backticks are retracted and the text stays, so the fact survives as prose and the exact-value claim does not ([ADR 069](ADR/069-retract-quoting-of-every-unsupported-exact-value.md)). No bullet is deleted for an exact-value failure, the eight-bullet and 25% removal bounds no longer apply to it, and the repaired summary is re-validated: any remaining structural problem still fails closed to Pi, and every backticked value that survives is still verified literally or as its canonical JSON-escaped rendering. The prompt requires every backticked span to be one contiguous excerpt copied as-is and forbids assembling one span from separately supported values (a setting name with its value, a path with a line range, a command with its flags), and it gives the model a cheaper alternative than composing: backtick only the fragments that are themselves contiguous with the joining text outside the backticks, or write the value as ordinary text without backticks, keeping the bullet. A bullet is omitted only when the fact itself has no support in the evidence ([ADR 066](ADR/066-quoting-downgrade-and-span-adjacency.md)). Every segment is validated independently against only its own sanitized source and deterministic file inventory. Every aggregate is validated independently against only the sanitized content of its ordered children and cumulative deterministic file inventory. A direct update is validated against both the sanitized previous summary and new source, plus cumulative sanitized file evidence; previous-summary-only exact values remain valid evidence. Custom focus instructions are not factual evidence. Any unrepaired failure prevents the whole graph batch from being installed.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
A fail-closed compaction reports only the stage, issue codes, the repair status, the unsupported-span count and the affected-bullet count. An exact-value repair either retracts the quoting (`downgraded`) or is not needed; a summary that is still invalid after the retraction is reported as `post-downgrade-invalid` and remains a structural failure. The disputed text is intentionally absent from logs, UI notifications, and diagnostics because it may contain sensitive source material.
|
|
38
38
|
|
|
39
|
-
The same failure carries a class-only span report on the fallback warning (`unsupportedSpanClasses`): rejected-span count, affected bullets, length buckets, character shapes (spaces, backslashes, escape sequences, separators, quotes, typographic characters, JSON punctuation), and how each distinct span relates to the evidence — escaped or unescaped rendering, collapsed whitespace, case or typographic variant, one-character deletion, two separately present values joined into one span — adjacent in one source with nothing but joining punctuation and spaces between them (`composed-adjacent-present`) or found at unrelated positions (`composed-two-present-parts`) — or no near-miss (every applicable lookup ran and found nothing). The adjacency question separates a join that re-renders a contiguous evidence region from an association the evidence never contains: a joiner gap holds no letters, digits or line breaks, so two parts on separate lines are not adjacent. The report contains class names and counters only, never span text, and
|
|
39
|
+
The same failure carries a class-only span report on the fallback warning (`unsupportedSpanClasses`): rejected-span count, affected bullets, length buckets, character shapes (spaces, backslashes, escape sequences, separators, quotes, typographic characters, JSON punctuation), and how each distinct span relates to the evidence — escaped or unescaped rendering, collapsed whitespace, case or typographic variant, one-character deletion, two separately present values joined into one span — adjacent in one source with nothing but joining punctuation and spaces between them (`composed-adjacent-present`) or found at unrelated positions (`composed-two-present-parts`) — or no near-miss (every applicable lookup ran and found nothing). The adjacency question separates a join that re-renders a contiguous evidence region from an association the evidence never contains: a joiner gap holds no letters, digits or line breaks, so two parts on separate lines are not adjacent. The report contains class names and counters only, never span text, and it is observation-only: neither validation nor the repair consults the relations, because every unsupported span is downgraded whatever its class. It exists to separate a summarizer that invents values from one whose rendering or composition rules differ from the validation domain, which would call for opposite prompt or model changes. The first production report produced by the 0.4.4 diagnostics attributed 9 of 14 rejected spans to composition, 2 to a one-character deviation, 2 to absence and 1 to the length limit, with no rendering class left at all.
|
|
40
40
|
|
|
41
41
|
Three relations mark spans that were *not* analysed, and they must never be read as invention. `not-classified-length` means the span exceeds the near-miss length limit (96 characters); `not-classified-partial` means its share of the budget ran out; `not-classified-budget` means the shared budget was already exhausted. To keep the histogram interpretable, transformed-form lookups cover every distinct span before any near-miss analysis starts, and each near-miss candidate may spend only an equal share of what remains (at least 32 lookups, never more than the budget left). The report also carries `spansClassifiedCheap` (span occurrences attributed by a transformed-form relation), `corpusSources`, `probeBudget` and `probesUsed`, so a run can be read without guessing how much of the budget was consumed. The shared budget defaults to 24000 evidence-source scans, where one lookup scans every corpus source once. `escaped-form-present` is not expected in reports from 0.4.4 on: validation accepts the canonical escaped rendering and the classifier consumes the same predicate, so such spans no longer reach it; the class stays in the taxonomy for compatibility. `classificationComplete` is false when the shared budget or a per-span share stopped an analysis; a `not-classified-length` span does not clear it, because that limit is deterministic rather than a resource shortfall.
|
|
42
42
|
|
|
43
43
|
## Provenance and recovery
|
|
44
44
|
|
|
45
|
-
The engine checks its own contract with the loaded core at session start and at the start of every compaction attempt: `CORE_VERSION` must equal the extension version and the core entry points the extension calls must be present. Because Pi loads extension sources from TypeScript but keeps dependency modules loaded for the life of the process, a core rebuilt under a running Pi stays stale in memory and a `/reload` is not enough to pick it up; without the check the first missing export surfaced as `... is not a function` deep inside generation. A mismatch now logs `runtime.core_incompatible`, notifies once with the versions and the failing entry point, and leaves the compaction coordinator uncreated, so `/context compaction` reports `enabled: false` with that reason and Pi's own compaction is the only behaviour left. The guard is detection only: it never changes validation, repair
|
|
45
|
+
The engine checks its own contract with the loaded core at session start and at the start of every compaction attempt: `CORE_VERSION` must equal the extension version and the core entry points the extension calls must be present. Because Pi loads extension sources from TypeScript but keeps dependency modules loaded for the life of the process, a core rebuilt under a running Pi stays stale in memory and a `/reload` is not enough to pick it up; without the check the first missing export surfaced as `... is not a function` deep inside generation. A mismatch now logs `runtime.core_incompatible`, notifies once with the versions and the failing entry point, and leaves the compaction coordinator uncreated, so `/context compaction` reports `enabled: false` with that reason and Pi's own compaction is the only behaviour left. The guard is detection only: it never changes validation, repair behaviour or the fail-closed decision, and it never throws while the extension is loading, because Pi treats an extension load error as fatal ([ADR 067](ADR/067-core-version-guard.md)).
|
|
46
46
|
|
|
47
47
|
`CompactionEntry.details` contains cumulative `readFiles` and `modifiedFiles` plus:
|
|
48
48
|
|
package/docs/releases/0.4.7.md
CHANGED
|
@@ -133,3 +133,26 @@ instead of depending on the model complying
|
|
|
133
133
|
- No provider calls are involved. `jev_verify` is not available in this
|
|
134
134
|
environment (project verification disabled), so the checks above were run
|
|
135
135
|
directly.
|
|
136
|
+
|
|
137
|
+
## Publication and registry verification
|
|
138
|
+
|
|
139
|
+
Published manually in dependency order from `bf221b5`: `ds4-context-core@0.4.7`,
|
|
140
|
+
then `ds4-context-reference-adapter@0.4.7`, then `ds4-context-engine@0.4.7`, all
|
|
141
|
+
with the default `latest` tag, after `npm run check` and `npm run pack:check` on
|
|
142
|
+
the same commit.
|
|
143
|
+
|
|
144
|
+
`npm run registry:check -- 0.4.7` needed five attempts, each with a fresh npm
|
|
145
|
+
cache, before the registry CDN served the new packuments (the known propagation
|
|
146
|
+
delay after a publish); the fifth reported "Verified all DS4 registry packages at
|
|
147
|
+
exact version 0.4.7". All three packages install in a clean consumer, the exact
|
|
148
|
+
adapter/core dependencies resolve, the public core and KV exports import, the
|
|
149
|
+
compiled reference conformance and packaged quality corpus run, the
|
|
150
|
+
`ds4-context-storage` CLI shim responds, and the published Pi extension starts
|
|
151
|
+
against isolated offline RPC state. `npm view <package> dist-tags.latest`
|
|
152
|
+
resolves to 0.4.7 for all three packages.
|
|
153
|
+
|
|
154
|
+
Annotated tag `v0.4.7` and the GitHub Release were created from `bf221b5`:
|
|
155
|
+
<https://github.com/Alucard24/ds4-context-engine/releases/tag/v0.4.7>. No session
|
|
156
|
+
data, credentials, provider payloads or prompt text were read or written while
|
|
157
|
+
preparing this release, and no provider call is involved in the release
|
|
158
|
+
procedure.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Release 0.4.8 — Retract the quoting of every unsupported exact value
|
|
2
|
+
|
|
3
|
+
**Coordinated packages:** `ds4-context-core`, `ds4-context-reference-adapter`, and `ds4-context-engine` 0.4.8.
|
|
4
|
+
**Implementation commit:** `f0a457a`.
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
Behaviour patch that ends the recurrent `compaction.custom_fallback` with
|
|
9
|
+
`unsupported-exact-value`. Validation is unchanged: a backticked value the
|
|
10
|
+
evidence does not hold literally, or as its canonical JSON-escaped rendering, is
|
|
11
|
+
still invalid. What changes is the repair: it retracts the two backticks of
|
|
12
|
+
**every** unsupported span in place, keeps the text, and the repaired summary is
|
|
13
|
+
re-validated. No bullet is deleted for an exact-value failure, so the
|
|
14
|
+
eight-bullet and 25% removal bounds no longer apply to that path, and the repair
|
|
15
|
+
no longer consults the span classification, which stays as class-only
|
|
16
|
+
diagnostics on the fallback warning. Fallback remains for structural, transport
|
|
17
|
+
and budget failures. SQLite schema 16, canonical JSONL history and every
|
|
18
|
+
provider-facing default are unchanged.
|
|
19
|
+
|
|
20
|
+
## Changes
|
|
21
|
+
|
|
22
|
+
- `packages/core/src/compaction/summary-contract.ts`: the repair API is now
|
|
23
|
+
`analyzeUnsupportedExactValueDowngrade` and `downgradeUnsupportedExactValues`,
|
|
24
|
+
with `ExactValueDowngradeResult` / `ExactValueDowngradeAttempt` replacing the
|
|
25
|
+
`ExactValuePrune*` types and statuses.
|
|
26
|
+
- `downgradeUnsupportedExactSpans` retracts the backticks of every span
|
|
27
|
+
returned by the existing `unsupportedExactMatches` and leaves the text.
|
|
28
|
+
- `affectedBulletCount` reports the bullets that contained a rejected span.
|
|
29
|
+
- `RENDERING_EQUIVALENT_RELATIONS` and `renderingEquivalentSpans` are removed:
|
|
30
|
+
the repair no longer needs the classifier.
|
|
31
|
+
- The classifier keeps its bounded analysis and the class-only report, now
|
|
32
|
+
documented as observation-only again.
|
|
33
|
+
- `src/pi-adapter/summary-generator.ts`: the downgrade outcome is recorded as
|
|
34
|
+
`unsupported-exact-spans-unquoted`; `unsupported-exact-bullets-pruned` no
|
|
35
|
+
longer exists, and a summary still invalid after the retraction is reported as
|
|
36
|
+
`post-downgrade-invalid`.
|
|
37
|
+
- `tests/unit/summary-contract.test.ts` and
|
|
38
|
+
`tests/unit/summary-generator.test.ts` cover the downgrade of supported,
|
|
39
|
+
composed, one-character-deviant, over-length and absent spans, the
|
|
40
|
+
disappearing bounds, and the class-only report on a structural failure.
|
|
41
|
+
`tests/unit/compaction-optimizations.test.ts` and
|
|
42
|
+
`tests/integration/compaction.test.ts` cover the completed compaction with
|
|
43
|
+
`validationStatus: "warning"` and the privacy-safe counters.
|
|
44
|
+
- `docs/COMPACTION.md`, `docs/ADR/069-retract-quoting-of-every-unsupported-exact-value.md`
|
|
45
|
+
and the ADR index record the decision; `README.md` links the release.
|
|
46
|
+
|
|
47
|
+
## Why
|
|
48
|
+
|
|
49
|
+
The affected-bullet series from production was 30/20 → 23/19 → 19/15 → 17/11 →
|
|
50
|
+
16/12, every run ending in `compaction.custom_fallback` with
|
|
51
|
+
`unsupported-exact-value; repair=too-many-bullets`. The class-only report that
|
|
52
|
+
closed the attribution carried 25 spans across 15 bullets: `spansClassifiedCheap`
|
|
53
|
+
was 0, so no span was a rendering variant of contiguous evidence; 11 spans were
|
|
54
|
+
compositions whose parts sit at unrelated positions, 5 spent their share of the
|
|
55
|
+
analysis budget, 4 exceeded the length limit, 3 were adjacent compositions and 2
|
|
56
|
+
had no near-miss at all.
|
|
57
|
+
|
|
58
|
+
On that input the 0.4.7 repair could retract the quoting of at most the three
|
|
59
|
+
adjacent spans. The remaining 22 spans kept the bullet-removal path, and
|
|
60
|
+
15 − 3 = 12 bullets still exceeded the eight-bullet bound, so 0.4.7 would have
|
|
61
|
+
fallen back by construction on the same input. The classes are not a finite list
|
|
62
|
+
of odd renderings to eliminate one release at a time: they are the summarizer's
|
|
63
|
+
normal composing and paraphrasing behaviour, and an association the evidence
|
|
64
|
+
does not contain (`composed-two-present-parts`) must never be accepted.
|
|
65
|
+
|
|
66
|
+
The repair now applies the only deterministic answer that keeps both the fact and
|
|
67
|
+
the verification: the fact stays as prose, the exactness claim goes, and every
|
|
68
|
+
value that remains backticked is still verified against the evidence.
|
|
69
|
+
Instructing the model differently (0.4.1, 0.4.5) was already shown not to
|
|
70
|
+
converge.
|
|
71
|
+
|
|
72
|
+
## Privacy and safety
|
|
73
|
+
|
|
74
|
+
- Logs, warnings and diagnostics keep carrying counters only: the number of
|
|
75
|
+
retracted spans, never span text, fragments or evidence hashes.
|
|
76
|
+
- The class-only report is observation-only and runs only after a validation
|
|
77
|
+
failure; it never changes validation or the repair.
|
|
78
|
+
- Validation strictness is preserved for every surviving backticked value. The
|
|
79
|
+
deliberate trade is that a value the evidence does not carry — including an
|
|
80
|
+
invented one — is no longer deleted: it stays as prose and in the recorded
|
|
81
|
+
counter, instead of costing the fact or the whole DS4 compaction. The fallback
|
|
82
|
+
this replaces (Pi's default compaction) does not check exact values at all.
|
|
83
|
+
- No provider call, network access or configuration change is involved in the
|
|
84
|
+
repair.
|
|
85
|
+
|
|
86
|
+
## Compatibility and persistence
|
|
87
|
+
|
|
88
|
+
- No migrations, no schema change (still 16), no new configuration key, and no
|
|
89
|
+
change to any provider-facing default: `chars-v1` remains the default
|
|
90
|
+
estimator, `modelAwareness.autoTune` and DS4 native continuation stay
|
|
91
|
+
disabled, `storage.scope` keeps its `project` default.
|
|
92
|
+
- The core repair API is renamed as listed above; the engine/core compatibility
|
|
93
|
+
guard turns a mixed artifact pair into one actionable line instead of a
|
|
94
|
+
missing function.
|
|
95
|
+
- Fallback still exists for missing, duplicate or empty sections, unsupported
|
|
96
|
+
file paths, unknown sections or headings, malformed content, transport and
|
|
97
|
+
budget failures, and `post-downgrade-invalid`.
|
|
98
|
+
|
|
99
|
+
## Validation
|
|
100
|
+
|
|
101
|
+
On Node 26.5.1 the release passed `npm run check` (100 Vitest files, 650 tests,
|
|
102
|
+
TypeScript builds and root typecheck), `npm run pack:check` in a clean consumer
|
|
103
|
+
for all three packages at 0.4.8 (251 core files, 7 reference-adapter files, 112
|
|
104
|
+
extension files), deterministic `npm run quality:compare` (candidate `0.9875`
|
|
105
|
+
against the frozen baseline `0.808156`), and
|
|
106
|
+
`npm run schema:context-persistence` (`passed: true`). No provider calls are
|
|
107
|
+
involved in this release procedure. `jev_verify` is not available in this
|
|
108
|
+
environment (project verification disabled), so the checks above were run
|
|
109
|
+
directly.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ds4-context-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Non-destructive, provider-independent context management for Pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"ds4-context-core": "0.4.
|
|
66
|
+
"ds4-context-core": "0.4.8",
|
|
67
67
|
"js-tiktoken": "1.0.21"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
@@ -6,11 +6,11 @@ import type {
|
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import type { CompactionThinkingLevel } from "ds4-context-core/config/config";
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
analyzeUnsupportedExactValueDowngrade,
|
|
10
10
|
classifyUnsupportedExactValueSpans,
|
|
11
11
|
groundSummaryFileSections,
|
|
12
12
|
validateSummary,
|
|
13
|
-
type
|
|
13
|
+
type ExactValueDowngradeResult,
|
|
14
14
|
type SummaryValidationInput,
|
|
15
15
|
type SummaryValidationIssue,
|
|
16
16
|
type SummaryValidationResult,
|
|
@@ -322,38 +322,38 @@ export async function generateValidatedSummary(
|
|
|
322
322
|
message: "Deterministic validation disabled by configuration",
|
|
323
323
|
}],
|
|
324
324
|
};
|
|
325
|
-
let
|
|
326
|
-
let
|
|
325
|
+
let exactDowngrade: ReturnType<typeof analyzeUnsupportedExactValueDowngrade> | undefined;
|
|
326
|
+
let exactDowngradeFailure: "post-downgrade-invalid" | undefined;
|
|
327
327
|
if (validation.status === "invalid") {
|
|
328
328
|
const errors = validation.issues.filter((issue) => issue.severity === "error");
|
|
329
329
|
const exactOnly = errors.length > 0
|
|
330
330
|
&& errors.every((issue) => issue.code === "unsupported-exact-value");
|
|
331
|
-
|
|
332
|
-
?
|
|
331
|
+
exactDowngrade = exactOnly
|
|
332
|
+
? analyzeUnsupportedExactValueDowngrade(content, validationInput)
|
|
333
333
|
: undefined;
|
|
334
|
-
const
|
|
335
|
-
if (
|
|
336
|
-
const repairedValidation = validateSummary(
|
|
334
|
+
const downgraded = exactDowngrade?.result;
|
|
335
|
+
if (downgraded) {
|
|
336
|
+
const repairedValidation = validateSummary(downgraded.content, validationInput);
|
|
337
337
|
if (repairedValidation.status !== "invalid") {
|
|
338
|
-
content =
|
|
338
|
+
content = downgraded.content;
|
|
339
339
|
validation = {
|
|
340
340
|
status: "warning",
|
|
341
|
-
issues: [...repairedValidation.issues, ...
|
|
341
|
+
issues: [...repairedValidation.issues, ...exactDowngradeIssues(downgraded)],
|
|
342
342
|
};
|
|
343
343
|
} else {
|
|
344
344
|
validation = repairedValidation;
|
|
345
|
-
|
|
345
|
+
exactDowngradeFailure = "post-downgrade-invalid";
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
349
|
if (validation.status === "invalid") {
|
|
350
350
|
const codes = unique(validation.issues.map((issue) => issue.code));
|
|
351
|
-
const repairDiagnostics =
|
|
352
|
-
? `; repair=${
|
|
351
|
+
const repairDiagnostics = exactDowngrade
|
|
352
|
+
? `; repair=${exactDowngradeFailure ?? exactDowngrade.status}; unsupportedSpans=${exactDowngrade.unsupportedSpans}; affectedBullets=${exactDowngrade.affectedBullets}`
|
|
353
353
|
: "";
|
|
354
354
|
const spanClassReport = validation.issues.some((issue) => issue.code === "unsupported-exact-value")
|
|
355
355
|
? classifyUnsupportedExactValueSpans(content, validationInput, {
|
|
356
|
-
...(
|
|
356
|
+
...(exactDowngrade ? { affectedBullets: exactDowngrade.affectedBullets } : {}),
|
|
357
357
|
})
|
|
358
358
|
: undefined;
|
|
359
359
|
throw new SummaryValidationError(
|
|
@@ -366,27 +366,17 @@ export async function generateValidatedSummary(
|
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
/**
|
|
369
|
-
* Record what the exact-value repair did, as
|
|
369
|
+
* Record what the exact-value repair did, as a count only: the disputed spans
|
|
370
370
|
* never reach logs, notifications or diagnostics because they may contain
|
|
371
371
|
* sensitive source material.
|
|
372
372
|
*/
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
if (repair.downgradedSpans > 0) {
|
|
383
|
-
issues.push({
|
|
384
|
-
code: "unsupported-exact-spans-unquoted",
|
|
385
|
-
severity: "warning",
|
|
386
|
-
message: `Retracted the quoting of ${repair.downgradedSpans} exact value(s) whose evidence rendering differs`,
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
return issues;
|
|
373
|
+
function exactDowngradeIssues(result: ExactValueDowngradeResult): SummaryValidationIssue[] {
|
|
374
|
+
if (result.downgradedSpans === 0) return [];
|
|
375
|
+
return [{
|
|
376
|
+
code: "unsupported-exact-spans-unquoted",
|
|
377
|
+
severity: "warning",
|
|
378
|
+
message: `Retracted the quoting of ${result.downgradedSpans} exact value(s) the evidence does not carry verbatim`,
|
|
379
|
+
}];
|
|
390
380
|
}
|
|
391
381
|
|
|
392
382
|
export function sumUsage(usages: readonly Usage[]): Usage {
|