dsh-jev-prune 0.1.0
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/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +177 -0
- package/README_zh.md +175 -0
- package/assets/banner.png +0 -0
- package/assets/banner.svg +73 -0
- package/assets/demo-poster.png +0 -0
- package/assets/demo.cast +6 -0
- package/assets/demo.gif +0 -0
- package/assets/demo.json +51 -0
- package/assets/two-layers.png +0 -0
- package/assets/two-layers.svg +118 -0
- package/cordis.patch.yml +3 -0
- package/demo/README.md +23 -0
- package/demo/fixtures.mjs +301 -0
- package/demo/render.py +31 -0
- package/demo/run.mjs +85 -0
- package/docs/ARCHITECTURE.md +63 -0
- package/docs/CONTRIBUTING.md +48 -0
- package/docs/PORTING.md +60 -0
- package/docs/RELEASING.md +27 -0
- package/docs/implementation.md +310 -0
- package/docs/measurements.md +16 -0
- package/docs/review-2026-10-05.md +44 -0
- package/examples/README.md +7 -0
- package/examples/minimal.yml +10 -0
- package/index.js +2043 -0
- package/package.json +77 -0
- package/scripts/inspect_session.mjs +235 -0
- package/scripts/verify_layout.mjs +24 -0
- package/scripts/verify_real_shapes.mjs +99 -0
- package/scripts/wire_profile.mjs +173 -0
- package/src/jev.js +320 -0
- package/src/prune.js +383 -0
- package/src/receipt.js +800 -0
- package/src/state.js +532 -0
- package/test/check.js +1971 -0
- package/test/smoke_apply.mjs +1359 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — 2026-10-06
|
|
4
|
+
|
|
5
|
+
- Concise English and Chinese project introductions; implementation/configuration history moved behind architecture links.
|
|
6
|
+
- Reproducible 24-second deterministic behavior recording, JSON evidence and terminal replay. Real plugin code runs against a simulated host with fixed judge scores.
|
|
7
|
+
- Release preparation and source-review findings covering PR #45 and issue #35.
|
|
8
|
+
|
|
9
|
+
### Runtime features
|
|
10
|
+
|
|
11
|
+
- Semantic result trimming with pressure budgets, bounded excerpts and native fallback.
|
|
12
|
+
- Deterministic receipts for full read-only steps and mixed parallel result bodies.
|
|
13
|
+
- Recent-node, evidence and tool-pairing checks; region-checkpoint text retrieval.
|
|
14
|
+
- Judge request retries, batch isolation and status/heartbeat diagnostics.
|
|
15
|
+
- Cross-platform smoke checks, coverage gates and a locked DSH dependency fixture.
|
|
16
|
+
|
|
17
|
+
Known limitations: pending receipt fencing does not identify external concurrent transactions; result caches do not invalidate on goal changes; replacement IDs are not directly restorable; small-sample layer-1 fallback can act at zero pressure ratio. See [review details](docs/review-2026-10-05.md).
|
|
18
|
+
|
|
19
|
+
Repository layout: helpers now live in `src/`, tests in `test/`, tools in `scripts/`, and project documentation in `docs/`. Public package imports and the root plugin entry remain compatible. Direct helper-script paths changed; use the updated documented commands.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-jev-prune contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# dsh-jev-prune
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
**Jev-judged context compaction for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).**
|
|
6
|
+
Structured judgments from [TypeSafe Jev](https://typesafe.ai) drive DSH's two-layer context compaction. The compaction algorithms are untouched; the judgment backend is pluggable (Jev / rules / a self-hosted model).
|
|
7
|
+
|
|
8
|
+
**English** · [简体中文](README_zh.md)
|
|
9
|
+
|
|
10
|
+
   [](https://github.com/yangyu666/dsh-jev-prune/actions/workflows/ci.yml)  [](https://dsh-plugin.org/plugins/yangyu666/dsh-jev-prune)
|
|
11
|
+
|
|
12
|
+
## The problem it solves
|
|
13
|
+
|
|
14
|
+
DSH's built-in context reclamation is **purely volumetric**. Once a tool result crosses a size threshold, its middle is chopped out and the head and tail are kept; region compaction, meanwhile, has the model **write a summary** to stand in for old history. The first approach cannot tell "this result is large but I still need it" from "this one is spent", and the second one invites summary hallucination.
|
|
15
|
+
|
|
16
|
+
This plugin replaces the decision in both places with Jev's structured output (`noul` / `choice`, returning calibrated probabilities), under one design rule:
|
|
17
|
+
|
|
18
|
+
> **What should not be generated by a model is not generated by a model.** Trimming only ever decides *keep* or *discard*; the original text is preserved verbatim. Region compaction injects a **deterministic receipt** produced by code, containing no model inference at all.
|
|
19
|
+
|
|
20
|
+
## The two layers
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
| Layer | Interception point | DSH default | This plugin |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| **1 · Result trimming** | `ctx.toolResultPruner.pruneSession` | Chops the middle once `thresholdChars` is exceeded | Jev decides, per tool result, whether it will still be needed. Needed ones are **never trimmed, however large**; stale ones are trimmed **however small** (unless shorter than `minCharsToPrune`); with no judgment available it falls back to DSH's original behaviour |
|
|
27
|
+
| **2 · Receipt compaction** | `ctx.compaction.summarize` + `compactRegion`, or a single-result surface replacement for mixed batches | The model reads the raw history and writes a summary | Moves fully eligible read-only steps out of the surface. In a parallel batch where only some results qualify, it keeps every call/result envelope and replaces only the eligible result bodies with **deterministic receipts**. Tool name, command, path, character count and seq are all computed by code |
|
|
28
|
+
|
|
29
|
+
A layer-2 receipt looks like this:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
[已压缩 · 确定性回执] 原历史 s25–s27 是 1 次工具调用(共约 16489 字符输出),
|
|
33
|
+
为释放上下文已移出。以下为事实清单(工具名/入参/字符数/seq 由代码算出;模型原话逐字引用,不含任何推断):
|
|
34
|
+
· s25 模型原话(逐字引用):identifiers:把版本字符串拆成标识符。Next inc.js.
|
|
35
|
+
· s27 read:C:\Users\you\project\src\state.js → 16489 字符输出
|
|
36
|
+
原始事件仍完整保存在会话日志中(seqs 25–27)。需要内容时重跑相同命令/读取相同文件即可;本回执不含对内容的解释。
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Parallel tool batches are evaluated per call/result pair. DSH 0.1.5 can replace one surface node or one balanced contiguous region, but cannot remove five pairs from a six-call assistant message in one atomic operation. For a mixed batch, the plugin therefore replaces each eligible `tool/result` body with a short receipt through DSH's native single-node `replace` protocol; rejected and recent results remain byte-for-byte unchanged, the assistant head stays intact, and tool pairing remains valid after every replacement. Results are matched to calls by `callId`, so completion order may differ from declaration order. A fully eligible batch still uses `compactRegion` and removes the whole balanced step.
|
|
40
|
+
|
|
41
|
+
> The receipt body is emitted by the plugin's own JavaScript, so its wording is Chinese today — as is the `/jev` status output. The `jev_*` tool descriptions are already English. Localizing the runtime strings is a separate change.
|
|
42
|
+
|
|
43
|
+
## Measured results
|
|
44
|
+
|
|
45
|
+
Numbers below come from a three-arm measurement of a 37-step "read every file in a directory, strictly one at a time" long task over `semver@6e05b76`: **A** = vanilla DSH (baseline), **B** = the plugin with `compactReceipts: false` (layer 1 only), **C** = the plugin with defaults (both layers). Every number is taken from the `usage` object the API actually returned in the DSH session logs — no estimator is involved in scoring.
|
|
46
|
+
|
|
47
|
+
**Layer 1 acts on every long run; the baseline never does.** Layer 1 trimmed stale results in every plugin-arm run (4–7 nodes per long run; arm A trims 0 by definition), and answers on the short/medium/long tasks were correct in every arm.
|
|
48
|
+
|
|
49
|
+
**Long tasks run on a fraction of the full-price input.** Uncached ("full-price") input tokens per completed 37-step run: baseline 75,781–87,872 vs full plugin 25,516–45,071 — roughly a third of the baseline at equal task scope. Report token classes separately: the cache-hit share of input is high (78–94%) and hit/miss prices differ by ~50×, so total-token comparisons mislead by design.
|
|
50
|
+
|
|
51
|
+
**Fewer destructive compactions — some of them receipts instead of summaries.** Per completed long run, DSH's own model-written summary compactions dropped from 31–40 (baseline) to 15–23 with the full plugin, of which 6–8 were replaced by deterministic receipts rendered by code. Layer 2 stays deliberately silent on short/medium tasks — its gates require a contiguous run of eligible read-only steps — so on those workloads the effect comes from layer 1. Even when layer 2 fires, DSH-initiated compactions still exist and fall back to model summaries: the plugin reduces them, it does not eliminate them.
|
|
52
|
+
|
|
53
|
+
**A failure mode we found and fixed.** Receipts replace a whole "call + result" step, including the assistant message that carried it; in one long run the model's intermediate notes were erased step by step (12 of 13) and it stopped issuing tool calls mid-task. Receipts now carry each step's **assistant-visible text verbatim** (`text` blocks only, `reasoning` drafts excluded, zero model generation; bounded by `receiptTextChars`, default 400, `0` disables). After the fix, the same long task completed in every run with correct answers.
|
|
54
|
+
|
|
55
|
+
[Measurement details and scope](docs/measurements.md)
|
|
56
|
+
|
|
57
|
+
## Gating (layer 2)
|
|
58
|
+
|
|
59
|
+
Moving a whole pair out of the surface is destructive, so the default is deliberately conservative. Every one of the following must hold:
|
|
60
|
+
|
|
61
|
+
- **Intersection of two axes**: `result` (is the content still needed) and `effect` (did the call change state outside the session) must *each* fall inside this session's trailing `compactQuantile`
|
|
62
|
+
- The tool is not in `neverCompactTools` (write-type calls are excluded by a hard rule, never by a probability)
|
|
63
|
+
- **Evidence guard**: results matching `error` / `assert` / `fail` / `todo` and friends are never moved out. If layer 1 has already trimmed a result, the guard follows `sourceEventSeqs` and scans the original event too
|
|
64
|
+
- Steps whose assistant **text** exceeds `maxStepTextChars`, or whose **`reasoning`** exceeds `maxStepReasoningChars`, are never moved out. The two are measured separately on purpose: long `text` means the step is delivering a conclusion worth keeping, while long `reasoning` is just scratch work — merging them into one budget let reasoning length alone silently shut layer 2 off
|
|
65
|
+
- Anything within the most recent `compactPreserveRecent` nodes is skipped by layer 2 (layer 1 uses `preserveRecent`)
|
|
66
|
+
- Both ends of the range must satisfy DSH's tool-pairing balance; the span must save at least `compactMinChars` characters; and the receipt must stay below `receiptMaxRatio` of the original content's tokens
|
|
67
|
+
|
|
68
|
+
Probabilities are consumed as **relative quantiles**, never as a fixed threshold: the output distribution of a small judge model is narrow, and only the relative ordering *within one session* carries stable information.
|
|
69
|
+
|
|
70
|
+
**Degradation on small populations.** Read-only tools are often a minority in write/execute-heavy sessions (measured: 1 in 6), which can leave a quantile population of only two or three items — too few for ordering to mean anything. Rather than giving up, the mode degrades to an **absolute floor**: both axes must fall below `floorThreshold` (default `0.2`, materially stricter than `compactThreshold`, compensating for the missing relative information). If the population is below `minCandidatesForFloor` (default `2`), nothing is moved out — a single sample is not a distribution. The default was lowered from `3` to `2` so that the two-candidate populations that batch-read sessions really produce are not skipped outright; one sample still never acts. Degradation is always reported in the report and the heartbeat; it never happens silently.
|
|
71
|
+
|
|
72
|
+
## Install and quick start
|
|
73
|
+
|
|
74
|
+
Requires Node `^22.19.0 || >=24.0.0`; tested against **DSH 0.1.5-rc.2**. The profile needs base pruner/compaction and tokenMeter services. Set `TYPESAFE_API_KEY` in the environment before starting DSH.
|
|
75
|
+
|
|
76
|
+
Install a pinned version:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
dsh plugin --profile web add github:yangyu666/dsh-jev-prune#v0.1.0
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Local development:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/yangyu666/dsh-jev-prune.git
|
|
86
|
+
cd dsh-jev-prune
|
|
87
|
+
git checkout v0.1.0
|
|
88
|
+
npm ci
|
|
89
|
+
npm run check
|
|
90
|
+
npm run smoke
|
|
91
|
+
dsh plugin --profile web add link:/absolute/path/to/dsh-jev-prune
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Without pnpm, run `node scripts/wire_profile.mjs <DSH_HOME> <profile-name>`. After host upgrades, call `jev_probe_shapes` to verify the event shapes.
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
Start with a dry run in the profile's plugin entry:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
- insert:
|
|
102
|
+
- id: jev-prune
|
|
103
|
+
name: dsh-jev-prune
|
|
104
|
+
config:
|
|
105
|
+
dryRun: true
|
|
106
|
+
judgeOn: pressure
|
|
107
|
+
softLimit: "55%"
|
|
108
|
+
compactReceipts: true
|
|
109
|
+
compactOn: pressure
|
|
110
|
+
compactSoftLimit: "70%"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
After inspecting `/jev`, set `dryRun: false` to apply reductions.
|
|
114
|
+
|
|
115
|
+
| Option | Default | Purpose |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `keepMode` | `budget` | Rank candidates; trimming budget follows context pressure. |
|
|
118
|
+
| `preserveRecent` / `compactPreserveRecent` | `4` / `1` | Independent recent-node protection. |
|
|
119
|
+
| `headChars` / `tailChars` | `600` / `200` | Verbatim content retained by layer 1. |
|
|
120
|
+
| `compactQuantile` | `0.34` | Tail fraction on each judgment axis; use the intersection. |
|
|
121
|
+
| `compactTools` | Read-only allow-list | Limits which tool pairs may be compacted. |
|
|
122
|
+
| `receiptTextChars` | `400` | Bounds verbatim assistant-visible notes in receipts. |
|
|
123
|
+
| `dryRun` | `false` | Judge and report without applying changes. |
|
|
124
|
+
|
|
125
|
+
[Full configuration and pressure-gate details](docs/implementation.md#configuration) · [Configuration example](examples/minimal.yml)
|
|
126
|
+
|
|
127
|
+
## In-session usage
|
|
128
|
+
|
|
129
|
+
| Entry point | Purpose |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `/jev`, `jev_prune_status` | Ledger for both layers: cached judgments, cumulative savings, takeover state, tool-name index |
|
|
132
|
+
| `jev_prune_now` | Force one layer-1 trimming pass |
|
|
133
|
+
| `jev_compact_now` (supports `dryRun`) | Force one layer-2 receipt compaction and list every gate's exclusion counts; in `dryRun` it also prints the full receipt text |
|
|
134
|
+
| `jev_restore` | Safety valve: fetch back the original text that a checkpoint moved out (read-only) |
|
|
135
|
+
| `jev_probe_shapes` | Print the real event shapes and the resolved tool names, for adapting to a different DSH version |
|
|
136
|
+
|
|
137
|
+
In normal operation both layers are driven automatically by context pressure; no manual step is needed.
|
|
138
|
+
|
|
139
|
+
## Demo
|
|
140
|
+
|
|
141
|
+

|
|
142
|
+
|
|
143
|
+
The recording runs the real plugin `apply()`, registered tools and replacement paths against a simulated DSH host with fixed judge probabilities. It shows trimming, preservation of a high-scored result, receipt compaction, and retrieval of a region checkpoint's original text. It does **not** measure live Jev quality or prove live-host compatibility.
|
|
144
|
+
|
|
145
|
+
[Replay, assertions and regeneration](demo/README.md) · [Machine-readable evidence](assets/demo.json)
|
|
146
|
+
|
|
147
|
+
## Limits and data handling
|
|
148
|
+
|
|
149
|
+
- Live judging sends history, paths, snippets and command output to TypeSafe and adds inference cost and latency.
|
|
150
|
+
- Automated CI covers helpers, simulated-host behavior and loading against a locked host dependency tree. It does not exercise a live DSH session end to end.
|
|
151
|
+
- Pending receipts are claim-once, but current fencing does not identify an external concurrent summary's transaction. Avoid concurrent compaction; see [review findings](docs/review-2026-10-05.md).
|
|
152
|
+
- Result judgments are cached by sequence, without task-goal invalidation. Small-population layer-1 fallback can trim at zero pressure ratio.
|
|
153
|
+
- `jev_restore` currently finds region summary checkpoints, truncates each returned event to 4,000 UTF-16 units, and does not directly resolve layer-1 or partial-result replacement IDs. Original events remain in the log.
|
|
154
|
+
|
|
155
|
+
## Layout and development
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
index.js Plugin entry (unchanged installation contract)
|
|
159
|
+
src/ Judge, pruning, receipts and event projection
|
|
160
|
+
test/ Helper and simulated-host checks
|
|
161
|
+
scripts/ Profile wiring and offline session inspection
|
|
162
|
+
docs/ Architecture, configuration, porting and releases
|
|
163
|
+
demo/ Reproducible behavior demonstration
|
|
164
|
+
assets/ Diagrams and recorded demonstration
|
|
165
|
+
examples/ Profile configuration examples
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npm run check
|
|
170
|
+
npm run smoke
|
|
171
|
+
npm run coverage
|
|
172
|
+
npm run demo
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
[Contributing](docs/CONTRIBUTING.md) · [Architecture](docs/ARCHITECTURE.md) · [Porting](docs/PORTING.md) · [Releasing](docs/RELEASING.md) · [Changelog](CHANGELOG.md)
|
|
176
|
+
|
|
177
|
+
[MIT](LICENSE)
|
package/README_zh.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# dsh-jev-prune
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
**Jev-judged context compaction for DeepSeek Harness.**
|
|
6
|
+
用 [TypeSafe Jev](https://typesafe.ai) 的结构化判断驱动 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)的两层上下文压缩。压缩算法不改动,判断后端可插拔(Jev / 规则 / 自托管模型)。
|
|
7
|
+
|
|
8
|
+
[English](README.md) · **简体中文**
|
|
9
|
+
|
|
10
|
+
   [](https://github.com/yangyu666/dsh-jev-prune/actions/workflows/ci.yml)  [](https://dsh-plugin.org/plugins/yangyu666/dsh-jev-prune)
|
|
11
|
+
|
|
12
|
+
## 它解决什么问题
|
|
13
|
+
|
|
14
|
+
DSH 自带的上下文回收是**纯体积**的:工具结果超过阈值就掐中间留头尾;区域压缩则让模型**写一段摘要**顶替旧历史。前者不认识"这条很大但后面还要用",后者会引入摘要幻觉。
|
|
15
|
+
|
|
16
|
+
本插件把这两处的判断都换成 Jev 的结构化输出(noul / choice,返回校准概率),并定了一条设计底线:
|
|
17
|
+
|
|
18
|
+
> **不该由模型生成的内容,就不让模型生成。** 裁剪只做留/删判断,原文逐字保留;区域压缩注入由代码生成的**确定性回执**,不含任何模型推断。
|
|
19
|
+
|
|
20
|
+
## 两层机制
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
| 层 | 接管点 | DSH 默认行为 | 本插件 |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| **1 · 结果裁剪** | `ctx.toolResultPruner.pruneSession` | 超过 `thresholdChars` 掐中间 | Jev 判定每个工具结果「接下来还要不要」,要的**再大也不裁**,过期的**再小也裁**(短于 `minCharsToPrune` 的除外);无判定时退回 DSH 原生行为 |
|
|
27
|
+
| **2 · 回执压缩** | `ctx.compaction.summarize` + `compactRegion`;混合批次则做单结果 surface 替换 | 模型读原历史、写摘要 | 全部合格的只读步骤整段移出;并行批次只有部分结果合格时,保留全部调用/结果外壳,只把合格结果正文换成**确定性回执**。工具名、命令、路径、字符数、seq 全由代码算出 |
|
|
28
|
+
|
|
29
|
+
第二层的回执长这样:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
[已压缩 · 确定性回执] 原历史 s25–s27 是 1 次工具调用(共约 16489 字符输出),
|
|
33
|
+
为释放上下文已移出。以下为事实清单(工具名/入参/字符数/seq 由代码算出;模型原话逐字引用,不含任何推断):
|
|
34
|
+
· s25 模型原话(逐字引用):identifiers:把版本字符串拆成标识符。Next inc.js.
|
|
35
|
+
· s27 read:C:\Users\you\project\src\state.js → 16489 字符输出
|
|
36
|
+
原始事件仍完整保存在会话日志中(seqs 25–27)。需要内容时重跑相同命令/读取相同文件即可;本回执不含对内容的解释。
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
并行工具批次按每一对 call/result 独立判定。DSH 0.1.5 只能原子替换一个 surface 节点,或替换一个配对平衡的连续区间,不能从同一条 6-call assistant 消息里一次抽走其中 5 对。因此遇到混合批次时,插件使用 DSH 原生的单节点 `replace` 协议,把每个合格 `tool/result` 的正文换成短回执;不合格及最近区结果逐字保留,assistant 头不改,每次替换前后工具配对都完整。call 与 result 按 `callId` 匹配,允许并行结果以不同顺序完成。整批全部合格时仍走 `compactRegion`,移出整个平衡步骤。
|
|
40
|
+
|
|
41
|
+
## 实测数据
|
|
42
|
+
|
|
43
|
+
以下数字来自一次三臂对照测量,任务是在 `semver@6e05b76` 上执行一个 **37 步"逐个读取目录下每个文件"** 的长任务:**A** = 原样 DSH(基线),**B** = 插件 + `compactReceipts: false`(仅第一层),**C** = 插件默认(两层全开)。每个数字都取自 DSH 会话日志里 **API 实际返回的 `usage`** —— 评分不使用任何估算器。
|
|
44
|
+
|
|
45
|
+
**第一层在每次长任务运行里都动作;基线从不动作。** 插件两臂的每一次长任务运行都有第一层裁剪发生(每次 4–7 个节点;A 臂按定义为 0),短/中/长三类任务上三臂的答案全部正确。
|
|
46
|
+
|
|
47
|
+
**长任务:全价输入只剩零头。** 每次完成的 37 步运行中,未命中(全价)输入 token:基线 75,781–87,872,完整插件 25,516–45,071 —— 同等任务量下约为基线的三分之一。必须分项报告 token:输入的缓存命中占比很高(78–94%),且命中/未命中单价相差约 50 倍,**用总 token 数比较会系统性误导**。
|
|
48
|
+
|
|
49
|
+
**破坏性压缩更少 —— 其中一部分由回执替代。** 每次完成的长任务运行里,DSH 自身发起的**模型摘要**压缩从基线的 31–40 次降到完整插件下的 15–23 次,其中 **6–8 次被代码渲染的确定性回执替代**。第二层在短/中任务上**有意保持静默** —— 它的门控要求一段连续合格的只读步骤 —— 所以那些负载上的收益来自第一层。即便第二层触发,DSH 自行发起的压缩仍然存在并回退为模型摘要:**插件减少它们,而不是消灭它们**。
|
|
50
|
+
|
|
51
|
+
**一个我们主动发现并修复的失效模式。** 回执替换的是整段「调用 + 结果」,其中包含承载它的 assistant 消息;一次长任务运行中,模型自己的中间记录被逐步抹掉(13 条只剩 1 条),随后它停止发起工具调用。现在回执会**逐字带上该步 assistant 的可见文本**(只取 `text` 块、排除 `reasoning` 草稿、零模型生成;长度由 `receiptTextChars` 约束,默认 400,设 `0` 关闭)。修复后,同一长任务在每次运行中都完成且答案正确。
|
|
52
|
+
|
|
53
|
+
[测量说明与适用边界](docs/measurements.md)
|
|
54
|
+
|
|
55
|
+
## 门控(第二层)
|
|
56
|
+
|
|
57
|
+
整对移出是破坏性动作,默认非常保守,需同时满足:
|
|
58
|
+
|
|
59
|
+
- **两轴判定取交集**:`result`(内容是否还需要)与 `effect`(调用是否改变了会话外状态)各自落在本次会话的尾部 `compactQuantile` 分位内
|
|
60
|
+
- 工具不在 `neverCompactTools`(改写类调用按硬规则永不移出)
|
|
61
|
+
- **证据守卫**:结果命中 `error` / `assert` / `fail` / `todo` 等词不移出;若第一层已经截断结果,守卫会沿 `sourceEventSeqs` 继续扫描原始事件
|
|
62
|
+
- assistant 消息的**可见文本**超过 `maxStepTextChars`、或**思考草稿**(`reasoning`)超过 `maxStepReasoningChars` 的步骤不移出。两者**分开统计**:text 长说明这一步在交代结论(该守),reasoning 长只是模型草稿写得多(不代表有承重信息)。合并成一个预算时,光靠 reasoning 长度就能把第二层静默关掉
|
|
63
|
+
- 第二层不移出最近 `compactPreserveRecent` 个节点(第一层仍使用 `preserveRecent`)
|
|
64
|
+
- 区间两端满足 DSH 的工具配对平衡;整段至少能省 `compactMinChars` 字符;回执 token 低于原内容的 `receiptMaxRatio`
|
|
65
|
+
|
|
66
|
+
概率的使用方式是**相对分位**而不是固定阈值:判断型小模型的输出分布很窄,只有同一会话内的相对排序携带稳定信息。
|
|
67
|
+
|
|
68
|
+
**小总体降级。** 只读工具在写/执行密集的会话里常常只占少数(实测只读 1/6),此时分位总体可能只有两三条——排序没有意义。这种情况**不是直接放弃**,而是降级为绝对下限模式:要求两轴**同时**低于 `floorThreshold`(默认 `0.2`,比 `compactThreshold` 明显更严,用来补偿"没有相对信息"这个缺口)。若样本连 `minCandidatesForFloor`(默认 2)都不到,则仍然不做——单条谈不上分布。该默认值由 3 降为 2,是为了让批量读会话实际产生的"两条候选"不再被整体跳过;单条仍然永不动作。降级发生时会在报告与心跳里给出说明,不会静默发生。
|
|
69
|
+
|
|
70
|
+
## 安装与快速开始
|
|
71
|
+
|
|
72
|
+
要求 Node `^22.19.0 || >=24.0.0`;针对 **DSH 0.1.5-rc.2** 验证。profile 需要基础裁剪、压缩与 tokenMeter 服务。启动 DSH 前在环境中设置 `TYPESAFE_API_KEY`。
|
|
73
|
+
|
|
74
|
+
固定版本安装:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
dsh plugin --profile web add github:yangyu666/dsh-jev-prune#v0.1.0
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
本地开发:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git clone https://github.com/yangyu666/dsh-jev-prune.git
|
|
84
|
+
cd dsh-jev-prune
|
|
85
|
+
git checkout v0.1.0
|
|
86
|
+
npm ci
|
|
87
|
+
npm run check
|
|
88
|
+
npm run smoke
|
|
89
|
+
dsh plugin --profile web add link:/absolute/path/to/dsh-jev-prune
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
无 pnpm 的手动接线:`node scripts/wire_profile.mjs <DSH_HOME> <profile名>`。升级宿主后执行 `jev_probe_shapes` 核对事件结构。
|
|
93
|
+
|
|
94
|
+
## 配置
|
|
95
|
+
|
|
96
|
+
先在 profile 的插件条目中开启 dry-run:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
- insert:
|
|
100
|
+
- id: jev-prune
|
|
101
|
+
name: dsh-jev-prune
|
|
102
|
+
config:
|
|
103
|
+
dryRun: true
|
|
104
|
+
judgeOn: pressure
|
|
105
|
+
softLimit: "55%"
|
|
106
|
+
compactReceipts: true
|
|
107
|
+
compactOn: pressure
|
|
108
|
+
compactSoftLimit: "70%"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
检查 `/jev` 的判定和排除原因后,设为 `dryRun: false` 执行压缩。
|
|
112
|
+
|
|
113
|
+
| 配置 | 默认 | 用途 |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `keepMode` | `budget` | 候选按概率排序,预算随上下文压力变化。 |
|
|
116
|
+
| `preserveRecent` / `compactPreserveRecent` | `4` / `1` | 两层独立的最近节点保护。 |
|
|
117
|
+
| `headChars` / `tailChars` | `600` / `200` | 第一层逐字保留的头尾长度。 |
|
|
118
|
+
| `compactQuantile` | `0.34` | 两轴尾部分位取交集。 |
|
|
119
|
+
| `compactTools` | 只读白名单 | 限制可压缩的工具配对。 |
|
|
120
|
+
| `receiptTextChars` | `400` | 限制回执里的助手可见原话长度。 |
|
|
121
|
+
| `dryRun` | `false` | 只判定、报告,不执行压缩。 |
|
|
122
|
+
|
|
123
|
+
[完整配置与压力门说明](docs/implementation.md#configuration) · [配置示例](examples/minimal.yml)
|
|
124
|
+
|
|
125
|
+
## 会话内使用
|
|
126
|
+
|
|
127
|
+
| 入口 | 用途 |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `/jev` 命令、`jev_prune_status` 工具 | 两层账本:判定缓存、累计节省、接管状态、工具名索引 |
|
|
130
|
+
| `jev_prune_now` | 手动触发一次第一层裁剪 |
|
|
131
|
+
| `jev_compact_now`(支持 `dryRun`) | 手动触发一次第二层回执压缩,逐条列出每个门控的排除计数与回执全文 |
|
|
132
|
+
| `jev_restore` | 安全阀:取回某个 checkpoint 移出 surface 的原始文本(只读) |
|
|
133
|
+
| `jev_probe_shapes` | 打印真实事件形状与工具名解析结果,用于适配不同 DSH 版本 |
|
|
134
|
+
|
|
135
|
+
正常情况下两层都由上下文压力自动驱动,无需手动介入。
|
|
136
|
+
|
|
137
|
+
## Demo
|
|
138
|
+
|
|
139
|
+

|
|
140
|
+
|
|
141
|
+
录制运行真实插件的 `apply()`、注册工具与替换路径,使用模拟 DSH 宿主和固定判定概率。依次展示裁剪、保留高分结果、生成回执和读取区域检查点原文。它不代表真实 Jev 判断质量,也不能证明真实宿主端到端兼容。
|
|
142
|
+
|
|
143
|
+
[回放、断言与重新生成](demo/README.md) · [原始演示记录](assets/demo.json)
|
|
144
|
+
|
|
145
|
+
## 限制与数据处理
|
|
146
|
+
|
|
147
|
+
- 在线判定会将历史、路径、代码片段和命令输出发送至 TypeSafe,并增加判定成本与延迟。
|
|
148
|
+
- CI 验证纯函数、模拟宿主行为和锁定宿主依赖树的模块加载;尚不覆盖真实 DSH 会话端到端执行。
|
|
149
|
+
- 回执只能领取一次,但当前令牌无法识别外部并发摘要的事务归属;应避免并发压缩。[审查记录](docs/review-2026-10-05.md)
|
|
150
|
+
- 结果判定按序号缓存,任务目标变化不会使其失效;第一层小样本降级可能在压力比例为零时裁剪。
|
|
151
|
+
- `jev_restore` 只查区域摘要检查点,每个事件最多返回 4,000 个 UTF-16 单元,尚不能直接解析第一层或逐结果替换的 ID。原始事件仍保存在日志中。
|
|
152
|
+
|
|
153
|
+
## 目录与开发
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
index.js 插件入口(保持原安装契约)
|
|
157
|
+
src/ 判定、裁剪、回执与事件转换
|
|
158
|
+
test/ 自检与模拟宿主测试
|
|
159
|
+
scripts/ 安装接线及离线会话检查工具
|
|
160
|
+
docs/ 架构、配置、移植和发布说明
|
|
161
|
+
demo/ 可复现演示与渲染脚本
|
|
162
|
+
assets/ 图解及演示录制
|
|
163
|
+
examples/ profile 配置示例
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npm run check
|
|
168
|
+
npm run smoke
|
|
169
|
+
npm run coverage
|
|
170
|
+
npm run demo
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
[贡献指南](docs/CONTRIBUTING.md) · [架构](docs/ARCHITECTURE.md) · [移植契约](docs/PORTING.md) · [发布说明](docs/RELEASING.md) · [变更记录](CHANGELOG.md)
|
|
174
|
+
|
|
175
|
+
[MIT](LICENSE)
|
|
Binary file
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="320" viewBox="0 0 1280 320" role="img" aria-label="dsh-jev-prune — Jev-judged context compaction for DeepSeek Harness">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
|
|
4
|
+
<stop offset="0" stop-color="#4CC9F0"/>
|
|
5
|
+
<stop offset="0.55" stop-color="#6EE7C8"/>
|
|
6
|
+
<stop offset="1" stop-color="#F0A868"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<radialGradient id="glowCyan" cx="0.5" cy="0.5" r="0.5">
|
|
9
|
+
<stop offset="0" stop-color="#4CC9F0" stop-opacity="0.22"/>
|
|
10
|
+
<stop offset="1" stop-color="#4CC9F0" stop-opacity="0"/>
|
|
11
|
+
</radialGradient>
|
|
12
|
+
<radialGradient id="glowAmber" cx="0.5" cy="0.5" r="0.5">
|
|
13
|
+
<stop offset="0" stop-color="#F0A868" stop-opacity="0.18"/>
|
|
14
|
+
<stop offset="1" stop-color="#F0A868" stop-opacity="0"/>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
</defs>
|
|
17
|
+
|
|
18
|
+
<rect width="1280" height="320" fill="#0B1220"/>
|
|
19
|
+
<ellipse cx="150" cy="40" rx="470" ry="300" fill="url(#glowCyan)"/>
|
|
20
|
+
<ellipse cx="1230" cy="300" rx="360" ry="260" fill="url(#glowAmber)"/>
|
|
21
|
+
<rect x="0" y="0" width="1280" height="3" fill="url(#accent)"/>
|
|
22
|
+
|
|
23
|
+
<!-- 左:字标 -->
|
|
24
|
+
<g font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'DejaVu Sans Mono', monospace">
|
|
25
|
+
<text x="72" y="108" font-size="12.5" letter-spacing="2.8" fill="#4CC9F0" fill-opacity="0.92">DEEPSEEK HARNESS PLUGIN</text>
|
|
26
|
+
<text x="72" y="168" font-size="54" font-weight="700" letter-spacing="-1">
|
|
27
|
+
<tspan fill="#E6EDF3">dsh-</tspan><tspan fill="#4CC9F0">jev</tspan><tspan fill="#E6EDF3">-prune</tspan>
|
|
28
|
+
</text>
|
|
29
|
+
<text x="72" y="206" font-size="17" fill="#B6C2CF">Jev-judged context compaction for DeepSeek Harness.</text>
|
|
30
|
+
<text x="72" y="230" font-size="17" fill="#7D8B9A">Deterministic receipts instead of model-written summaries.</text>
|
|
31
|
+
|
|
32
|
+
<g>
|
|
33
|
+
<rect x="72" y="256" width="250" height="30" rx="15" fill="#4CC9F0" fill-opacity="0.10" stroke="#4CC9F0" stroke-opacity="0.45"/>
|
|
34
|
+
<text x="197" y="276" font-size="12" letter-spacing="1.1" fill="#7FD9F5" text-anchor="middle">LAYER 1 · TOOL-RESULT TRIMMING</text>
|
|
35
|
+
<rect x="334" y="256" width="160" height="30" rx="15" fill="#F0A868" fill-opacity="0.10" stroke="#F0A868" stroke-opacity="0.45"/>
|
|
36
|
+
<text x="414" y="276" font-size="12" letter-spacing="1.1" fill="#F0BE8A" text-anchor="middle">LAYER 2 · RECEIPTS</text>
|
|
37
|
+
</g>
|
|
38
|
+
</g>
|
|
39
|
+
|
|
40
|
+
<!-- 右:上下文表面收缩为回执(8 列栅格:x=720..1210,列宽 56,间距 6) -->
|
|
41
|
+
<g font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, 'DejaVu Sans Mono', monospace">
|
|
42
|
+
<text x="720" y="100" font-size="12.5" letter-spacing="1.6" fill="#7D8B9A">CONTEXT SURFACE · 8 NODES</text>
|
|
43
|
+
<g fill="#4CC9F0" fill-opacity="0.22" stroke="#4CC9F0" stroke-opacity="0.50">
|
|
44
|
+
<rect x="720" y="112" width="56" height="16" rx="4"/>
|
|
45
|
+
<rect x="782" y="112" width="56" height="16" rx="4"/>
|
|
46
|
+
<rect x="844" y="112" width="56" height="16" rx="4"/>
|
|
47
|
+
<rect x="906" y="112" width="56" height="16" rx="4"/>
|
|
48
|
+
<rect x="968" y="112" width="56" height="16" rx="4"/>
|
|
49
|
+
<rect x="1030" y="112" width="56" height="16" rx="4"/>
|
|
50
|
+
<rect x="1092" y="112" width="56" height="16" rx="4"/>
|
|
51
|
+
<rect x="1154" y="112" width="56" height="16" rx="4"/>
|
|
52
|
+
</g>
|
|
53
|
+
|
|
54
|
+
<g stroke="#5C6B7A" stroke-width="1.6" fill="none">
|
|
55
|
+
<path d="M965 140 L965 160"/>
|
|
56
|
+
<path d="M960 155 L965 161 L970 155"/>
|
|
57
|
+
</g>
|
|
58
|
+
<text x="979" y="157" font-size="12.5" fill="#7D8B9A">layer 1 + layer 2</text>
|
|
59
|
+
|
|
60
|
+
<text x="720" y="188" font-size="12.5" letter-spacing="1.6" fill="#7D8B9A">AFTER COMPACTION</text>
|
|
61
|
+
<g fill="#4CC9F0" fill-opacity="0.22" stroke="#4CC9F0" stroke-opacity="0.50">
|
|
62
|
+
<rect x="720" y="200" width="56" height="22" rx="4"/>
|
|
63
|
+
<rect x="782" y="200" width="56" height="22" rx="4"/>
|
|
64
|
+
<rect x="844" y="200" width="56" height="22" rx="4"/>
|
|
65
|
+
</g>
|
|
66
|
+
<g>
|
|
67
|
+
<rect x="906" y="200" width="304" height="22" rx="4" fill="#F0A868" fill-opacity="0.09" stroke="#F0A868" stroke-opacity="0.55" stroke-dasharray="5 4"/>
|
|
68
|
+
<text x="1058" y="215" font-size="13" fill="#F0BE8A" text-anchor="middle">receipt · s27 read → 16489 chars</text>
|
|
69
|
+
</g>
|
|
70
|
+
</g>
|
|
71
|
+
|
|
72
|
+
<rect x="0" y="317" width="1280" height="1" fill="#FFFFFF" fill-opacity="0.07"/>
|
|
73
|
+
</svg>
|
|
Binary file
|
package/assets/demo.cast
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{"version":2,"width":120,"height":24,"title":"dsh-jev-prune deterministic demo (simulated host)","env":{"TERM":"xterm-256color"}}
|
|
2
|
+
[0,"o","\u001b[2J\u001b[H01 / Inspect long tool output\r\n\r\nREAL PLUGIN / SIMULATED DSH HOST / FIXED JUDGE SCORES\r\nNo live TypeSafe requests. No live-host compatibility claim.\r\nRead s3: 6,000 characters; keep score 0.05\r\nRead s7: 6,000 characters; keep score 0.95 (protected)\r\n"]
|
|
3
|
+
[6,"o","\u001b[2J\u001b[H02 / Trim spent output; preserve useful evidence\r\n\r\nActual pruneSession result: 2 outputs trimmed\r\ns3: 6000 -> 848 characters\r\ns7: unchanged, byte-for-byte equality assertion passed\r\nOriginal s3 remains in the session event log\r\n"]
|
|
4
|
+
[12,"o","\u001b[2J\u001b[H03 / Inject a deterministic region receipt\r\n\r\njev_compact_now invoked the real registered tool\r\nProvider: jev-receipt / Model: deterministic\r\nOriginal region: s2-s12\r\nProtected s7 remains on the surface\r\n[已压缩 · 确定性回执] 原历史 s2–s12 是 2 次工具调用(共约 1696 字符输出),为释放上下文已移出。以下为事实清单(工具名/入参/字符数/seq 由代码算出;模型原话仅作原文摘录,插件不新增推断):\r\n· s2 模型原话(原文摘录):看一下。\r\n· s10 Read:server/src/game/river.ts → 848 字符输出\r\n· s4 模型原话(原文摘录):看一下。\r\n"]
|
|
5
|
+
[18,"o","\u001b[2J\u001b[H04 / Retrieve checkpoint text without changing the surface\r\n\r\njev_restore({ seq: 13 }) returned hidden region text\r\nArchived tool output excerpt found: assertion passed\r\nSurface unchanged: assertion passed\r\nScope: REGION checkpoint only; each event is capped at 4,000 units\r\nLayer-1 / partial-result IDs are not directly restorable yet\r\nAll demonstration assertions passed\r\n"]
|
|
6
|
+
[24,"o","\r\nDemo complete.\r\n"]
|
package/assets/demo.gif
ADDED
|
Binary file
|
package/assets/demo.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": 1,
|
|
3
|
+
"host": "simulated",
|
|
4
|
+
"judge": "fixed probabilities",
|
|
5
|
+
"liveApiCalls": 0,
|
|
6
|
+
"stages": [
|
|
7
|
+
{
|
|
8
|
+
"title": "01 / Inspect long tool output",
|
|
9
|
+
"lines": [
|
|
10
|
+
"REAL PLUGIN / SIMULATED DSH HOST / FIXED JUDGE SCORES",
|
|
11
|
+
"No live TypeSafe requests. No live-host compatibility claim.",
|
|
12
|
+
"Read s3: 6,000 characters; keep score 0.05",
|
|
13
|
+
"Read s7: 6,000 characters; keep score 0.95 (protected)"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"title": "02 / Trim spent output; preserve useful evidence",
|
|
18
|
+
"lines": [
|
|
19
|
+
"Actual pruneSession result: 2 outputs trimmed",
|
|
20
|
+
"s3: 6000 -> 848 characters",
|
|
21
|
+
"s7: unchanged, byte-for-byte equality assertion passed",
|
|
22
|
+
"Original s3 remains in the session event log"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"title": "03 / Inject a deterministic region receipt",
|
|
27
|
+
"lines": [
|
|
28
|
+
"jev_compact_now invoked the real registered tool",
|
|
29
|
+
"Provider: jev-receipt / Model: deterministic",
|
|
30
|
+
"Original region: s2-s12",
|
|
31
|
+
"Protected s7 remains on the surface",
|
|
32
|
+
"[已压缩 · 确定性回执] 原历史 s2–s12 是 2 次工具调用(共约 1696 字符输出),为释放上下文已移出。以下为事实清单(工具名/入参/字符数/seq 由代码算出;模型原话仅作原文摘录,插件不新增推断):",
|
|
33
|
+
"· s2 模型原话(原文摘录):看一下。",
|
|
34
|
+
"· s10 Read:server/src/game/river.ts → 848 字符输出",
|
|
35
|
+
"· s4 模型原话(原文摘录):看一下。"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"title": "04 / Retrieve checkpoint text without changing the surface",
|
|
40
|
+
"lines": [
|
|
41
|
+
"jev_restore({ seq: 13 }) returned hidden region text",
|
|
42
|
+
"Archived tool output excerpt found: assertion passed",
|
|
43
|
+
"Surface unchanged: assertion passed",
|
|
44
|
+
"Scope: REGION checkpoint only; each event is capped at 4,000 units",
|
|
45
|
+
"Layer-1 / partial-result IDs are not directly restorable yet",
|
|
46
|
+
"All demonstration assertions passed"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"assertionsPassed": true
|
|
51
|
+
}
|
|
Binary file
|