@sema-agent/server 7.143.0 → 7.144.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/MIGRATION.md +166 -0
- package/USAGE.md +24 -14
- package/dist/approval-card.d.ts +31 -14
- package/dist/approval-card.js +8 -8
- package/dist/boot/execution-env.js +1 -1
- package/dist/boot/runner-deps.d.ts +10 -5
- package/dist/boot/runner-deps.js +5 -4
- package/dist/boot/shutdown.d.ts +1 -1
- package/dist/boot/shutdown.js +4 -2
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-07-capability-layer.js +1 -1
- package/dist/boot/stage-10-http-server.js +2 -7
- package/dist/capabilities/scenarios.d.ts +14 -18
- package/dist/capabilities/scenarios.js +1 -2
- package/dist/config-d-migration.d.ts +2 -0
- package/dist/delegated-session-owner.d.ts +33 -151
- package/dist/delegated-session-owner.js +1 -83
- package/dist/entry-mode-clamp-notice.d.ts +1 -1
- package/dist/execution-placement.d.ts +7 -4
- package/dist/hooks/classic-stations.d.ts +3 -1
- package/dist/hooks/classic-stations.js +2 -0
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/refusal-body.d.ts +7 -3
- package/dist/http/refusal-body.js +1 -0
- package/dist/http/resume-legs.js +11 -4
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lane-home-probe.d.ts +15 -0
- package/dist/lane-home-probe.js +4 -0
- package/dist/observability/corrupt-read-seat.d.ts +5 -9
- package/dist/observability/corrupt-read-seat.js +1 -2
- package/dist/observability/fail-open.d.ts +12 -8
- package/dist/observability/fail-open.js +12 -8
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/observability/run-terminal.js +2 -2
- package/dist/parked-revive-surface.d.ts +6 -7
- package/dist/peer-inbound-face.d.ts +29 -34
- package/dist/peer-inbound-face.js +28 -63
- package/dist/plugins/caching-session-store.d.ts +0 -3
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +41 -34
- package/dist/plugins/checkpoint-store-sql.js +99 -38
- package/dist/plugins/fork-routing-session-store.d.ts +8 -1
- package/dist/plugins/fork-routing-session-store.js +6 -0
- package/dist/plugins/local-checkpoint-store.d.ts +6 -8
- package/dist/plugins/local-checkpoint-store.js +3 -2
- package/dist/plugins/local-session-store.d.ts +64 -29
- package/dist/plugins/local-session-store.js +126 -56
- package/dist/plugins/local-session-window.d.ts +4 -2
- package/dist/plugins/one-time-migrations.d.ts +12 -12
- package/dist/plugins/one-time-migrations.js +12 -12
- package/dist/plugins/pg-session-storage.d.ts +1 -9
- package/dist/plugins/pg-session-storage.js +2 -19
- package/dist/plugins/remote-env-host.d.ts +8 -4
- package/dist/plugins/remote-env-host.js +7 -9
- package/dist/plugins/remote-shell.js +12 -2
- package/dist/plugins/schema-consistency.d.ts +5 -1
- package/dist/plugins/session-fork.d.ts +1 -1
- package/dist/plugins/session-ownership.d.ts +9 -0
- package/dist/plugins/session-ownership.js +6 -0
- package/dist/plugins/session-store.d.ts +13 -16
- package/dist/plugins/session-store.js +9 -10
- package/dist/plugins/sql-json-column.d.ts +24 -2
- package/dist/plugins/sql-json-column.js +38 -3
- package/dist/plugins/store-backend.js +3 -2
- package/dist/plugins/tidb-session-store.d.ts +2 -14
- package/dist/plugins/tidb-session-store.js +2 -20
- package/dist/run-local.js +2 -1
- package/dist/runs.js +4 -0
- package/dist/security.d.ts +0 -4
- package/dist/session-error-wire.d.ts +24 -25
- package/dist/session-error-wire.js +4 -5
- package/dist/session-incarnation.d.ts +2 -2
- package/dist/session-notify-door.d.ts +2 -2
- package/dist/session-notify-door.js +5 -1
- package/dist/tool-approval.d.ts +3 -1
- package/dist/tool-approval.js +47 -18
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +1 -1
- package/dist/trace/ledger-sink.js +12 -4
- package/dist/trace/model-segment.d.ts +25 -6
- package/dist/trace/model-segment.js +47 -6
- package/dist/trace/project.d.ts +8 -2
- package/dist/trace/project.js +6 -4
- package/dist/trace/redact.d.ts +11 -0
- package/dist/trace/redact.js +19 -3
- package/dist/trace/self-minted-wire.d.ts +88 -9
- package/dist/trace/self-minted-wire.js +25 -3
- package/package.json +2 -2
- package/wire-changes/server@7.144.0.json +291 -0
- package/dist/session-records-skipped-notice.d.ts +0 -21
- package/dist/session-records-skipped-notice.js +0 -27
|
@@ -159,7 +159,7 @@ export declare function fleetViewOf(req: IncomingMessage, w: IdentityWiring, fac
|
|
|
159
159
|
* 有身份边界的部署上:
|
|
160
160
|
* · **无主的行**经无主臂的唯一判据 `ownerlessRowOpen`(`security.ts`):普通会话照旧对任何调用方开放;委派子代的 placed 行只对 fleet 调用方
|
|
161
161
|
* ({@link sessionCallerOf})开放 —— 任何具名主体、没有 service 凭据的无身份调用方都与别人的行同体(调用点答 404)([ref])。
|
|
162
|
-
*
|
|
162
|
+
* 代价如实:升级前写下、属主还没定下的存量子代行连它将来的属主也暂时读不到(SQL 两店由一次性迁移 M23 在窗内每次起服回填;本机文件店没有回填臂;7.144.0 起没有任何店在停驻时定属主 —— 属主只由建行那一笔记下引擎交来的 `placement.owner`);
|
|
163
163
|
* · 有主的行就是 run 面那一条谓词({@link runOwnerReadable}),一字不变。
|
|
164
164
|
* run 面(poll / events / cancel …)不读本谓词 —— 那是 run 资源的门,另一只。
|
|
165
165
|
*/
|
|
@@ -19,15 +19,19 @@ export type RefusalBody = {
|
|
|
19
19
|
/** 拒体:`{ error, errorCode, ...facts }`。 */
|
|
20
20
|
export declare function refusalBody(r: Refusal): RefusalBody;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* `detail.code` ⇒ `blockedBy`(挡住它的准入码)· `detail.field` ⇒ `field`(哪一侧 / 哪一格)· `detail.reason` ⇒ `reason`(同码多臂时哪一臂)
|
|
22
|
+
* 引擎拒一次续跑时的**机读事实位** → 拒体的同名事实键(唯一读法;续跑家族的每一只拒答都读它):
|
|
23
|
+
* `detail.code` ⇒ `blockedBy`(挡住它的准入码)· `detail.field` ⇒ `field`(哪一侧 / 哪一格)· `detail.reason` ⇒ `reason`(同码多臂时哪一臂)·
|
|
24
|
+
* `detail.thrownName` ⇒ `thrownName`(引擎 7.62.0 起,只在 `reason: requirements_damaged` 的拒上:判官读这一行时被抛出的东西的名字,有界、不带 message ——
|
|
25
|
+
* 在场 = 引擎缺陷〔判官被一个读时会抛的成员绊倒〕,缺席 = 行的内容与它自述的对不上〔数据损坏〕,运维凭这一位分诊)。
|
|
24
26
|
* 一员在场 ⇔ 它是非空串;其余(缺席、非串、空串)一律不铸键 —— 引擎没说就是没说,本层不编值,也不把一个非串原样推上 wire。
|
|
25
27
|
* 载体有两种,读法同一只:同步腿的 `CheckpointError.detail`(`http/resume-legs.ts` `checkpointRefusalAnswer`),与后台停驻子代赎回回执的
|
|
26
|
-
* `details.detail`(`parked-decide.ts` 的 422 `parked_resume.startup_failed`;引擎 7.54.0
|
|
28
|
+
* `details.detail`(`parked-decide.ts` 的 422 `parked_resume.startup_failed`;引擎 7.54.0 起它把认领前那只失败的 `code` / `field` / `reason` 交到回执上 ——
|
|
29
|
+
* 回执只带这三位,`thrownName` 今天不在回执里,所以这条腿的体上它恒缺席;回执哪天多带,同一只读法自然过境)。
|
|
27
30
|
*/
|
|
28
31
|
export declare function resumeRefusalFacts(detail: unknown): {
|
|
29
32
|
blockedBy?: string;
|
|
30
33
|
field?: string;
|
|
31
34
|
reason?: string;
|
|
35
|
+
thrownName?: string;
|
|
32
36
|
};
|
|
33
37
|
//# sourceMappingURL=refusal-body.d.ts.map
|
|
@@ -10,6 +10,7 @@ export function resumeRefusalFacts(detail) {
|
|
|
10
10
|
...(word(d.code) ? { blockedBy: d.code } : {}),
|
|
11
11
|
...(word(d.field) ? { field: d.field } : {}),
|
|
12
12
|
...(word(d.reason) ? { reason: d.reason } : {}),
|
|
13
|
+
...(word(d.thrownName) ? { thrownName: d.thrownName } : {}),
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
//# sourceMappingURL=refusal-body.js.map
|
package/dist/http/resume-legs.js
CHANGED
|
@@ -32,7 +32,7 @@ import { redactSecrets } from "../trace/redact.js";
|
|
|
32
32
|
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
33
33
|
import { createForwardAppendFailedNote, createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
|
|
34
34
|
import { registerEngineNoticeLeg } from "../trace/engine-notice-wire.js";
|
|
35
|
-
import { reasoningDeltaBytes, reasoningSegmentEventId } from "../trace/model-segment.js";
|
|
35
|
+
import { blockText, reasoningDeltaBytes, reasoningSegmentEventId } from "../trace/model-segment.js";
|
|
36
36
|
import { errorText } from "../observability/err-text.js";
|
|
37
37
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
38
38
|
import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
@@ -912,6 +912,7 @@ export function createResumeLegs(ctx) {
|
|
|
912
912
|
const rs = deps.runStore;
|
|
913
913
|
const startSeq = rs && taskId ? await rs.maxSeq(taskId) : 0;
|
|
914
914
|
let text = "";
|
|
915
|
+
let block = "";
|
|
915
916
|
let reasoning = "";
|
|
916
917
|
let reasoningEventId;
|
|
917
918
|
const persistThinking = deps.config.traceThinking;
|
|
@@ -945,9 +946,11 @@ export function createResumeLegs(ctx) {
|
|
|
945
946
|
reasoning = "";
|
|
946
947
|
reasoningEventId = undefined;
|
|
947
948
|
}
|
|
948
|
-
|
|
949
|
-
|
|
949
|
+
const segment = text + blockText(block);
|
|
950
|
+
if (segment) {
|
|
951
|
+
await append("text", modelTextEventData({ text: segment, eventId: anchor.firstTextEventId }));
|
|
950
952
|
text = "";
|
|
953
|
+
block = "";
|
|
951
954
|
}
|
|
952
955
|
};
|
|
953
956
|
const driveResume = async () => {
|
|
@@ -1037,9 +1040,13 @@ export function createResumeLegs(ctx) {
|
|
|
1037
1040
|
await appendPromptManifest(append, deps.promptManifests, taskId);
|
|
1038
1041
|
switch (ev.type) {
|
|
1039
1042
|
case "text_delta":
|
|
1040
|
-
|
|
1043
|
+
block += ev.delta;
|
|
1041
1044
|
anchor.onText(ev.eventId);
|
|
1042
1045
|
break;
|
|
1046
|
+
case "text_end":
|
|
1047
|
+
text += blockText(block, ev);
|
|
1048
|
+
block = "";
|
|
1049
|
+
break;
|
|
1043
1050
|
case "reasoning_delta": {
|
|
1044
1051
|
const rb = reasoningDeltaBytes(ev);
|
|
1045
1052
|
if (persistThinking && rb !== undefined) {
|
|
@@ -412,6 +412,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
412
412
|
...durableRowIdentity("assistant-inbox", s.checkpointId, s.token),
|
|
413
413
|
scope: s.scope,
|
|
414
414
|
createdAt: s.createdAt,
|
|
415
|
+
rowVerdict: s.rowVerdict,
|
|
415
416
|
...(s.gateKind !== undefined ? { gateKind: s.gateKind } : {}),
|
|
416
417
|
...(s.severity !== undefined ? { severity: s.severity } : {}),
|
|
417
418
|
...(s.spentMicroUsd !== undefined ? { spentMicroUsd: s.spentMicroUsd } : {}),
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { createBrain } from "./brain.js";
|
|
|
4
4
|
export { createSessionStore } from "./plugins/session-store.js";
|
|
5
5
|
export { createStoreBackend, type StoreBackend, type SessionCaptureRecordSource } from "./plugins/store-backend.js";
|
|
6
6
|
export { RetiredSchemaPresentError } from "./plugins/schema-consistency.js";
|
|
7
|
+
export { LocalDataRootSchemaMismatchError, type LocalSidecarMismatch } from "./plugins/local-session-store.js";
|
|
7
8
|
export { CachingSessionStore, type CachingOptions } from "./plugins/caching-session-store.js";
|
|
8
9
|
export type { RunRecord, RunEvent } from "./plugins/store-contracts.js";
|
|
9
10
|
export { runInBackground } from "./runs.js";
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { createBrain } from "./brain.js";
|
|
|
4
4
|
export { createSessionStore } from "./plugins/session-store.js";
|
|
5
5
|
export { createStoreBackend } from "./plugins/store-backend.js";
|
|
6
6
|
export { RetiredSchemaPresentError } from "./plugins/schema-consistency.js";
|
|
7
|
+
export { LocalDataRootSchemaMismatchError } from "./plugins/local-session-store.js";
|
|
7
8
|
export { CachingSessionStore } from "./plugins/caching-session-store.js";
|
|
8
9
|
export { runInBackground } from "./runs.js";
|
|
9
10
|
export { createHardenedVmRunner, runInHardenedVm } from "./orchestration/hardened-vm-runner.js";
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
* · **有主张 ⇒ 证**:座 = 主张原样(下单门与引擎 prepare 在环境开起来之前就要基);开环境那一拍读一次(与命令同一条 shell、同一份 env:
|
|
16
16
|
* `printf %s "$HOME"`;host 直接读它自己组合给子进程的那份 env),两者不一致 ⇒ 这只执行环境不开(拒句点名两值与改法),环境答了的判定记在环境上
|
|
17
17
|
* (同一镜像 / 同一目标机再问也是同一个答案,不重试成风暴);读不出同样不开(证不了主张 = 不拿一个没证过的目录去守),但不记 —— 与任何一次建连失败同,下一次重问。
|
|
18
|
+
* 「不开」落在读数到手的那一刻:读数在铸环境时就到手的车道(host:读数是适配器自己组合给子进程的那份 env)⇒ 环境**不铸** —— 构造抛带码的拒
|
|
19
|
+
* ({@link laneHomeRefusal},码 `env.home_unconfirmed`),工厂原样抛出,引擎在准备期再抛、不建环境,run 的失败终局原样承运码与句:没有命令、没有读边界判,
|
|
20
|
+
* 任何形状的命令都是同一首拒;读数要环境起来才有的车道(远端五条)⇒ 开环境那一拍拒,环境的门回同一句。
|
|
18
21
|
* · **没主张 ⇒ 实测**:同一拍问同一句;答出绝对路径 ⇒ 座 = 它,之后不再问;
|
|
19
22
|
* · **实测也缺席**(问不出 / 答的不是绝对路径,含空串)⇒ 座缺席(引擎失败关闭,不猜、不补 `/`),环境照开(没主张就没有主张可拒),一行 warn(点名读到了什么与出路)。
|
|
20
23
|
* 读不了家目录的车道(device:设备协议没有读数)不持座 —— 声明就是座,起服披露「来自声明、未实测」(`execution-lane-caps.ts` `buildLaneHomeBootNote`)。
|
|
@@ -68,6 +71,18 @@ export type LanePathFlavor = "posix" | "win32";
|
|
|
68
71
|
* 次序:读不出 → 不是绝对路径 → 一致 → 不一致(「绝对」先于「一致」:主张自己是相对串时,一个同样相对的读数也不放行)。
|
|
69
72
|
*/
|
|
70
73
|
export declare function judgeLaneHome(lane: string, claim: LaneHomeClaim, probe: LaneHomeProbe, paths?: LanePathFlavor): LaneHomeVerdict;
|
|
74
|
+
/**
|
|
75
|
+
* 本仓自铸的**执行环境拒码**闭集(`env.*` 族;今天一员)—— 一只执行环境在交给引擎之前就被拒时,工厂抛出的错带的 `code`。引擎在准备期原样再抛、不建环境,
|
|
76
|
+
* run 的 `failed` 终局原样承运码与句;同步提交腿按零工作拒落档(`runs.ts` 的 `EXECUTION_ENV_REFUSAL_HTTP_STATUS`,按本闭集键控:加一员而档没跟 ⇒ tsc 红)。
|
|
77
|
+
* · `env.home_unconfirmed` —— 家目录主张证不了({@link judgeLaneHome} 的三形拒句:读不出 / 不是绝对路径 / 与实测不一致)。三形一个码:出路都在部署
|
|
78
|
+
* (声明、环境里的 `HOME`,或会话 `settings.env` 里的 `HOME`),消费端不按形分岔;是哪一形、怎么改,句子里说。
|
|
79
|
+
*/
|
|
80
|
+
export declare const EXECUTION_ENV_REFUSAL_CODES: readonly ["env.home_unconfirmed"];
|
|
81
|
+
export type ExecutionEnvRefusalCode = (typeof EXECUTION_ENV_REFUSAL_CODES)[number];
|
|
82
|
+
/** 家目录拒的带码错误:句 = 判官的拒句原文,码 = `env.home_unconfirmed`。读数在铸环境时就到手的车道(host)构造时抛它,工厂原样抛出。 */
|
|
83
|
+
export declare function laneHomeRefusal(verdict: NonNullable<LaneHomeVerdict>): Error & {
|
|
84
|
+
readonly code: Extract<ExecutionEnvRefusalCode, "env.home_unconfirmed">;
|
|
85
|
+
};
|
|
71
86
|
/** 起服与每只环境「家目录答不出」那一行 warn 的事件名 —— 一只 code,起服(车道读不了)与环境(实测缺席)共用。 */
|
|
72
87
|
export declare const LANE_HOME_UNDECLARED_EVENT = "execution_lane_home_undeclared";
|
|
73
88
|
/**
|
package/dist/lane-home-probe.js
CHANGED
|
@@ -61,6 +61,10 @@ export function judgeLaneHome(lane, claim, probe, paths = "posix") {
|
|
|
61
61
|
answered: true,
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
export const EXECUTION_ENV_REFUSAL_CODES = ["env.home_unconfirmed"];
|
|
65
|
+
export function laneHomeRefusal(verdict) {
|
|
66
|
+
return Object.assign(new Error(verdict.refusal), { code: "env.home_unconfirmed" });
|
|
67
|
+
}
|
|
64
68
|
export const LANE_HOME_UNDECLARED_EVENT = "execution_lane_home_undeclared";
|
|
65
69
|
const HOME_ABSENT_COST = "the engine cannot place its home-anchored read-deny rows, so every contents-disclosing recursive read (grep -r, rg, git grep, tar c, …) asks a person on the full shell — " +
|
|
66
70
|
"no allow rule, mode or bypass releases that question — and is refused on the read-only face, so unattended tasks cannot search code; \"~/\" permission rules are refused at submission.";
|
|
@@ -9,13 +9,8 @@ import type { Logger } from "./logger.js";
|
|
|
9
9
|
* @param event warn 事件名。**留在调用点**:它是那只店的身份,接线锚(test/roster-corrupt-read.test.ts)
|
|
10
10
|
* 正是靠「构造实参里能读到这个名字」来证明座不是个空回调。
|
|
11
11
|
* @param note 这张脸的后果句(可选)。缺席 ⇒ 不写这个键。
|
|
12
|
-
* @param leg 与披露**同拍**的一条附加腿(可选;[ref] 加):座拿到一次披露时先交给它、再写日志。唯一的用户是
|
|
13
|
-
* `LocalSessionStore` 那只 `FileSessionRepo` 的座 —— 会话打开作用域的计数腿(`noteReplayInSessionOpenScope`:
|
|
14
|
-
* 作用域在场时把 `replay` 计数记到那次打开上,由打开方铸 `session.records_skipped`)。腿**必须不抛**(那一只是纯内存
|
|
15
|
-
* 赋值);先腿后日志,是因为日志座可能坏(core 的 guard 会吞掉它的抛),而一次日志故障不许吃掉这一记。
|
|
16
|
-
* 座本身不变:载荷投影、事件名、后果句仍由本属主铸,腿只多拿一份同一个 `info`。
|
|
17
12
|
*/
|
|
18
|
-
export declare function createCorruptReadSeat(warn: Logger["warn"], event: string, note?: string
|
|
13
|
+
export declare function createCorruptReadSeat(warn: Logger["warn"], event: string, note?: string): (info: FileStorageCorruptReadInfo) => void;
|
|
19
14
|
/**
|
|
20
15
|
* 铸一只 **F 类**腐读座([ref]):同一份 core 披露载荷,按 F 类座纪律处置 —— 每命中 `recordFailOpen(tag, 明细)`
|
|
21
16
|
* (计数逐次 + 探针行逐次 + warn 每进程每 tag 一次;三件套的节流粒度见 `fail-open.ts` 模块头)。
|
|
@@ -25,7 +20,8 @@ export declare function createCorruptReadSeat(warn: Logger["warn"], event: strin
|
|
|
25
20
|
* · `record` —— 一条被跳过的记录:**一次命中**,明细进探针行(会话 / 行号 / 坏体形 / 原因);
|
|
26
21
|
* · `file` —— 整个文件 / 目录读不出:**一次命中**(同一 tag,明细里 `kind=file`);
|
|
27
22
|
* · `replay` —— 同一批 `record` 的**汇总**(跳过 ≥1 条的每次读恰一发):**不计、不 warn** —— 计它就是把一条坏行记两次
|
|
28
|
-
* ([ref] 的教训)
|
|
23
|
+
* ([ref] 的教训)。汇总交给 `leg` 腿(唯一的用户 = local 会话店的一次性迁移 M33 整档读作用域);用户面的丢失账在 core 交出的存储上
|
|
24
|
+
* (`getReplayLoss` → 引擎的 `session.lineage_rerooted`,core 7.62.0),不经这只座;运维面逐条明细都在探针里。
|
|
29
25
|
*
|
|
30
26
|
* ## 为什么 warn 里不再逐条
|
|
31
27
|
* 修前每命中一行 warn(本座的 `warn` 参数形):一份有 113 行读不出的存档,一次列表 + 一次查看 = 342 行,存档没修好每读再发 ——
|
|
@@ -33,8 +29,8 @@ export declare function createCorruptReadSeat(warn: Logger["warn"], event: strin
|
|
|
33
29
|
* `fail_open_total{tag}`,逐条明细进探针。
|
|
34
30
|
*
|
|
35
31
|
* @param tag 登记过的 F 类 tag(`fail-open.ts` 闭集词表;`docs/FAIL-OPEN-CENSUS.md` §1 有登记行)。
|
|
36
|
-
* @param leg
|
|
37
|
-
*
|
|
32
|
+
* @param leg 与披露**同拍**的附加腿(可选):**先于**记账交给它(记账故障不许吃掉腿那一记);腿**必须不抛**(纯内存赋值)。今天唯一的用户 =
|
|
33
|
+
* local 会话店一次性迁移 M33 的整档读作用域(`noteReplayInArchiveRewriteRead`:读时跳过了记录的存档留着不重写)。**收全部三级**(包括不计数的 `replay`)—— 腿要的恰是那条汇总。
|
|
38
34
|
*/
|
|
39
35
|
export declare function createCorruptReadFailOpenSeat(tag: FailOpenTag, leg?: (info: FileStorageCorruptReadInfo) => void): (info: FileStorageCorruptReadInfo) => void;
|
|
40
36
|
/**
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { join, sep } from "node:path";
|
|
2
2
|
import { readJsonlRecords, resolveDataRoot } from "@sema-agent/core";
|
|
3
3
|
import { recordFailOpen } from "./fail-open.js";
|
|
4
|
-
export function createCorruptReadSeat(warn, event, note
|
|
4
|
+
export function createCorruptReadSeat(warn, event, note) {
|
|
5
5
|
return (info) => {
|
|
6
|
-
leg?.(info);
|
|
7
6
|
return warn(event, {
|
|
8
7
|
kind: info.kind,
|
|
9
8
|
path: info.path,
|
|
@@ -201,15 +201,19 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
201
201
|
};
|
|
202
202
|
readonly "server.approvals.park-row-blob-unreadable": {
|
|
203
203
|
readonly cls: "F";
|
|
204
|
-
readonly note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)S-2076
|
|
204
|
+
readonly note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 7.144.0 起同 tag 另有一座:判官判决 `rowVerdict` 与技能卡两位共用的那一次**整行读**(`projectStoredRow`;按快照摘要记忆,未命中才读)—— 整行解不出 ⇒ 这一行不带判决与两位;体是对象但 core 摘要读不动 ⇒ 判决照给、只丢两位;两形逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)";
|
|
205
205
|
};
|
|
206
206
|
readonly "server.approvals.durable-row-checkpoint-id-missing": {
|
|
207
207
|
readonly cls: "F";
|
|
208
208
|
readonly note: "7.133.0(`checkpoint-identity.ts` 的 `durableRowIdentity`;两只店的 `listPending` + `/v1/assistant/inbox` handler):三处 durable 读面(运维队列行 `GET /v1/approvals` 与 `/v1/approvals/stream` 的 `pending` 帧;停驻收件 `GET /v1/assistant/inbox` 的行)读到一行停驻门**没有可用的 `checkpointId`** ⇒ 这一行**照列、`checkpointId` 键缺席**(消费方按「这一行没有可 join 的身份」处理)。detail = `face=<approvals-queue|assistant-inbox> why=<absent|untrusted>`:`absent` = 行上没有这一格(core 5.42.0 之前停驻的老行 —— core 明写不回填);`untrusted` = 在场却没过信任边界(非串 / 空串 / 超长 / 含 resume token —— 数据污染;没过边界的值不上 wire)。放行(列、键缺席)的最坏后果 = 消费方对这一行做不了跨面 join(三面对账少一行)—— 行本身、决断口(`/v1/approvals/:sessionId/decide`,按会话)、到期收割都照常。不放行有两种形:整只拒的代价是一行老 / 坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧);把这一行藏起来的代价更糟 —— 人看不到要批的东西(审批面上的 fail-open,方向反了)。故 F 类;必须留痕(两种成因从此可分)。计数非零 = 有老 / 坏行在飞(列着、没身份);`/stream` 每 3s 一拍重读,同一行每拍计一次(量值 = 行 × 拍数,在场才是信号)。 7.137.0 起第四面:park 账本行(`GET /v1/runs/:id/events` 的 `suspended` / `needs_review`;唯一构造器 `trace/project.ts` 的 `parkEventData`,写时判一次,detail `face=run-events-park`)—— 暂停因由上的门身份没过信任边界 ⇒ 行照写、`checkpointId` 键缺席(决断方回显不了这道门,退回不带键的决断或从 run 结果取原值;行本身、门、待批调用身份照常)。 第五面:回决门族的 200 体(`/decide` / `/resume` / `/plan_review` 执行之前从选中的那一行捕获一次,`http/resume-legs.ts` 三处;detail `face=decision-receipt`)—— 选中那一行的门身份没过信任边界 ⇒ 结清证据照铸、体上 `checkpointId` 键缺席(决断方只是对不上身份;位、决定、续跑都照常)。每次走到捕获点的决断计一次(计的是选中那一行的事实,与这次决断随后走哪条车道无关)。";
|
|
209
209
|
};
|
|
210
|
-
readonly "server.peer-inbound.
|
|
210
|
+
readonly "server.peer-inbound.queue-box-unknown": {
|
|
211
211
|
readonly cls: "F";
|
|
212
|
-
readonly note: "S-1370(`peer-inbound-face.ts` 的 `
|
|
212
|
+
readonly note: "S-1370(`peer-inbound-face.ts` 的 `list`;core 7.62.0 起读 core 的队列枚举 `listPeerHeldQueues`):一只有可审卡的 held 队列,它的箱(`PeerHeldQueueSnapshot.box`)既不是打开它的那只会话自己的箱、也不是 principal 收件箱 ⇒ 拼不出决断口 id 的车道段,那只队列的卡**不列**。按构造不可达:core 的快照注逐字只有这两种箱。放行(不列、队列其余照常)的最坏后果 = 那张被扣的信不出现在 `GET /v1/approvals` 的 `pending[]` 上 —— 它仍在 core 的队列里,按 `dialogExpiry` 带 `expired` 回执结清(core 的安全默认),有序关停照样结清它(关停不按车道筛)。不放行(抛)= 一只读不懂的队列打掉调用方整张审批列表(列表 500、`/stream` 每拍重读每拍抛)。故 F 类;detail `cards=<那只队列的卡数>`;`/stream` 每 3 s 一拍重读,同一只队列每拍计一次(在场才是信号);计数非零 = core 加了第三种箱,对 core 的 d.ts 重核车道读法(`org-delivery-gate.ts` 的 `laneOfBox`)。";
|
|
213
|
+
};
|
|
214
|
+
readonly "server.session-notify.active-run-read-failed": {
|
|
215
|
+
readonly cls: "F";
|
|
216
|
+
readonly note: "`session-notify-door.ts` 的 `deliver`(会话通知门的判活读;两只调用方 `POST /v1/sessions/:id/notify` 与后台子代完成 relay 同经):判活读 —— run 店的单活认领读 `getActiveTaskId` —— 抛(店瞬断 / 超时 / 连接被回收)⇒ 门当这只会话**没有在飞的 run**,落空闲臂:入收件箱,下次开流排空成 `task_notification` 帧,不把读失败抛给调用方。放行的最坏后果 = 这一条通知晚到 —— 本该在活流的下一个边界投递(`priority: next`),改成下一次开流才排空(至少一次,晚一次开流),不丢、不错投;两臂的投递动作之前紧邻的住客复核照做,所以这不是门、不是权限、不是凭证。不放行(抛)= 一次 run 店瞬断把通知路由答成 500(经全局兜底)、把后台子代的完成通知记成 `relay_failed` 交不出去,比晚一次开流更糟。读失败与「会话真的空闲」在外部同形,所以必须留痕:计数 + 探针(detail 带会话 id 与错句,经记录器统一脱敏)+ 每进程一次 warn。";
|
|
213
217
|
};
|
|
214
218
|
readonly "server.approvals.queue-row-gate-kind-missing": {
|
|
215
219
|
readonly cls: "F";
|
|
@@ -325,7 +329,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
325
329
|
};
|
|
326
330
|
readonly "server.park.toolcallid-read-failed": {
|
|
327
331
|
readonly cls: "F";
|
|
328
|
-
readonly note: "[4913]:durable park 投影腿在 strip 之前拿结果里的 checkpointToken 换 `pendingAction.toolCallId`(cs.get 一次读),那次读**抛了**(store 抖动 /
|
|
332
|
+
readonly note: "[4913]:durable park 投影腿在 strip 之前拿结果里的 checkpointToken 换 `pendingAction.toolCallId`(cs.get 一次读),那次读**抛了**(store 抖动 / 坏 checkpoint 行 / 行已被并发消费)⇒ 本次 park 的 wire 投影**缺 `toolCallId` 键**,其余键(gate/checkpointId)照旧。放行的最坏后果 = 消费方(cli 判别子 v3 写者②)退回该键到货前的行为——同族多兄弟 durable park 分不出主角、诚实全不标(cli 侧 S3 局限,成文的旧现状),纯展示/关联面,不参与任何门/CAS/resume 判定,故 F 类。绝不挡终局路径是承重的:park 投影点全在 done/suspended 事件写链上,让它抛会把一次 store 抖动升级成整条 run 终局写失败。必须留痕:键缺席与「tool-less park 本就无键」([1995]② OMITTED 契约)在 wire 上同形,不计数则「投影为什么总缺」在遥测里永不显形。";
|
|
329
333
|
};
|
|
330
334
|
readonly "server.exec-lane.ssh-host-key-unverified": {
|
|
331
335
|
readonly cls: "P-DEBT";
|
|
@@ -337,7 +341,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
337
341
|
};
|
|
338
342
|
readonly "server.approvals.stale-echoed-token-unreadable": {
|
|
339
343
|
readonly cls: "F";
|
|
340
|
-
readonly note: "S-02 codex R1-[medium](验真后修):decide 的 409 `approval_stale` 臂对**调用方回显的旧 token** 做归属判定(`cs.get(binding.checkpointToken)`),那次读**抛了**(store 抖动 /
|
|
344
|
+
readonly note: "S-02 codex R1-[medium](验真后修):decide 的 409 `approval_stale` 臂对**调用方回显的旧 token** 做归属判定(`cs.get(binding.checkpointToken)`),那次读**抛了**(store 抖动 / 坏 checkpoint 行 / 行恰被清理)。修前这里是静默 `catch(()=>null)`,「读不出」被折成「确认不在库」——叠上 S-02 的 404 收口后,一次 store 抖动就会把合法旧 token 的 409+terminal 谎报成 404「没有这条审批」。修后:unreadable ⇒ **保持 409**(`terminal` 不披露——证不出归属就不说,与 2026-07-26 纪律同向;404 折叠只在读成功且未命中时走,探测方无法自控 store 故障 ⇒ 谕示封闭不破)。放行的最坏后果 = 该次拒体 `terminal` 诚实缺席(`currentPending` 由它自己的读口与属主复核另判,不受本臂牵连),壳退回重拉列表,judgment 面 fail-safe,故 F 类。留痕理由:这次读是 terminal 披露与 404 折叠两个判定的输入,长期抖动必须在遥测显形。";
|
|
341
345
|
};
|
|
342
346
|
readonly "server.resume.reopen-confirm-unreadable": {
|
|
343
347
|
readonly cls: "F";
|
|
@@ -345,7 +349,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
345
349
|
};
|
|
346
350
|
readonly "server.approvals.stale-current-pending-unreadable": {
|
|
347
351
|
readonly cls: "F";
|
|
348
|
-
readonly note: "S-02 件2([5522]④→[5525]):409 `approval_stale` 拒体铸 additive 指路键 `currentPending`(本会话当前 pending 的 D-1 坐标,壳一跳重定位)时,当前 pending 行的 `cs.get(token)` 读**抛了**(store 抖动 /
|
|
352
|
+
readonly note: "S-02 件2([5522]④→[5525]):409 `approval_stale` 拒体铸 additive 指路键 `currentPending`(本会话当前 pending 的 D-1 坐标,壳一跳重定位)时,当前 pending 行的 `cs.get(token)` 读**抛了**(store 抖动 / 坏 checkpoint 行 / 行恰被并发消费)⇒ 本次拒体**缺 `currentPending` 键**,409 本体与 `terminal` 判定照旧。放行的最坏后果 = 壳退回该键到货前的行为(重拉 GET /v1/approvals 自行重定位),纯指路/便利面,不参与任何门/CAS/resume 判定,故 F 类(同族先例:`server.park.toolcallid-read-failed`,同为 cs.get 投影读失败臂)。必须留痕:键缺席与「此刻确实没有 pending」在 wire 上同形,不计数则「指路为什么总缺」在遥测里永不显形。";
|
|
349
353
|
};
|
|
350
354
|
readonly "server.file-history.retention-trim-failed": {
|
|
351
355
|
readonly cls: "F";
|
|
@@ -481,7 +485,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
481
485
|
};
|
|
482
486
|
readonly "server.session-repo.corrupt-record-skipped": {
|
|
483
487
|
readonly cls: "F";
|
|
484
|
-
readonly note: "S-990(`plugins/local-session-store.ts` `createLocalSessionRepo` 的 `FileSessionRepo` 座,local 车道的会话存档;`LocalSessionStore` 与会话视图口 `audit.ts` 共用,S-879):一份会话存档里有记录读不出(整行毁 / 半截 JSON / 形不对,core 记成 `kind:\"record\"` 逐条披露)或存档文件 / 目录整体读不出(`kind:\"file\"`)⇒ core 的成文处置是跳过 + 披露,会话照常打开、列表少一行。最坏后果 = 模型读到的历史少了一截 / 列表静默少一份会话 —— 都是**可用性**损失,不开任何门;发起这一轮的人另有 wire 面披露(
|
|
488
|
+
readonly note: "S-990(`plugins/local-session-store.ts` `createLocalSessionRepo` 的 `FileSessionRepo` 座,local 车道的会话存档;`LocalSessionStore` 与会话视图口 `audit.ts` 共用,S-879):一份会话存档里有记录读不出(整行毁 / 半截 JSON / 形不对,core 记成 `kind:\"record\"` 逐条披露)或存档文件 / 目录整体读不出(`kind:\"file\"`)⇒ core 的成文处置是跳过 + 披露,会话照常打开、列表少一行。最坏后果 = 模型读到的历史少了一截 / 列表静默少一份会话 —— 都是**可用性**损失,不开任何门;发起这一轮的人另有 wire 面披露(core 7.62.0 起引擎在 run 里说 `engine_notice` 码 `session.lineage_rerooted`,丢失账读自 core 交出的存储 `getReplayLoss`,与本 tag 无关;7.104.0–7.143.0 是本仓自铸的 `session.records_skipped`)⇒ F。**计数单位 = 一条被跳过的记录 = 一次命中**(`replay` 级是同一批记录的汇总,不计,S-616 同教训);**每命中一行探针**(`SEMA_FAILOPEN_PROBE`)带 `path` / `sessionId` / `line` / `form` / `reason` 逐条明细 —— 运维要看「哪份存档的哪一行坏了」读探针,不读本条 warn:本条是每进程每 tag 一次的告警(`detail` 是首条明细,不是全部)。修前:每命中一行 warn,一份 113 行坏记录的存档做一次列表 + 一次查看打出 342 行,存档没修好每读再发。";
|
|
485
489
|
};
|
|
486
490
|
readonly "server.workflow-run.corrupt-record-skipped": {
|
|
487
491
|
readonly cls: "F";
|
|
@@ -595,7 +599,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
595
599
|
};
|
|
596
600
|
readonly "server.remote-write.stage-seal-fallback": {
|
|
597
601
|
readonly cls: "F";
|
|
598
|
-
readonly note: "远端五条车道的写(`plugins/remote-shell.ts` 的暂存编排):准备脚本把刚建的私有暂存目录收成 0700 并读回核实(`chmod 700` 退出 0 ∧ `stat` 读回的模式低三位恰是 700 ∧ 属主 = 本身份),任一步不成 —— `chmod` 被文件系统 / 内核拒;退出 0 却没生效(不认权限位的文件系统);父目录带缺省 ACL
|
|
602
|
+
readonly note: "远端五条车道的写(`plugins/remote-shell.ts` 的暂存编排):准备脚本把刚建的私有暂存目录收成 0700 并读回核实(`chmod 700` 退出 0 ∧ `stat` 读回的模式低三位恰是 700 ∧ 属主 = 本身份),任一步不成 —— `chmod` 被文件系统 / 内核拒;退出 0 却没生效(不认权限位的文件系统);父目录带缺省 ACL 而掩码收不下来;目录上有继承来的 ACL 条目(macOS 原生 ACL / FreeBSD · illumos ZFS 的 NFSv4 ACL)去不掉或读不出,或目标机平台不在读 ACL 的适配器闭集里(`uname -s` 不是 Linux / Darwin / FreeBSD / SunOS);目标机上没有 `stat` —— 准备退出 4、这次写**不暂存**,两只文件面、五条腿一律改为直接写目标(与「目标目录不收新名字」同一条回落;能追加写的腿直接追加,e2b / adb 的追加 = 读旧 + 拼 + 整份写目标 —— adb 的这一形就是 7.138.x 的追加,push 没有追加写)。修前这一步是 `chmod 700 … || :`:加固失败照样放行上传,字节落在一只别的身份可能读得到的目录里(P 轴 fail-open),那一臂已删,字节从不进一只没核成私有的目录。放行的最坏后果 = 这一次写失去「整旧或整新」(非原子:中途断 / 取消 ⇒ 目标可能只写了一半,整份写目标的 e2b / adb 上可能没了或只剩半份;写目标那一步因取消中断答 `unknown`,那一步开始之前取消答 `aborted`、目标未碰,那一步不收取消(ssh 的 sftp)照样写完);ssh / local-docker / k8s 写进原 inode、权限位不变,e2b 的 `files.write` 与 adb 的 push 整份写目标、inode / 权限位由对端定(adbd 不保,与 7.138.x 同形);不是门、不是凭据。Android 共享存储(`/sdcard` 一类:权限位由挂载派生、不认 chmod)上 adb 的写按 sdcardfs / MediaProvider FUSE 的权限语义**推断**每一次都走这里(未上真机,真机读数候 test;结构性,运维修不掉;工作区放在 `/data/local/tmp` 一类认权限位的目录就不走)。计数非零 = 这台目标机的这个目录上私有目录收不成私有(文件系统不认权限位 / 缺省 ACL 掩码收不下来 / 继承来的 ACL 条目去不掉 / 平台不可知 / 缺 `stat`),写在走非原子的退路,去看那个目录。detail = `<目标路径>: <准备脚本写的原因句>`。";
|
|
599
603
|
};
|
|
600
604
|
readonly "server.park.held-card-void-failed": {
|
|
601
605
|
readonly cls: "F";
|
|
@@ -183,15 +183,19 @@ export const FAIL_OPEN_TAGS = {
|
|
|
183
183
|
},
|
|
184
184
|
"server.approvals.park-row-blob-unreadable": {
|
|
185
185
|
cls: "F",
|
|
186
|
-
note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)S-2076
|
|
186
|
+
note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `readParkRowActionCell`):运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint` 列里寄存行的 **`pendingAction` 子树**(NP-3 / 7.100.0 起引擎内只取这一棵、整只快照不出库;只为 park 行事实 `requiresRealApproval` / `ruleOffersAbsence` / `mandated`(S-663 二段,core #1079)/ `mandate`(S-721)/ `origin`(S-755)而读 —— 事实位的真源是 `approval-card.ts` 的 `ParkRowFacts`)**在场却不是一只对象**(JSON `null` 字面 / 串 / 数 —— 手改 / 迁移脚本改过)。子树**缺席**(SQL NULL:成员不在,或整只文档不是对象 —— 后者 `get()` 照旧拒;MariaDB 文本承载上的非 JSON 字节同样答 SQL NULL)⇒ 事实缺席、不计数。放行的最坏后果 = **这一行**的 park 行事实(`ParkRowFacts` 各位)缺席(展示/分诊材料;core 定性 display metadata,resume 的带子读 gate 自己的位),队列其余部分照常 —— 而这一行本来就 resume 不了(`get()` 对同一格拒)。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 blob 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),与同一 `rows.map` 里 `rule_suggestions` / `risk_descriptor` 两格同族同判。故 F 类;tag 与那两格**分开计**(哪一格在坏要读得出来)。计数非零 = 这一行的 decide 同样读不动(`get()` 对同一格拒),去按 session 查那一行。 7.144.0 起同 tag 另有一座:判官判决 `rowVerdict` 与技能卡两位共用的那一次**整行读**(`projectStoredRow`;按快照摘要记忆,未命中才读)—— 整行解不出 ⇒ 这一行不带判决与两位;体是对象但 core 摘要读不动 ⇒ 判决照给、只丢两位;两形逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)",
|
|
187
187
|
},
|
|
188
188
|
"server.approvals.durable-row-checkpoint-id-missing": {
|
|
189
189
|
cls: "F",
|
|
190
190
|
note: "7.133.0(`checkpoint-identity.ts` 的 `durableRowIdentity`;两只店的 `listPending` + `/v1/assistant/inbox` handler):三处 durable 读面(运维队列行 `GET /v1/approvals` 与 `/v1/approvals/stream` 的 `pending` 帧;停驻收件 `GET /v1/assistant/inbox` 的行)读到一行停驻门**没有可用的 `checkpointId`** ⇒ 这一行**照列、`checkpointId` 键缺席**(消费方按「这一行没有可 join 的身份」处理)。detail = `face=<approvals-queue|assistant-inbox> why=<absent|untrusted>`:`absent` = 行上没有这一格(core 5.42.0 之前停驻的老行 —— core 明写不回填);`untrusted` = 在场却没过信任边界(非串 / 空串 / 超长 / 含 resume token —— 数据污染;没过边界的值不上 wire)。放行(列、键缺席)的最坏后果 = 消费方对这一行做不了跨面 join(三面对账少一行)—— 行本身、决断口(`/v1/approvals/:sessionId/decide`,按会话)、到期收割都照常。不放行有两种形:整只拒的代价是一行老 / 坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧);把这一行藏起来的代价更糟 —— 人看不到要批的东西(审批面上的 fail-open,方向反了)。故 F 类;必须留痕(两种成因从此可分)。计数非零 = 有老 / 坏行在飞(列着、没身份);`/stream` 每 3s 一拍重读,同一行每拍计一次(量值 = 行 × 拍数,在场才是信号)。 7.137.0 起第四面:park 账本行(`GET /v1/runs/:id/events` 的 `suspended` / `needs_review`;唯一构造器 `trace/project.ts` 的 `parkEventData`,写时判一次,detail `face=run-events-park`)—— 暂停因由上的门身份没过信任边界 ⇒ 行照写、`checkpointId` 键缺席(决断方回显不了这道门,退回不带键的决断或从 run 结果取原值;行本身、门、待批调用身份照常)。 第五面:回决门族的 200 体(`/decide` / `/resume` / `/plan_review` 执行之前从选中的那一行捕获一次,`http/resume-legs.ts` 三处;detail `face=decision-receipt`)—— 选中那一行的门身份没过信任边界 ⇒ 结清证据照铸、体上 `checkpointId` 键缺席(决断方只是对不上身份;位、决定、续跑都照常)。每次走到捕获点的决断计一次(计的是选中那一行的事实,与这次决断随后走哪条车道无关)。",
|
|
191
191
|
},
|
|
192
|
-
"server.peer-inbound.
|
|
192
|
+
"server.peer-inbound.queue-box-unknown": {
|
|
193
193
|
cls: "F",
|
|
194
|
-
note: "S-1370(`peer-inbound-face.ts` 的 `
|
|
194
|
+
note: "S-1370(`peer-inbound-face.ts` 的 `list`;core 7.62.0 起读 core 的队列枚举 `listPeerHeldQueues`):一只有可审卡的 held 队列,它的箱(`PeerHeldQueueSnapshot.box`)既不是打开它的那只会话自己的箱、也不是 principal 收件箱 ⇒ 拼不出决断口 id 的车道段,那只队列的卡**不列**。按构造不可达:core 的快照注逐字只有这两种箱。放行(不列、队列其余照常)的最坏后果 = 那张被扣的信不出现在 `GET /v1/approvals` 的 `pending[]` 上 —— 它仍在 core 的队列里,按 `dialogExpiry` 带 `expired` 回执结清(core 的安全默认),有序关停照样结清它(关停不按车道筛)。不放行(抛)= 一只读不懂的队列打掉调用方整张审批列表(列表 500、`/stream` 每拍重读每拍抛)。故 F 类;detail `cards=<那只队列的卡数>`;`/stream` 每 3 s 一拍重读,同一只队列每拍计一次(在场才是信号);计数非零 = core 加了第三种箱,对 core 的 d.ts 重核车道读法(`org-delivery-gate.ts` 的 `laneOfBox`)。",
|
|
195
|
+
},
|
|
196
|
+
"server.session-notify.active-run-read-failed": {
|
|
197
|
+
cls: "F",
|
|
198
|
+
note: "`session-notify-door.ts` 的 `deliver`(会话通知门的判活读;两只调用方 `POST /v1/sessions/:id/notify` 与后台子代完成 relay 同经):判活读 —— run 店的单活认领读 `getActiveTaskId` —— 抛(店瞬断 / 超时 / 连接被回收)⇒ 门当这只会话**没有在飞的 run**,落空闲臂:入收件箱,下次开流排空成 `task_notification` 帧,不把读失败抛给调用方。放行的最坏后果 = 这一条通知晚到 —— 本该在活流的下一个边界投递(`priority: next`),改成下一次开流才排空(至少一次,晚一次开流),不丢、不错投;两臂的投递动作之前紧邻的住客复核照做,所以这不是门、不是权限、不是凭证。不放行(抛)= 一次 run 店瞬断把通知路由答成 500(经全局兜底)、把后台子代的完成通知记成 `relay_failed` 交不出去,比晚一次开流更糟。读失败与「会话真的空闲」在外部同形,所以必须留痕:计数 + 探针(detail 带会话 id 与错句,经记录器统一脱敏)+ 每进程一次 warn。",
|
|
195
199
|
},
|
|
196
200
|
"server.approvals.queue-row-gate-kind-missing": {
|
|
197
201
|
cls: "F",
|
|
@@ -307,7 +311,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
307
311
|
},
|
|
308
312
|
"server.park.toolcallid-read-failed": {
|
|
309
313
|
cls: "F",
|
|
310
|
-
note: "[4913]:durable park 投影腿在 strip 之前拿结果里的 checkpointToken 换 `pendingAction.toolCallId`(cs.get 一次读),那次读**抛了**(store 抖动 /
|
|
314
|
+
note: "[4913]:durable park 投影腿在 strip 之前拿结果里的 checkpointToken 换 `pendingAction.toolCallId`(cs.get 一次读),那次读**抛了**(store 抖动 / 坏 checkpoint 行 / 行已被并发消费)⇒ 本次 park 的 wire 投影**缺 `toolCallId` 键**,其余键(gate/checkpointId)照旧。放行的最坏后果 = 消费方(cli 判别子 v3 写者②)退回该键到货前的行为——同族多兄弟 durable park 分不出主角、诚实全不标(cli 侧 S3 局限,成文的旧现状),纯展示/关联面,不参与任何门/CAS/resume 判定,故 F 类。绝不挡终局路径是承重的:park 投影点全在 done/suspended 事件写链上,让它抛会把一次 store 抖动升级成整条 run 终局写失败。必须留痕:键缺席与「tool-less park 本就无键」([1995]② OMITTED 契约)在 wire 上同形,不计数则「投影为什么总缺」在遥测里永不显形。",
|
|
311
315
|
},
|
|
312
316
|
"server.exec-lane.ssh-host-key-unverified": {
|
|
313
317
|
cls: "P-DEBT",
|
|
@@ -319,7 +323,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
319
323
|
},
|
|
320
324
|
"server.approvals.stale-echoed-token-unreadable": {
|
|
321
325
|
cls: "F",
|
|
322
|
-
note: "S-02 codex R1-[medium](验真后修):decide 的 409 `approval_stale` 臂对**调用方回显的旧 token** 做归属判定(`cs.get(binding.checkpointToken)`),那次读**抛了**(store 抖动 /
|
|
326
|
+
note: "S-02 codex R1-[medium](验真后修):decide 的 409 `approval_stale` 臂对**调用方回显的旧 token** 做归属判定(`cs.get(binding.checkpointToken)`),那次读**抛了**(store 抖动 / 坏 checkpoint 行 / 行恰被清理)。修前这里是静默 `catch(()=>null)`,「读不出」被折成「确认不在库」——叠上 S-02 的 404 收口后,一次 store 抖动就会把合法旧 token 的 409+terminal 谎报成 404「没有这条审批」。修后:unreadable ⇒ **保持 409**(`terminal` 不披露——证不出归属就不说,与 2026-07-26 纪律同向;404 折叠只在读成功且未命中时走,探测方无法自控 store 故障 ⇒ 谕示封闭不破)。放行的最坏后果 = 该次拒体 `terminal` 诚实缺席(`currentPending` 由它自己的读口与属主复核另判,不受本臂牵连),壳退回重拉列表,judgment 面 fail-safe,故 F 类。留痕理由:这次读是 terminal 披露与 404 折叠两个判定的输入,长期抖动必须在遥测显形。",
|
|
323
327
|
},
|
|
324
328
|
"server.resume.reopen-confirm-unreadable": {
|
|
325
329
|
cls: "F",
|
|
@@ -327,7 +331,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
327
331
|
},
|
|
328
332
|
"server.approvals.stale-current-pending-unreadable": {
|
|
329
333
|
cls: "F",
|
|
330
|
-
note: "S-02 件2([5522]④→[5525]):409 `approval_stale` 拒体铸 additive 指路键 `currentPending`(本会话当前 pending 的 D-1 坐标,壳一跳重定位)时,当前 pending 行的 `cs.get(token)` 读**抛了**(store 抖动 /
|
|
334
|
+
note: "S-02 件2([5522]④→[5525]):409 `approval_stale` 拒体铸 additive 指路键 `currentPending`(本会话当前 pending 的 D-1 坐标,壳一跳重定位)时,当前 pending 行的 `cs.get(token)` 读**抛了**(store 抖动 / 坏 checkpoint 行 / 行恰被并发消费)⇒ 本次拒体**缺 `currentPending` 键**,409 本体与 `terminal` 判定照旧。放行的最坏后果 = 壳退回该键到货前的行为(重拉 GET /v1/approvals 自行重定位),纯指路/便利面,不参与任何门/CAS/resume 判定,故 F 类(同族先例:`server.park.toolcallid-read-failed`,同为 cs.get 投影读失败臂)。必须留痕:键缺席与「此刻确实没有 pending」在 wire 上同形,不计数则「指路为什么总缺」在遥测里永不显形。",
|
|
331
335
|
},
|
|
332
336
|
"server.file-history.retention-trim-failed": {
|
|
333
337
|
cls: "F",
|
|
@@ -439,7 +443,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
439
443
|
},
|
|
440
444
|
"server.session-repo.corrupt-record-skipped": {
|
|
441
445
|
cls: "F",
|
|
442
|
-
note: "S-990(`plugins/local-session-store.ts` `createLocalSessionRepo` 的 `FileSessionRepo` 座,local 车道的会话存档;`LocalSessionStore` 与会话视图口 `audit.ts` 共用,S-879):一份会话存档里有记录读不出(整行毁 / 半截 JSON / 形不对,core 记成 `kind:\"record\"` 逐条披露)或存档文件 / 目录整体读不出(`kind:\"file\"`)⇒ core 的成文处置是跳过 + 披露,会话照常打开、列表少一行。最坏后果 = 模型读到的历史少了一截 / 列表静默少一份会话 —— 都是**可用性**损失,不开任何门;发起这一轮的人另有 wire 面披露(
|
|
446
|
+
note: "S-990(`plugins/local-session-store.ts` `createLocalSessionRepo` 的 `FileSessionRepo` 座,local 车道的会话存档;`LocalSessionStore` 与会话视图口 `audit.ts` 共用,S-879):一份会话存档里有记录读不出(整行毁 / 半截 JSON / 形不对,core 记成 `kind:\"record\"` 逐条披露)或存档文件 / 目录整体读不出(`kind:\"file\"`)⇒ core 的成文处置是跳过 + 披露,会话照常打开、列表少一行。最坏后果 = 模型读到的历史少了一截 / 列表静默少一份会话 —— 都是**可用性**损失,不开任何门;发起这一轮的人另有 wire 面披露(core 7.62.0 起引擎在 run 里说 `engine_notice` 码 `session.lineage_rerooted`,丢失账读自 core 交出的存储 `getReplayLoss`,与本 tag 无关;7.104.0–7.143.0 是本仓自铸的 `session.records_skipped`)⇒ F。**计数单位 = 一条被跳过的记录 = 一次命中**(`replay` 级是同一批记录的汇总,不计,S-616 同教训);**每命中一行探针**(`SEMA_FAILOPEN_PROBE`)带 `path` / `sessionId` / `line` / `form` / `reason` 逐条明细 —— 运维要看「哪份存档的哪一行坏了」读探针,不读本条 warn:本条是每进程每 tag 一次的告警(`detail` 是首条明细,不是全部)。修前:每命中一行 warn,一份 113 行坏记录的存档做一次列表 + 一次查看打出 342 行,存档没修好每读再发。",
|
|
443
447
|
},
|
|
444
448
|
"server.workflow-run.corrupt-record-skipped": {
|
|
445
449
|
cls: "F",
|
|
@@ -553,7 +557,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
553
557
|
},
|
|
554
558
|
"server.remote-write.stage-seal-fallback": {
|
|
555
559
|
cls: "F",
|
|
556
|
-
note: "远端五条车道的写(`plugins/remote-shell.ts` 的暂存编排):准备脚本把刚建的私有暂存目录收成 0700 并读回核实(`chmod 700` 退出 0 ∧ `stat` 读回的模式低三位恰是 700 ∧ 属主 = 本身份),任一步不成 —— `chmod` 被文件系统 / 内核拒;退出 0 却没生效(不认权限位的文件系统);父目录带缺省 ACL
|
|
560
|
+
note: "远端五条车道的写(`plugins/remote-shell.ts` 的暂存编排):准备脚本把刚建的私有暂存目录收成 0700 并读回核实(`chmod 700` 退出 0 ∧ `stat` 读回的模式低三位恰是 700 ∧ 属主 = 本身份),任一步不成 —— `chmod` 被文件系统 / 内核拒;退出 0 却没生效(不认权限位的文件系统);父目录带缺省 ACL 而掩码收不下来;目录上有继承来的 ACL 条目(macOS 原生 ACL / FreeBSD · illumos ZFS 的 NFSv4 ACL)去不掉或读不出,或目标机平台不在读 ACL 的适配器闭集里(`uname -s` 不是 Linux / Darwin / FreeBSD / SunOS);目标机上没有 `stat` —— 准备退出 4、这次写**不暂存**,两只文件面、五条腿一律改为直接写目标(与「目标目录不收新名字」同一条回落;能追加写的腿直接追加,e2b / adb 的追加 = 读旧 + 拼 + 整份写目标 —— adb 的这一形就是 7.138.x 的追加,push 没有追加写)。修前这一步是 `chmod 700 … || :`:加固失败照样放行上传,字节落在一只别的身份可能读得到的目录里(P 轴 fail-open),那一臂已删,字节从不进一只没核成私有的目录。放行的最坏后果 = 这一次写失去「整旧或整新」(非原子:中途断 / 取消 ⇒ 目标可能只写了一半,整份写目标的 e2b / adb 上可能没了或只剩半份;写目标那一步因取消中断答 `unknown`,那一步开始之前取消答 `aborted`、目标未碰,那一步不收取消(ssh 的 sftp)照样写完);ssh / local-docker / k8s 写进原 inode、权限位不变,e2b 的 `files.write` 与 adb 的 push 整份写目标、inode / 权限位由对端定(adbd 不保,与 7.138.x 同形);不是门、不是凭据。Android 共享存储(`/sdcard` 一类:权限位由挂载派生、不认 chmod)上 adb 的写按 sdcardfs / MediaProvider FUSE 的权限语义**推断**每一次都走这里(未上真机,真机读数候 test;结构性,运维修不掉;工作区放在 `/data/local/tmp` 一类认权限位的目录就不走)。计数非零 = 这台目标机的这个目录上私有目录收不成私有(文件系统不认权限位 / 缺省 ACL 掩码收不下来 / 继承来的 ACL 条目去不掉 / 平台不可知 / 缺 `stat`),写在走非原子的退路,去看那个目录。detail = `<目标路径>: <准备脚本写的原因句>`。",
|
|
557
561
|
},
|
|
558
562
|
"server.park.held-card-void-failed": {
|
|
559
563
|
cls: "F",
|
|
@@ -122,7 +122,7 @@ export declare function redactErrorMessage(raw: string | undefined): string | un
|
|
|
122
122
|
* `plugins/pg-pool.ts` 的 DDL),数 MB 终稿是正常形 —— {@link redactErrorMessage} 的两道上限是为
|
|
123
123
|
* `task_run.error` 那一列 `TEXT(65 535 字节)` 定的,套到这里等于用静默的数据损坏换一次脱敏。
|
|
124
124
|
*/
|
|
125
|
-
export declare function redactModelText(raw: string): string;
|
|
125
|
+
export declare function redactModelText(raw: string, before?: string): string;
|
|
126
126
|
/**
|
|
127
127
|
* 🔴 **provider 回声字段的形状闸 —— 唯一铸点**([ref],7.105.0;test [ref] 附带;动作经 [ref] 与 core 源头闸归一)。
|
|
128
128
|
*
|
|
@@ -85,9 +85,9 @@ export function redactErrorMessage(raw) {
|
|
|
85
85
|
return OVERSIZED_REDACTION_PLACEHOLDER;
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
export function redactModelText(raw) {
|
|
88
|
+
export function redactModelText(raw, before = "") {
|
|
89
89
|
try {
|
|
90
|
-
return redactSecrets(raw);
|
|
90
|
+
return redactSecrets(raw, before === "" ? undefined : { before });
|
|
91
91
|
}
|
|
92
92
|
catch (err) {
|
|
93
93
|
recordFailOpen("server.run-terminal.redact-threw", `model-text len=${raw.length} err=${errorText(err)}`);
|
|
@@ -24,17 +24,16 @@
|
|
|
24
24
|
* 近似如实记:重解的列表是**部署缺省**那一份,读不回那一 run 的逐请求差异(`settings.webSearch` 后端、center overlay 场景)——
|
|
25
25
|
* 座只判 bundle 实例的成员性,继承面是 `[...web, ...scaffolds]`,那两项差异不改变谁在面内。
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `{
|
|
31
|
-
*
|
|
32
|
-
* (批准之后删了、同 id 被重新登记)⇒ 停驻否决 —— 两件都在挂点那一侧判,与这里无关。
|
|
27
|
+
* **委派树根见证([ref])与交座是两个独立判据**:Runner 之外复活的后台子代的完成 relay(会话通知门,`session-notify-door.ts`)要**委派树根的见证**:
|
|
28
|
+
* 根 id(行上本来就带 `rootSessionId`)+ 判断那一刻的根行住客 = 写口放行的那一位(赎回腿解析器那一读;不是那一位时写口整条拒,走不到这里)—— 见证恒带住客。
|
|
29
|
+
* 所以**每一行**都交出它({@link ScenarioContext} 的 `delegationRoot`):交座的一层行以 `{ sessionId: root, delegationRoot }` 重解,不交座的行(更深的行、根属主不是卡的租户的
|
|
30
|
+
* 一层行)以 `{ delegationRoot }` 重解 —— 只喂 relay,不挂任何会话级设施、不带 principal,交座判据(上面三条)一个字不动。行上没有根 ⇒ boot 期那只裸 Agent(没有根可交 ⇒ 不接 relay)。
|
|
31
|
+
* 复活的子代再要审批时的停驻挂点(`plugins/session-store.ts`)不读见证:引擎交它那一行自己的属主,挂点只比对(core 7.62.0 [ref];根见证在挂点的读法随 [ref] P-5 退役)。
|
|
33
32
|
*/
|
|
34
33
|
import { type BackgroundAgentRecord, type ToolSpec } from "@sema-agent/core";
|
|
35
34
|
import type { Scenario } from "./capabilities/scenarios.js";
|
|
36
35
|
import type { SessionFace } from "./session-incarnation.js";
|
|
37
|
-
/** 一次赎回用的面:驱动的 Agent 工具(
|
|
36
|
+
/** 一次赎回用的面:驱动的 Agent 工具(它的完成 relay 绑着行上的根)+ (交座时)与它同出一张列表的继承座。 */
|
|
38
37
|
export interface ParkedReviveSurface {
|
|
39
38
|
readonly reviveTool: ToolSpec;
|
|
40
39
|
/** 缺席 = 不交座(core fail-closed:复活的子代不继承任何场景层工具)。 */
|