@deepseek-ai/dsh-session-format-v2-to-v3 0.1.5-alpha.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepSeek
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.
@@ -0,0 +1,6 @@
1
+ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
+ # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
+ # after editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/session/session-format-v2-to-v3/README.md
5
+ README.md: c9ea46c14bce7e84c23af2a06e0cd310f13397cb
6
+ README.zh.md: 64306531b7fcf2c32815e3bbc3c73cb52b6449cf
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ ---
2
+ description: "The complete V2-to-V3 Session conversion: system heads, audited references, PTC and preset names, canonical envelopes, preservation, and refusal."
3
+ kind: "package-library"
4
+ ---
5
+
6
+ # @deepseek-ai/dsh-session-format-v2-to-v3
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ Restore supported released V2 Sessions as V3 without changing historical request meaning. This page is the single specification for this adjacent edge: what it transforms, preserves, and refuses, followed separately by native V3 admission. The library promotes system prompts into messages, remaps local event references, translates PTC and preset names, and canonicalizes envelopes. Persistence consumes it through the static catalog; the library does not read or publish files.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [V2-to-V3 specification](#v2-to-v3-specification)
18
+ - [Header and preset references](#header-and-presets)
19
+ - [System head and message identities](#system-head)
20
+ - [Sequence references and inheritance](#sequence-references)
21
+ - [PTC vocabulary](#ptc-vocabulary)
22
+ - [Canonical envelopes and tool errors](#canonical-envelopes)
23
+ - [Delivery guards](#delivery-guards)
24
+ - [Source audit and refusal](#source-audit)
25
+ - [Native V3 admission](#native-v3-admission)
26
+ - [Understand the implementation](#understand-the-implementation)
27
+ - [Further Exploration](#further-exploration)
28
+ - [Model Experience](#model-experience)
29
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
30
+ - [Dev Note](#dev-note)
31
+
32
+ -----
33
+
34
+ <a id="use-this-package"></a>
35
+ ## Use this package
36
+
37
+ ### When to use it
38
+
39
+ Use the [catalog](../session-format-catalog/README.md) to restore a Session. Direct imports serve catalog assembly and tests; this library has no Cordis mount configuration. The [public exports](src/index.ts) provide the migration declaration, released V2 source codec, V3 target codec, target header validator, and target restorer.
40
+
41
+ ### Entry point
42
+
43
+ The header-only operation does not convert or validate an event body:
44
+
45
+ ```text
46
+ const targetHeader = sessionFormatV2ToV3.migrateHeader(sourceHeader)
47
+ ```
48
+
49
+ Full restoration feeds decoded events through a fresh stage and validates the target artifact. Callers must not treat partial stage emissions as a successful restore: an error can occur at a later event or at `finish()`. The [format protocol](../session-format/README.md) owns stage scheduling and catalog error handling; [JSONL persistence](../session-persistence-jsonl/README.md) owns read preparation and immutable successor publication.
50
+
51
+ -----
52
+
53
+ <a id="v2-to-v3-specification"></a>
54
+ ## V2-to-V3 specification
55
+
56
+ The complete edge is not an identity conversion. It preserves the relative order and timestamps of source events and the meaning of each historical request, but inserted system events change event count, dense sequence positions, local references, and inherited cuts. PTC/preset translation and final envelope canonicalization add no events. Only the named fields below change; preservation applies to admitted input, not arbitrary unaudited extensions.
57
+
58
+ <a id="header-and-presets"></a>
59
+ ### Header and preset references
60
+
61
+ The logical header changes `version: 2` to `version: 3`. It retains `id`, `createdAt`, `isSeeded`, `delegationDepth`, and admitted optional `cwd`, `parentSession`, and `origin`. The exact preset id `code` becomes `ptc` in `header.agentPreset` and every `agent-preset/selected.data.agentPreset`, including inherited and local selections. Other strings and an absent header preset remain unchanged. Selection payloads require a string preset id and reject unaudited members.
62
+
63
+ This conversion does not inspect installed presets or rewrite other occurrences of `code`. Released V0/V1 data receives it only after the frozen preceding edges reach V2. Native V3 custom preset ids are not renamed, and `settings.yaml` is outside this package.
64
+
65
+ <a id="system-head"></a>
66
+ ### System head and message identities
67
+
68
+ The first `step/start` is followed immediately by an empty `system/message` append, even if the step aborts without a request. Later steps do not create another head. A log with no step and no surface receives no head or invented request.
69
+
70
+ At every `request/header`, absent `data.header.system` means the empty prompt; otherwise its string is compared exactly with the current prompt. A change inserts a system message immediately before that request header, replacing exactly the current protected head and citing it in `sourceEventSeqs`. An unchanged prompt inserts nothing. Empty strings and absent fields clear an earlier prompt; whitespace-only strings remain nonempty text. Every request header loses `data.header.system`, regardless of whether a replacement was needed.
71
+
72
+ Synthetic messages carry the open step's `turn` and `step`, the anchor event's `time`, role `system`, and source `{ kind: 'plugin', plugin: '@deepseek-ai/dsh-system-prompt' }`. Empty prompts use `content: []`; other prompts use one text block containing the exact string. The first append has no provenance; each replacement uses the preceding head's target sequence for both endpoints and its sole source reference. Empty heads retain protection but produce no model message.
73
+
74
+ Each synthetic id is `v2-to-v3-system-` followed by the hexadecimal SHA-256 of `JSON.stringify(['session-format-v2-to-v3', sourceHeader.id, anchor.seq, anchor.type])`. The anchor is the source `step/start` for initial creation or the changed `request/header` for replacement. Collisions with generated or source message ids are refused in either encounter order, including ids in inbox insertions and title-request messages. Existing message ids never change. In particular, a `TOOL_NOT_STARTED` repair id retains its canonical historical `interrupted-tool-result-<callId>-<integer>` suffix; that suffix is not a target sequence coordinate.
75
+
76
+ <a id="sequence-references"></a>
77
+ ### Sequence references and inheritance
78
+
79
+ Source events must be dense from zero. Each original event receives its target position after any preceding insertion. The [reference mapper](src/references.ts) changes only these same-artifact references; every referenced source position must name an earlier event with an established mapping:
80
+
81
+ | Owner | Fields remapped |
82
+ |---|---|
83
+ | Surface envelope | `sourceEventSeqs[]`; `surfaceOp.start/end` before their canonical rename |
84
+ | `command/done.data` | `sourceEventSeq` when present |
85
+ | `compaction/summary.data` and `compaction/prune.data` | `shadowedRange.start/end` and `shadowedSeqs[]` |
86
+ | `session/title.data` and `session/title-llm-request.data` | `messageSeqs[]` |
87
+
88
+ There is no recursive numeric-field rewrite. Delivery `throughSeq` and `sessionFormatVersion`, session-reference `capturedThroughSeq` and `capturedFormatVersion`, workflow-local `seq`, stream block indices, turn/step numbers, inbox indices, token/byte counts, and all ids keep their source values. Embedded assistant streams, model replay state, tool arguments/results, title-request input text and `data.system` retain their recorded meaning. Compaction payload endpoints keep the names `start/end`; only envelope replacement endpoints are renamed.
89
+
90
+ For a seeded Session, the last `session/end-seed` with `data.inherited: true` identifies the source cut. Its source sequence is the inherited event count, excluding that marker; its mapped target sequence is the target cut. Synthetic events before it are inherited, and later ones are local. An untagged marker does not establish the cut. A supplied `sourceInheritedEventCount` must agree; a seeded log without a marker and an unseeded log with one are refused. Unseeded stages expose `headerInheritedEventCount: 0`; seeded stages leave it unknown until `finish()` derives the exact cut. This also supports V0/V1 chains whose preceding stage changes event count and cannot supply the cut before EOF.
91
+
92
+ <a id="ptc-vocabulary"></a>
93
+ ### PTC vocabulary
94
+
95
+ The exact event tags `tool/code-dispatch-start` and `tool/code-dispatch` become `tool/ptc-dispatch-start` and `tool/ptc-dispatch`. Their payloads retain their values. Plugin attribution changes from exactly `tools-code-mode` to `tools-ptc` only when `source.kind === 'plugin'` in these three slots:
96
+
97
+ - `user/message.data.source.plugin`
98
+ - `agent/inbox/spliced.data.inserted[].source.plugin`
99
+ - `session/title-llm-request.data.messages[].source.plugin`
100
+
101
+ Similar plugin names, other source kinds, arbitrary text, nested JSON, and historical ids including `:code:` remain unchanged. This does not rename `run_code` or its `code` argument. V2 source events already using either reserved V3 PTC tag are refused even when ignorable; an opaque source extension must not acquire current lifecycle meaning through migration.
102
+
103
+ <a id="canonical-envelopes"></a>
104
+ ### Canonical envelopes and tool errors
105
+
106
+ After structural insertion and reference remapping, canonicalization converts exact envelope replacements `{ op: 'replace', start, end }` to `{ op: 'replace', startSeq, endSeq }` on original and synthetic events. It omits exactly `tools: []` and `adapterDefaults: {}` from `request/header.data.header`. This final operation preserves its input event count, coordinates, timestamps, order, and inherited cut; it neither remaps twice nor normalizes unrelated empty values such as `config.stop: []`.
107
+
108
+ All four V3 surface types (`system/message`, `user/message`, `assistant/message`, `tool/result`) require `surfaceOp`. Assistant messages alone forbid `sourceEventSeqs`; for the others, a supplied list must be nonempty, unique, and refer only to earlier events. Known log-only events allow neither surface metadata field. Replacements allow no aliases or extra keys. Their endpoints identify an inclusive span in current surface order, not numeric sequence order; restoration checks live membership, endpoint order, and complete provenance coverage.
109
+
110
+ Source surface events already require placement; migration does not invent missing append markers. A `tool/result` with `data.error` requires its single tool-result block to carry `isError: true`. Failed results may omit structured error identity. Contradictory outcomes are refused, never repaired by adding `isError` or deleting diagnostics. Ordinary tool and PTC lifecycle relationships still require validation after these event-local checks.
111
+
112
+ <a id="delivery-guards"></a>
113
+ ### Delivery guards
114
+
115
+ A V2 `session-log-deepseek/delivery-accepted` with `data.sessionFormatVersion === 3` is refused, not promoted into a V3 upload watermark. Markers for other generations retain their payloads, including an absent generation and future non-target generations. A V2-generation marker must have a valid earlier `throughSeq`; if it names a different Session, it is permitted only in the inherited prefix of a Session with `parentSession`. A foreign local marker or one without parent metadata is refused. The marker's envelope sequence changes normally; its captured acceptance coordinates do not.
116
+
117
+ <a id="source-audit"></a>
118
+ ### Source audit and refusal
119
+
120
+ Migration classifies the [released V2 event inventory](../session-format-v1-to-v2/src/dispositions.ts), including log-only `assistant/attempt`, plus `feedback/message-put` and `feedback/message-delete`. The [payload validator](src/payload.ts) applies exact admitted envelope and payload members and released nested validation. Unknown events, even ignorable ones, and unaudited members at checked records are refused. Message-source classification covers the five Message slots below: unknown source kinds are refused, while agent relay attribution is admitted without interpreting ids as Session references.
121
+
122
+ The content audit admits exactly `text`, `reasoning`, `image`, `file`, `tool-call`, and `tool-result`. It validates owned block fields and recursively audits every nested `tool-result.content` in this finite set of positions:
123
+
124
+ | Owner | Audited content |
125
+ |---|---|
126
+ | Five Message slots | `user/message.data.content`; `assistant/message.data.message.content`; `tool/result.data.message.content`; `agent/inbox/spliced.data.inserted[].content`; `session/title-llm-request.data.messages[].content` |
127
+ | Queued team message | `team/message/queued.data.message.content`; the historical Team payload remains `version: 1` with `message.delivery` |
128
+ | Compaction output | `compaction/summary.data.summary` and optional `compaction/summary.data.rawOutput` |
129
+ | PTC predecessor output | `tool/code-dispatch.data.content` |
130
+ | Embedded assistant streams | In `assistant/message.data.stream[]` and `assistant/attempt.data.stream[]`, raw `type: 'chunk'` records: `chunk.block` for `block-end` and `chunk.blockType` for `block-start`, including starts with no completed block |
131
+
132
+ All positions use the same historical kind set; a partial start cannot introduce an unknown kind. Unknown kinds and malformed owned blocks refuse the whole migration; catalog restoration reports `SessionFormatUnsupportedMigrationError`. The diagnostic identifies the source event type, source sequence, full indexed payload path, and violated rule. Unknown-kind errors name the offending kind; malformed known-block errors name the kind and field error. A malformed content container or missing block reports its location without inventing a kind. Persistence leaves source bytes unchanged and publishes no successor on refusal.
133
+
134
+ Admission does not rewrite content. In particular, embedded stream bytes are preserved although their owned block fields are inspected. Tool arguments, `replayState.response`, and `replayState.blocks` remain opaque; matching field names inside arbitrary JSON do not trigger this audit. File attachment metadata is validated without interpreting ids or byte counts as Session references. This is not a general schema audit or recursive coordinate inference, and native V3 extension acceptance is separate.
135
+
136
+ A surface event before the first step, a changed prompt outside an open step, or a generated-id collision raises `SessionFormatUnsupportedMigrationError` rather than moving events or inventing ownership. Malformed source fields, missing placement, invalid references, inconsistent cuts, delivery violations, and contradictory tool results raise format errors in the direct stage or target validator. The catalog reports migration-stage and transformed-target validation failures as typed unsupported migration; physical decoding failures remain corruption under its selected recovery policy. No source or target repair, generation fallback, or file rewrite is performed by this edge.
137
+
138
+ -----
139
+
140
+ <a id="native-v3-admission"></a>
141
+ ## Native V3 admission
142
+
143
+ Input already marked V3 does not run V2-to-V3. Native catalog reads with `validation: 'transformed'` apply codec checks only and skip artifact restoration; full relationships, open-step ownership, protected-head operations, and vocabulary checks require `restoreReleasedV3Artifact` or catalog `validation: 'current'`. The following rules distinguish those restoration checks from codec admission; they are not additional historical transformations:
144
+
145
+ - Native V3 admits in-history system appends, non-head system replacements, and compaction of non-head system nodes. System messages require valid payloads and matching open-step ownership. The first surface system head can be replaced only by a system message covering exactly that head; ordinary replacements and compaction cannot consume it. Migration itself produces only the initial head and head replacements, not route-dependent in-history updates.
146
+ - Native V3 rejects every `request/header.data.header.system`, even empty or malformed, and rejects noncanonical replacement spellings and the two empty header optionals. It preserves whitespace content, empty stop lists, and admitted nested header/source/data extensions. That extension admission does not widen the V2 source audit or the exact logical Session header fields.
147
+ - Required predecessor PTC tags are refused even if installed. Obsolete or unknown ignorable events remain opaque, including their logical metadata, and cannot satisfy current PTC relationships. Installed ordinary event additions are admitted as log-only envelopes; unknown required types are refused by vocabulary-aware restoration. The physical codec still enforces released framing and provenance encoding.
148
+ - V3 event-local checks run before encoding and after decoding. Raw retired-system-header, malformed-system-payload, and required predecessor-PTC refusal run before recoverable suppression, including after corrupt rows. Strict reads reject canonical errors immediately. Recoverable canonical decoding withholds the first invalid event and its suffix; a later `turn/end` establishes a commit and rejects that suffix. Only accepted inherited markers count; a seeded accepted prefix without one is refused. Unclassified event metadata is deferred to vocabulary-aware restoration rather than discarded as canonical corruption, so it cannot hide an unknown required type.
149
+
150
+ -----
151
+
152
+ <a id="understand-the-implementation"></a>
153
+ ## Understand the implementation
154
+
155
+ <details>
156
+ <summary>Implementation internals — click to expand</summary>
157
+
158
+ The [stage](src/migration.ts) owns synchronous per-artifact sequence maps, message identity sets, and prompt/lifecycle state. Compact runs expand incrementally. The [codec](src/codec.ts) reuses frozen V2 framing; the [restorer](src/validation.ts) validates V3 structure before giving frozen ordinary relationship validation a private system/PTC/repair-id and endpoint view. That view retains the actual target generation for delivery checks and never escapes: restoration returns the original V3 artifact and identities. Frozen V0-to-V1 and V1-to-V2 semantics remain unchanged. No runtime invariant companion is published because this library owns no independently observable registrations or state replicas.
159
+
160
+ [Combined catalog tests](tests/combined-migration.spec.ts) exercise transformation composition and native reopen; [migration tests](tests/migration.spec.ts) and [canonical tests](tests/canonical-envelopes.spec.ts) pin preservation and refusal. [Persistence integration](../session-persistence-jsonl/tests/v2-ptc-migration.spec.ts) owns publication evidence. The [released-format decision](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md) owns the rationale for testing adjacent composition separately from native admission.
161
+
162
+ </details>
163
+
164
+ -----
165
+
166
+ <a id="further-exploration"></a>
167
+ ## Further Exploration
168
+
169
+ - [Released V1 to V2](../session-format-v1-to-v2/README.md) — frozen preceding conversion and source codec.
170
+ - [System-prompt surface decision](../../../.agents/notes/implemented/architecture/2026-09-02-system-prompt-as-surface-node.md) — prompt ownership and protected-head rationale.
171
+ - [Canonical V3 envelope decision](../../../.agents/notes/implemented/architecture/2026-09-06-v3-canonical-session-envelopes.md) — strict acceptance and validation ownership.
172
+
173
+ -----
174
+
175
+ <a id="model-experience"></a>
176
+ ## Model Experience
177
+
178
+ ### Historical restoration
179
+
180
+ #### What the model sees
181
+
182
+ Each historical request retains its prompt text and ordinary message content. Empty system heads produce no model message. PTC attribution uses `tools-ptc`; dispatch events remain log-only.
183
+
184
+ #### Token effect
185
+
186
+ The edge adds no model-visible text; it moves the recorded prompt from the request header into the message history.
187
+
188
+ #### KV Cache effect
189
+
190
+ The edge preserves historical request meaning and model configuration; it does not guarantee provider cache hits or byte-identical native V3 recordings.
191
+
192
+ ## Known Limitations and Deferred Work
193
+
194
+ <a id="known-limitations-and-deferred-work"></a>
195
+
196
+ - **Historical preset ambiguity** — released `code` references cannot distinguish a custom preset with the legacy built-in id; the [exact rename](#header-and-presets) is host-independent.
197
+ - **No file or settings migration** — this package never changes committed generations or `settings.yaml`. Persistence owns publishing the final successor; an existing V3 generation does not rerun its incoming edge. V3 is unreleased; compatibility or repair for already-written development V3 files is not provided.
198
+
199
+ <a id="dev-note"></a>
200
+ ### Dev Note
201
+
202
+ <details>
203
+ <summary>Working context for maintainers — click to expand</summary>
204
+
205
+ None.
206
+
207
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,207 @@
1
+ ---
2
+ description: "完整的 V2 到 V3 Session 转换:系统头节点、经过审计的引用、PTC 与预设名称、规范信封、保留与拒绝规则。"
3
+ kind: "package-library"
4
+ ---
5
+
6
+ # @deepseek-ai/dsh-session-format-v2-to-v3
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## 概述
11
+
12
+ 将受支持的已发布 V2 Session 恢复为 V3,同时保留历史请求含义。本页是这条相邻迁移边的单一规范真源:先说明转换、保留与拒绝的内容,再单独说明原生 V3 准入。本库将系统提示词提升为消息,重映射本地事件引用,转换 PTC 与预设名称,并规范化信封。持久化通过静态目录使用本库;本库不读取或发布文件。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [V2 到 V3 规范](#v2-to-v3-specification)
18
+ - [头部与预设引用](#header-and-presets)
19
+ - [系统头节点与消息身份](#system-head)
20
+ - [序列引用与继承](#sequence-references)
21
+ - [PTC 词汇](#ptc-vocabulary)
22
+ - [规范信封与工具错误](#canonical-envelopes)
23
+ - [投递保护](#delivery-guards)
24
+ - [源审计与拒绝](#source-audit)
25
+ - [原生 V3 准入](#native-v3-admission)
26
+ - [理解实现](#understand-the-implementation)
27
+ - [深入探索](#further-exploration)
28
+ - [模型体验](#model-experience)
29
+ - [已知限制与后续工作](#known-limitations-and-deferred-work)
30
+ - [开发备注](#dev-note)
31
+
32
+ -----
33
+
34
+ <a id="use-this-package"></a>
35
+ ## 使用本包
36
+
37
+ ### 使用场景
38
+
39
+ 使用[目录](../session-format-catalog/README.zh.md)恢复 Session。直接导入用于目录组装和测试;本库没有 Cordis 挂载配置。[公共导出](src/index.ts)提供迁移声明、已发布 V2 源编解码器、V3 目标编解码器、目标头校验器和目标恢复器。
40
+
41
+ ### 入口
42
+
43
+ 仅头部操作不会转换或校验事件正文:
44
+
45
+ ```text
46
+ const targetHeader = sessionFormatV2ToV3.migrateHeader(sourceHeader)
47
+ ```
48
+
49
+ 完整恢复将解码后的事件送入新的阶段,并校验目标产物。调用方不得将阶段的部分输出视为成功恢复:错误可能出现在后续事件或 `finish()`。[格式协议](../session-format/README.zh.md)负责阶段调度与目录错误处理;[JSONL 持久化](../session-persistence-jsonl/README.zh.md)负责读取准备和不可变后继代的发布。
50
+
51
+ -----
52
+
53
+ <a id="v2-to-v3-specification"></a>
54
+ ## V2 到 V3 规范
55
+
56
+ 整条迁移边不是恒等转换。它保留源事件的相对顺序、时间戳和每个历史请求的含义,但插入的系统事件会改变事件数、稠密序列位置、本地引用和继承切点。PTC/预设转换及最终信封规范化不添加事件。只有下文列出的字段发生变化;保留承诺适用于已接纳的输入,而非任意未经审计的扩展。
57
+
58
+ <a id="header-and-presets"></a>
59
+ ### 头部与预设引用
60
+
61
+ 逻辑头部将 `version: 2` 改为 `version: 3`。它保留 `id`、`createdAt`、`isSeeded`、`delegationDepth`,以及已接纳的可选字段 `cwd`、`parentSession` 和 `origin`。在 `header.agentPreset` 和每条 `agent-preset/selected.data.agentPreset` 中,精确匹配的预设标识 `code` 变为 `ptc`,包括继承与本地选择。其他字符串和缺失的头部预设保持不变。选择载荷要求字符串预设标识,并拒绝未经审计的成员。
62
+
63
+ 此转换不检查已安装预设,也不改写其他位置的 `code`。已发布 V0/V1 数据仅在经过冻结的前代迁移边到达 V2 后接受此转换。原生 V3 自定义预设标识不被重命名,`settings.yaml` 不属于本包范围。
64
+
65
+ <a id="system-head"></a>
66
+ ### 系统头节点与消息身份
67
+
68
+ 首个 `step/start` 后立即追加空 `system/message`,即使该步骤在发出请求前中止。后续步骤不再创建头节点。没有步骤也没有 surface 的日志不会获得头节点或虚构请求。
69
+
70
+ 在每条 `request/header` 处,缺失的 `data.header.system` 表示空提示词;否则,其字符串与当前提示词进行精确比较。发生变化时,在该请求头之前立即插入系统消息,恰好替换当前受保护的头节点,并在 `sourceEventSeqs` 中引用它。提示词不变时不插入消息。空字符串和缺失字段会清空先前的提示词;仅含空白的字符串仍为非空文本。每个请求头都会移除 `data.header.system`,无论是否需要替换。
71
+
72
+ 合成消息携带开放步骤的 `turn` 和 `step`、锚点事件的 `time`、角色 `system`,以及来源 `{ kind: 'plugin', plugin: '@deepseek-ai/dsh-system-prompt' }`。空提示词使用 `content: []`;其他提示词使用包含精确字符串的单个文本块。首次追加没有溯源;每次替换的两个端点及唯一源引用都使用前一头节点的目标序号。空头节点保持受保护,但不产生模型消息。
73
+
74
+ 每个合成标识由 `v2-to-v3-system-` 加上 `JSON.stringify(['session-format-v2-to-v3', sourceHeader.id, anchor.seq, anchor.type])` 的十六进制 SHA-256 构成。首次创建的锚点是源 `step/start`,替换的锚点是提示词变化的 `request/header`。与已生成或源消息标识的冲突均被拒绝,不受遇到顺序影响;检查范围包括收件箱插入消息与标题请求消息中的标识。现有消息标识绝不改变。特别是,`TOOL_NOT_STARTED` 修复标识保留规范的历史 `interrupted-tool-result-<callId>-<integer>` 后缀;该后缀不是目标序列坐标。
75
+
76
+ <a id="sequence-references"></a>
77
+ ### 序列引用与继承
78
+
79
+ 源事件必须从零开始稠密排列。每个原始事件在其前面的插入完成后获得目标位置。[引用映射器](src/references.ts)仅修改以下同产物引用;每个被引用的源位置必须指向已建立映射的更早事件:
80
+
81
+ | 所有者 | 重映射字段 |
82
+ |---|---|
83
+ | Surface 信封 | `sourceEventSeqs[]`;规范重命名前的 `surfaceOp.start/end` |
84
+ | `command/done.data` | 存在时的 `sourceEventSeq` |
85
+ | `compaction/summary.data` 和 `compaction/prune.data` | `shadowedRange.start/end` 和 `shadowedSeqs[]` |
86
+ | `session/title.data` 和 `session/title-llm-request.data` | `messageSeqs[]` |
87
+
88
+ 不存在递归数值字段改写。投递的 `throughSeq` 和 `sessionFormatVersion`、会话引用的 `capturedThroughSeq` 和 `capturedFormatVersion`、工作流本地 `seq`、流块索引、轮次/步骤编号、收件箱索引、token/字节计数以及所有标识都保留源值。内嵌 assistant 流、模型回放状态、工具参数/结果、标题请求输入文本及 `data.system` 保留已记录的含义。压缩(compaction)载荷端点保持 `start/end` 名称;仅信封替换端点被重命名。
89
+
90
+ 对于有种子的 Session,最后一条带有 `data.inherited: true` 的 `session/end-seed` 标识源切点。其源序号等于继承事件数,不含该标记;其映射后的目标序号即目标切点。此前的合成事件属于继承部分,此后的属于本地部分。未标记继承的结束标记不建立切点。若提供 `sourceInheritedEventCount`,则必须一致;有种子但没有标记的日志,以及无种子却有继承标记的日志都会被拒绝。无种子阶段公开 `headerInheritedEventCount: 0`;有种子阶段保持未知,直到 `finish()` 推导精确切点。这也支持前一阶段改变事件数、无法在 EOF 前提供切点的 V0/V1 迁移链。
91
+
92
+ <a id="ptc-vocabulary"></a>
93
+ ### PTC 词汇
94
+
95
+ 精确的事件标签 `tool/code-dispatch-start` 和 `tool/code-dispatch` 变为 `tool/ptc-dispatch-start` 和 `tool/ptc-dispatch`。其载荷值保持不变。仅在以下三个位置的 `source.kind === 'plugin'` 时,精确匹配的插件归属 `tools-code-mode` 才变为 `tools-ptc`:
96
+
97
+ - `user/message.data.source.plugin`
98
+ - `agent/inbox/spliced.data.inserted[].source.plugin`
99
+ - `session/title-llm-request.data.messages[].source.plugin`
100
+
101
+ 相似插件名、其他来源种类、任意文本、嵌套 JSON 及包含 `:code:` 的历史标识保持不变。此转换不重命名 `run_code` 或其 `code` 参数。已使用任一 V3 保留 PTC 标签的 V2 源事件即使可忽略也会被拒绝;不透明源扩展不得通过迁移获得当前生命周期含义。
102
+
103
+ <a id="canonical-envelopes"></a>
104
+ ### 规范信封与工具错误
105
+
106
+ 结构插入和引用重映射完成后,规范化将原始与合成事件上的精确信封替换对象 `{ op: 'replace', start, end }` 转为 `{ op: 'replace', startSeq, endSeq }`。它仅从 `request/header.data.header` 中省略精确的 `tools: []` 和 `adapterDefaults: {}`。这个最终操作保留其输入事件数、坐标、时间戳、顺序与继承切点;既不重复映射,也不规范化 `config.stop: []` 等无关空值。
107
+
108
+ 四种 V3 surface 类型(`system/message`、`user/message`、`assistant/message`、`tool/result`)都要求 `surfaceOp`。仅 assistant 消息禁止 `sourceEventSeqs`;其他类型提供的列表必须非空、唯一,且仅引用更早的事件。已知仅日志事件不允许两个 surface 元数据字段。替换不允许别名或额外键。端点按当前 surface 顺序而非数值序号顺序标识闭区间;恢复会检查存活成员、端点顺序与完整溯源覆盖。
109
+
110
+ 源 surface 事件本就要求位置标记;迁移不虚构缺失的追加标记。带有 `data.error` 的 `tool/result` 要求其唯一工具结果块携带 `isError: true`。失败结果可以省略结构化错误身份。矛盾结果会被拒绝,绝不通过添加 `isError` 或删除诊断来修复。普通工具与 PTC 生命周期关系仍须在这些事件本地检查后验证。
111
+
112
+ <a id="delivery-guards"></a>
113
+ ### 投递保护
114
+
115
+ V2 `session-log-deepseek/delivery-accepted` 若携带 `data.sessionFormatVersion === 3`,就会被拒绝,而非提升为 V3 上传水位。其他代的标记保留其载荷,包括缺失代次和非目标的未来代次。V2 代标记必须具有有效且更早的 `throughSeq`;若它指向另一个 Session,则仅允许出现在具有 `parentSession` 的 Session 的继承前缀中。本地的外部会话标记或没有父会话元数据的外部会话标记会被拒绝。标记的信封序号正常变化;其捕获的接收坐标不变。
116
+
117
+ <a id="source-audit"></a>
118
+ ### 源审计与拒绝
119
+
120
+ 迁移分类[已发布 V2 事件清单](../session-format-v1-to-v2/src/dispositions.ts),包括仅日志的 `assistant/attempt`,以及 `feedback/message-put` 和 `feedback/message-delete`。[载荷校验器](src/payload.ts)应用精确的已接纳信封和载荷成员,以及已发布嵌套校验。未知事件(即使可忽略)以及被检查记录中未经审计的成员均被拒绝。消息来源分类覆盖下表的五个 Message 位置:未知来源种类会被拒绝,agent(智能体)中继归属则被接纳,但标识不会被解释为 Session 引用。
121
+
122
+ 内容审计仅接纳 `text`、`reasoning`、`image`、`file`、`tool-call` 和 `tool-result`。它校验归本格式所有的块字段,并在以下有限位置递归审计每层嵌套的 `tool-result.content`:
123
+
124
+ | 所有者 | 审计内容 |
125
+ |---|---|
126
+ | 五个 Message 位置 | `user/message.data.content`;`assistant/message.data.message.content`;`tool/result.data.message.content`;`agent/inbox/spliced.data.inserted[].content`;`session/title-llm-request.data.messages[].content` |
127
+ | 排队的团队消息 | `team/message/queued.data.message.content`;历史 Team 载荷保持 `version: 1` 并带有 `message.delivery` |
128
+ | 压缩输出 | `compaction/summary.data.summary` 和可选的 `compaction/summary.data.rawOutput` |
129
+ | PTC 前代输出 | `tool/code-dispatch.data.content` |
130
+ | 内嵌 assistant 流 | `assistant/message.data.stream[]` 和 `assistant/attempt.data.stream[]` 中的原始 `type: 'chunk'` 记录:`block-end` 的 `chunk.block` 和 `block-start` 的 `chunk.blockType`,包括尚无完整块的起始记录 |
131
+
132
+ 所有位置共用同一历史种类集合;未完成的起始记录不能引入未知种类。未知种类和归本格式所有的畸形块都会拒绝整次迁移;目录恢复报告 `SessionFormatUnsupportedMigrationError`。诊断标明源事件类型、源序号、包含索引的完整载荷路径和违反的规则。未知种类错误标明违规种类;已知块的畸形错误标明种类和字段错误。畸形内容容器或缺失块报告其位置,而不虚构种类。拒绝时,持久化保留源字节且不发布后继代。
133
+
134
+ 准入不改写内容。特别是,内嵌流虽然接受归本格式所有的块字段检查,其字节仍保持不变。工具参数、`replayState.response` 和 `replayState.blocks` 保持不透明;任意 JSON 内的同名字段不会触发此审计。文件附件元数据接受校验,但标识或字节计数不会被解释为 Session 引用。这不是通用 schema 审计或递归坐标推断,原生 V3 扩展准入与此分开。
135
+
136
+ 首个步骤前的 surface 事件、开放步骤外的提示词变化或生成标识冲突,会抛出 `SessionFormatUnsupportedMigrationError`,而非移动事件或虚构归属。源字段格式错误、缺失位置、无效引用、不一致切点、投递违规与矛盾工具结果,会在直接阶段或目标校验器中抛出格式错误。目录将迁移阶段和转换后目标校验失败报告为类型化的不支持迁移;物理解码失败仍按所选恢复策略归类为损坏。本迁移边不修复源或目标,不回退代次,也不改写文件。
137
+
138
+ -----
139
+
140
+ <a id="native-v3-admission"></a>
141
+ ## 原生 V3 准入
142
+
143
+ 已标记为 V3 的输入不运行 V2 到 V3 迁移。使用 `validation: 'transformed'` 的原生目录读取仅执行编解码器检查,跳过产物恢复;完整关系、开放步骤归属、受保护头节点操作与词汇检查需要 `restoreReleasedV3Artifact` 或目录的 `validation: 'current'`。以下规则区分这些恢复检查与编解码器准入;它们不是额外的历史转换:
144
+
145
+ - 原生 V3 接纳历史内系统消息追加、非头系统节点替换和非头系统节点压缩。系统消息要求有效载荷及匹配的开放步骤归属。首个 surface 系统头节点只能被恰好覆盖该头节点的系统消息替换;普通替换和压缩不能消耗它。迁移本身只产生初始头节点与头节点替换,不产生依赖路由的历史内更新。
146
+ - 原生 V3 拒绝任何 `request/header.data.header.system`,包括空值或格式错误值,并拒绝非规范替换拼写及两个空请求头可选字段。它保留空白内容、空停止列表和已接纳的嵌套 header/source/data 扩展。此扩展准入不会扩大 V2 源审计或精确的逻辑 Session 头字段范围。
147
+ - 必需的前代 PTC 标签即使已安装也会被拒绝。已退役或未知的可忽略事件(包括其逻辑元数据)保持不透明,且不能满足当前 PTC 关系。已安装的普通事件新增项作为仅日志信封接纳;未知必需类型由识别词汇的恢复阶段拒绝。物理编解码器仍执行已发布的分帧与溯源编码规则。
148
+ - V3 事件本地检查在编码前及解码后执行。原始行的已退役系统头字段、畸形系统载荷和必需前代 PTC 的拒绝先于可恢复抑制执行,包括损坏行之后。严格读取立即拒绝规范错误。可恢复的规范解码不产出首个无效事件及其后缀;后续 `turn/end` 建立提交事实并拒绝该后缀。只有已接纳的继承标记计数;有种子的已接纳前缀若没有标记则被拒绝。未分类事件元数据会延迟到识别词汇的恢复阶段,而不是作为规范损坏丢弃,因此不能隐藏未知必需类型。
149
+
150
+ -----
151
+
152
+ <a id="understand-the-implementation"></a>
153
+ ## 理解实现
154
+
155
+ <details>
156
+ <summary>实现细节 — 点击展开</summary>
157
+
158
+ [阶段](src/migration.ts)拥有每份产物独立的同步序列映射、消息身份集合和提示词/生命周期状态。紧凑事件段增量展开。[编解码器](src/codec.ts)复用冻结的 V2 分帧;[恢复器](src/validation.ts)先校验 V3 结构,再向冻结的普通关系校验提供私有 system/PTC/修复标识与端点视图。该视图为投递检查保留实际目标代次,且绝不对外返回:恢复返回原始 V3 产物与身份。冻结的 V0 到 V1 和 V1 到 V2 语义保持不变。本库不拥有可独立观察的注册或状态副本,因此不发布运行时不变量伴随入口。
159
+
160
+ [组合目录测试](tests/combined-migration.spec.ts)验证转换组合与原生重新打开;[迁移测试](tests/migration.spec.ts)和[规范测试](tests/canonical-envelopes.spec.ts)固定保留与拒绝规则。[持久化集成](../session-persistence-jsonl/tests/v2-ptc-migration.spec.ts)负责发布证据。[已发布格式决策](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md)负责将相邻组合测试与原生准入测试分开的依据。
161
+
162
+ </details>
163
+
164
+ -----
165
+
166
+ <a id="further-exploration"></a>
167
+ ## 深入探索
168
+
169
+ - [已发布 V1 到 V2](../session-format-v1-to-v2/README.zh.md) — 冻结的前代转换与源编解码器。
170
+ - [系统提示词 surface 决策](../../../.agents/notes/implemented/architecture/2026-09-02-system-prompt-as-surface-node.zh.md) — 提示词归属与头节点保护依据。
171
+ - [规范 V3 信封决策](../../../.agents/notes/implemented/architecture/2026-09-06-v3-canonical-session-envelopes.zh.md) — 严格准入与校验归属。
172
+
173
+ -----
174
+
175
+ <a id="model-experience"></a>
176
+ ## 模型体验
177
+
178
+ ### 历史日志恢复
179
+
180
+ #### 模型看到什么
181
+
182
+ 每个历史请求保留其提示词文本与普通消息内容。空系统头节点不产生模型消息。PTC 归属使用 `tools-ptc`;分发事件仍仅写日志。
183
+
184
+ #### Token 影响
185
+
186
+ 迁移边不添加模型可见文本;它将已记录的提示词从请求头移入消息历史。
187
+
188
+ #### KV Cache 影响
189
+
190
+ 迁移边保留历史请求含义与模型配置;它不保证提供方缓存命中,也不保证与原生 V3 录制字节相同。
191
+
192
+ ## 已知限制与后续工作
193
+
194
+ <a id="known-limitations-and-deferred-work"></a>
195
+
196
+ - **历史预设歧义** — 已发布 `code` 引用无法区分与旧内置标识同名的自定义预设;[精确重命名](#header-and-presets)不依赖宿主。
197
+ - **不迁移文件或设置** — 本包绝不修改已提交代或 `settings.yaml`。持久化负责发布最终后继代;已有 V3 代不重新运行其入边。V3 尚未发布;本包不为已写出的开发期 V3 文件提供兼容或修复。
198
+
199
+ <a id="dev-note"></a>
200
+ ### 开发备注
201
+
202
+ <details>
203
+ <summary>维护者工作上下文 — 点击展开</summary>
204
+
205
+ 无。
206
+
207
+ </details>