dsh-retrace 0.4.15 → 0.4.16
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/lib/prewrite-guard.js +37 -16
- package/package.json +1 -1
package/lib/prewrite-guard.js
CHANGED
|
@@ -44,14 +44,28 @@ import { editorError } from './host-core.js'
|
|
|
44
44
|
export const ROLLBACK_RATIO = 0.4
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
47
|
+
* 回档幅度判定(2026-09-01 重设计——不再用「占比」):
|
|
48
|
+
*
|
|
49
|
+
* 事故复盘:DSH 2.0.3 的 host Session 用「事件窗口」构造(官方 Session
|
|
50
|
+
* constructor(log, baseSeq) 注释「complete log or loaded event window」),
|
|
51
|
+
* `session.surface.nodes` 可能只是**窗口化 surface**(编辑最后一条消息时
|
|
52
|
+
* 只有 ~12 节点)。用占比做分母 → 12/12 = 100% → 编辑最新消息也被误拦
|
|
53
|
+
* (用户实测:长对话编辑最后一条报「遮蔽 100%」)。
|
|
54
|
+
*
|
|
55
|
+
* 新判定:**绝对遮蔽数**(shadowedSeqs.length,不依赖 surface 总数)——
|
|
56
|
+
* - ≤ ROLLBACK_MIN_SHADOWED 节点(≈ 20 轮):任何会话都允许编辑/撤回;
|
|
57
|
+
* - > 阈值:仅当**会话足够大**(事件数 > ROLLBACK_MIN_EVENTS)才拦
|
|
58
|
+
* (事故防御针对大会话的早期编辑,避免小会话误伤)。
|
|
59
|
+
* 分母信号:优先用 `session.events.length`(host 全量事件数,不窗口化)。
|
|
52
60
|
*/
|
|
53
61
|
export const ROLLBACK_MIN_SURFACE = 20
|
|
54
62
|
|
|
63
|
+
/** 绝对遮蔽阈值:遮蔽 ≤ 40 个节点(≈ 20 轮)永不在任何会话拦截。 */
|
|
64
|
+
export const ROLLBACK_MIN_SHADOWED = 40
|
|
65
|
+
|
|
66
|
+
/** 会话规模阈值:事件数 > 2000 才算「大会话」(短会话永不拦)。 */
|
|
67
|
+
export const ROLLBACK_MIN_EVENTS = 2000
|
|
68
|
+
|
|
55
69
|
/**
|
|
56
70
|
* 该 marker 是否来自 rollback(restore op)——rollback 本身就是「从快照点
|
|
57
71
|
* 回档」的官方机制,不应再被回档幅度守卫拦截(否则大范围回档永远不可用,
|
|
@@ -62,15 +76,22 @@ export function isRestoreMarker(envelope) {
|
|
|
62
76
|
return typeof id === 'string' && id.startsWith('retrace-restore-')
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* 回档幅度判定(返回 true = 应拦截)。
|
|
81
|
+
* 不依赖窗口化 surface 总数:遮蔽绝对数 > 阈值 且 会话足够大 才拦。
|
|
82
|
+
*/
|
|
66
83
|
export function rollbackShareOf(session, envelope) {
|
|
67
84
|
if (!session || !envelope) return 0
|
|
68
85
|
const shadowed = Array.isArray(envelope.sourceEventSeqs) ? envelope.sourceEventSeqs.length : 0
|
|
69
86
|
if (shadowed <= 0) return 0
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
if (shadowed <= ROLLBACK_MIN_SHADOWED) return 0 // 遮蔽 ≤ 40 节点:允许
|
|
88
|
+
// 会话规模:优先 events 全量,fallback surface(窗口化也够判断「大会话」)
|
|
89
|
+
const eventCount = Array.isArray(session.events) ? session.events.length : 0
|
|
90
|
+
const surfaceTotal = Array.isArray(session.surface?.nodes) ? session.surface.nodes.length : 0
|
|
91
|
+
const scale = Math.max(eventCount, surfaceTotal)
|
|
92
|
+
if (scale <= ROLLBACK_MIN_EVENTS) return 0 // 小会话豁免
|
|
93
|
+
// 返回占比仅作日志参考(拦截判定已由绝对阈值完成)
|
|
94
|
+
return shadowed / Math.max(scale, 1)
|
|
74
95
|
}
|
|
75
96
|
|
|
76
97
|
/** R2 —— T1 折叠自检:与 dsh-token-meter/_foldEvent 及 checks.js T1 同语义。 */
|
|
@@ -113,24 +134,24 @@ export function createMarkerGuard({ log = () => {}, prewriterFactory, enabled =
|
|
|
113
134
|
*/
|
|
114
135
|
async validateMarkerAppend(session, envelope) {
|
|
115
136
|
if (typeof enabled === 'function' && enabled(session?.id) === false) return { t1Ok: true }
|
|
116
|
-
// 快照点守卫(2026-08-31 c2d05ce9
|
|
137
|
+
// 快照点守卫(2026-08-31 c2d05ce9 事故闭环):回档请求(遮蔽过大)
|
|
117
138
|
// 拒绝落盘——生产基线不支持原地大幅改写,引导从快照点创建官方分支。
|
|
118
139
|
// 在契约校验之前独立检查(业务规则,与合法性正交);host 层强制,UI 绕过也拦。
|
|
119
|
-
//
|
|
140
|
+
// 豁免:restore(rollback 回档本身合法);判定用绝对遮蔽数(不依赖窗口化 surface)。
|
|
120
141
|
if (
|
|
121
142
|
envelope?.surfaceOp?.op === 'replace' &&
|
|
122
143
|
Array.isArray(envelope.sourceEventSeqs) &&
|
|
123
144
|
!isRestoreMarker(envelope)
|
|
124
145
|
) {
|
|
125
146
|
const share = rollbackShareOf(session, envelope)
|
|
126
|
-
if (share >
|
|
127
|
-
const
|
|
147
|
+
if (share > 0) {
|
|
148
|
+
const shadowed = envelope.sourceEventSeqs.length
|
|
128
149
|
log(
|
|
129
|
-
`retrace: rollback guard — replace shadows ${
|
|
150
|
+
`retrace: rollback guard — replace shadows ${shadowed} surface nodes in a large session; refusing in-place rewrite; guide user to fork a branch from the snapshot point`,
|
|
130
151
|
)
|
|
131
152
|
throw editorError(
|
|
132
153
|
'rollback-guide',
|
|
133
|
-
`此操作将回档到较早的快照点(遮蔽 ${
|
|
154
|
+
`此操作将回档到较早的快照点(遮蔽 ${shadowed} 个对话节点)。生产基线不支持原地大幅改写;请从快照点创建会话分支,在新分支中继续——原会话完整保留。`,
|
|
134
155
|
)
|
|
135
156
|
}
|
|
136
157
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-retrace",
|
|
3
3
|
"description": "Retrace · 回溯 — Recall, edit-and-resend, regenerate, and conversation/artifact versioning (timeline, rollback, fork map) for DeepSeek Harness — Web and Desktop",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.16",
|
|
5
5
|
"packageManager": "pnpm@11.7.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|