@sparkelf/dsh-patch-session-envelope-ignorable 0.2.0-rc.44

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 patches/npm/session-envelope-ignorable/README.md
5
+ README.md: 6eb808d895e9acdd2b2cd06a21add3518412ad7a
6
+ README.zh.md: abf5983079e08aff14e0c636b6cbc547af3f5b4a
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @sparkelf/dsh-patch-session-envelope-ignorable
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ This data-only package lets a log-only event declare the session envelope's `ignorable` marker at `Session.append`.
6
+
7
+ The envelope has carried `ignorable` since the released session format, and the persistence read path enforces it: an event whose type the reader does not know is refused unless the event is marked ignorable, because skipping an unrecognized required event could reconstruct a wrong session. The marker had no writer. `Session.append` builds the envelope from `type`, `seq`, `time`, `data`, and the surface metadata, so an out-of-repo plugin appending its own event type could only produce records that every reader without that plugin refuses — including the reader that wrote them, once the plugin is unmounted.
8
+
9
+ The patch adds an `EnvelopeIntent` to `packages/core/session/src/types.ts` and widens `append`'s rest parameter to accept it for non-surface events. The event construction copies `ignorable: true` onto the envelope only when the caller passes exactly `true`, matching the field's own contract: absence means required, and an explicit falsy value would be indistinguishable from a producer that meant the opposite.
10
+
11
+ The deployment carries three sessions written by `@sparkelf/dsh-image-hoist` before this patch: `session-08bf0cc7-b831-4834-a30f-9153854503fe`, `session-160644ce-0546-4a75-8482-3848a0f2ebc7`, and `session-7dad49d6-1745-4158-b578-8fddf54cb45f`. Their `image/hoist` records are repaired in place by moving the marker to the envelope. This package is the writer-side change, moved from a mirror stash into a reviewed patch so a rebuild cannot drop it.
package/README.zh.md ADDED
@@ -0,0 +1,11 @@
1
+ # @sparkelf/dsh-patch-session-envelope-ignorable
2
+
3
+ [English](README.md) | 中文
4
+
5
+ 这个 data-only 包让「只写日志」的事件可以在 `Session.append` 时声明会话信封的 `ignorable` 标记。
6
+
7
+ 信封从已发布的会话格式起就带 `ignorable`,持久化读取路径也强制它:读取器不认识的类型会被拒绝,除非该事件标了 ignorable —— 因为静默跳过一条不可忽略的事件会重建出错误的会话。**但没有任何写入者能设置它。** `Session.append` 用 `type`、`seq`、`time`、`data` 和 surface 元数据构造信封,所以外部插件追加自己的事件类型时,只能产出「所有没挂载该插件的读取器都拒绝」的记录 —— 包括卸载插件后它自己。
8
+
9
+ 补丁在 `packages/core/session/src/types.ts` 增加 `EnvelopeIntent`,并把 `append` 的剩余参数放宽为非 surface 事件可接受它。事件构造只在调用方传入恰好 `true` 时把 `ignorable: true` 复制到信封上,与该字段自身的契约一致:缺省即必需,显式的假值与「本意相反的生产者」无法区分。
10
+
11
+ 部署里有三个由 `@sparkelf/dsh-image-hoist` 在本补丁之前写入的会话:`session-08bf0cc7-b831-4834-a30f-9153854503fe`、`session-160644ce-0546-4a75-8482-3848a0f2ebc7`、`session-7dad49d6-1745-4158-b578-8fddf54cb45f`。它们的 `image/hoist` 记录已就地修复,把标记移到信封上。本包是写入侧改动:从镜像暂存区搬进受审查的补丁,重建不会再丢掉它。
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "description": "Data-only exact official-source patch letting a log-only event declare the session envelope's ignorable marker at append",
3
+ "dshPatch": {
4
+ "formatVersion": 1,
5
+ "variants": [
6
+ {
7
+ "dsh": ">=0.2.0-rc.2",
8
+ "file": "./patches/session-envelope-ignorable.patch",
9
+ "id": "session-envelope-ignorable-at-append",
10
+ "target": {
11
+ "baseRevision": "639ed015397290b3745d163aafe02ffee4aa3f84",
12
+ "kind": "dsh-source",
13
+ "paths": [
14
+ "packages/core/session/src/"
15
+ ]
16
+ }
17
+ }
18
+ ]
19
+ },
20
+ "files": [
21
+ "patches/*.patch"
22
+ ],
23
+ "license": "MIT",
24
+ "name": "@sparkelf/dsh-patch-session-envelope-ignorable",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "repository": {
29
+ "directory": "patches/npm/session-envelope-ignorable",
30
+ "type": "git",
31
+ "url": "git+https://github.com/SparkElf/deepseek-harness-plus.git"
32
+ },
33
+ "type": "module",
34
+ "version": "0.2.0-rc.44"
35
+ }
@@ -0,0 +1,59 @@
1
+ --- a/packages/core/session/src/types.ts
2
+ +++ b/packages/core/session/src/types.ts
3
+ @@ -478,6 +478,18 @@
4
+ })
5
+
6
+ /**
7
+ + * Envelope markers a log-only event may declare at {@link Session.append}.
8
+ + *
9
+ + * `ignorable` lets a reader that does not know the event type skip it instead of refusing the
10
+ + * whole log. Only a producer whose record cannot affect reconstruction may set it, so it is
11
+ + * opt-in per append rather than a property of the event type.
12
+ + */
13
+ +export type EnvelopeIntent = {
14
+ + /** Marks an event a reader may skip when it does not recognize the type. */
15
+ + ignorable?: true
16
+ +}
17
+ +
18
+ +/**
19
+ * One immutable entry in the session log.
20
+ *
21
+ * A proper discriminated union over `type` (not independent `type`/`data`
22
+ --- a/packages/core/session/src/index.ts
23
+ +++ b/packages/core/session/src/index.ts
24
+ @@ -15,7 +15,8 @@
25
+ import type { Message } from '@deepseek-ai/dsh-llm'
26
+ import { SESSION_FORMAT_VERSION, SessionLogOffset, SessionSeq } from './types.ts'
27
+ import type { TypertLookup } from '@deepseek-ai/dsh-typert-protocol'
28
+ -import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SessionId, SessionSeedEventState, SurfaceIntent, SurfaceEventType } from './types.ts'
29
+ +import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SessionId, SessionSeedEventState, EnvelopeIntent,
30
+ + SurfaceIntent, SurfaceEventType } from './types.ts'
31
+ import { SurfaceManager, validateSessionEventData, validateSurfaceMetadata } from './surface.ts'
32
+ import type { SessionSurface, SessionMessageProjection } from './surface.ts'
33
+ import { foldRequestHeader } from './request-header.ts'
34
+ @@ -722,9 +723,12 @@
35
+ append<T extends SessionEventType>(
36
+ type: T,
37
+ data: SessionEventMap[T],
38
+ - ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent<T>] : []
39
+ + ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent<T>] : [opts?: EnvelopeIntent]
40
+ ): SessionEvent<T> {
41
+ - const surfaceOpts: SurfaceIntent | undefined = opts[0]
42
+ + // A surface event's single option object is a `SurfaceIntent`; a log-only event's is an
43
+ + // `EnvelopeIntent`. The two never share a field, so one object serves both.
44
+ + const intent: SurfaceIntent & EnvelopeIntent = (opts[0] ?? {}) as SurfaceIntent & EnvelopeIntent
45
+ + const surfaceOpts: SurfaceIntent | undefined = opts[0] as SurfaceIntent | undefined
46
+ const surfaceMetadata = {
47
+ ...surfaceOpts?.sourceEventSeqs === undefined ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs },
48
+ ...surfaceOpts?.surfaceOp === undefined ? {} : { surfaceOp: surfaceOpts.surfaceOp },
49
+ @@ -747,6 +751,10 @@
50
+ time: Date.now(),
51
+ data: dataSnapshot,
52
+ ...(surfaceMetadataSnapshot as { surfaceOp?: unknown; sourceEventSeqs?: unknown }),
53
+ + // A log-only producer declares that a reader without its event type may skip the record.
54
+ + // Only `true` is admitted: the field's absence means required, and an explicit falsy value
55
+ + // would be indistinguishable from a producer that meant the opposite.
56
+ + ...(intent.ignorable === true ? { ignorable: true } : {}),
57
+ } as unknown as SessionEvent<T>)
58
+ validateSessionEventData(event, `session event "${type}" at seq ${event.seq}`)
59
+ this.surfaceManager.validateNext(event as SessionEvent)