@sema-agent/server 7.143.0 → 7.145.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.
Files changed (139) hide show
  1. package/MIGRATION.md +295 -0
  2. package/README.md +3 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +34 -16
  5. package/dist/approval-card.d.ts +31 -14
  6. package/dist/approval-card.js +8 -8
  7. package/dist/audit.d.ts +2 -21
  8. package/dist/audit.js +0 -9
  9. package/dist/boot/execution-env.js +1 -1
  10. package/dist/boot/runner-deps.d.ts +10 -5
  11. package/dist/boot/runner-deps.js +5 -4
  12. package/dist/boot/session-faces.d.ts +1 -1
  13. package/dist/boot/session-faces.js +3 -3
  14. package/dist/boot/shutdown.d.ts +1 -1
  15. package/dist/boot/shutdown.js +4 -2
  16. package/dist/boot/stage-01-config.js +2 -0
  17. package/dist/boot/stage-07-capability-layer.js +1 -1
  18. package/dist/boot/stage-09-leader.d.ts +1 -1
  19. package/dist/boot/stage-10-http-server.d.ts +1 -1
  20. package/dist/boot/stage-10-http-server.js +4 -9
  21. package/dist/capabilities/scenarios.d.ts +14 -18
  22. package/dist/capabilities/scenarios.js +1 -2
  23. package/dist/config-d-migration.d.ts +3 -0
  24. package/dist/delegated-session-owner.d.ts +33 -151
  25. package/dist/delegated-session-owner.js +1 -83
  26. package/dist/entry-mode-clamp-notice.d.ts +1 -1
  27. package/dist/execution-placement.d.ts +7 -4
  28. package/dist/fleet/fleet-bus.d.ts +13 -3
  29. package/dist/fleet/fleet-bus.js +17 -3
  30. package/dist/hooks/classic-stations.d.ts +3 -1
  31. package/dist/hooks/classic-stations.js +2 -0
  32. package/dist/http/admission.js +2 -1
  33. package/dist/http/checkpoint-ctx.d.ts +1 -0
  34. package/dist/http/checkpoint-ctx.js +1 -0
  35. package/dist/http/durable-run-leg.js +7 -6
  36. package/dist/http/principal-gate.d.ts +1 -1
  37. package/dist/http/refusal-body.d.ts +7 -3
  38. package/dist/http/refusal-body.js +1 -0
  39. package/dist/http/resume-legs.js +16 -7
  40. package/dist/http/route-ctx.d.ts +15 -0
  41. package/dist/http/routes/approvals-assistant.d.ts +20 -1
  42. package/dist/http/routes/approvals-assistant.js +28 -6
  43. package/dist/http/routes/rules.d.ts +1 -1
  44. package/dist/http/routes/rules.js +5 -2
  45. package/dist/http/routes/session-sync.js +12 -0
  46. package/dist/http/routes/tasks.js +12 -9
  47. package/dist/http/run-meta.d.ts +14 -7
  48. package/dist/http/run-meta.js +5 -2
  49. package/dist/http/server.d.ts +13 -5
  50. package/dist/http/server.js +3 -0
  51. package/dist/http/submit-ctx.d.ts +12 -0
  52. package/dist/http/submit-ctx.js +23 -0
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.js +1 -0
  55. package/dist/lane-home-probe.d.ts +15 -0
  56. package/dist/lane-home-probe.js +4 -0
  57. package/dist/observability/corrupt-read-seat.d.ts +5 -9
  58. package/dist/observability/corrupt-read-seat.js +1 -2
  59. package/dist/observability/fail-open.d.ts +26 -10
  60. package/dist/observability/fail-open.js +26 -10
  61. package/dist/observability/run-terminal.d.ts +1 -1
  62. package/dist/observability/run-terminal.js +2 -2
  63. package/dist/parked-revive-surface.d.ts +6 -7
  64. package/dist/peer-inbound-face.d.ts +29 -34
  65. package/dist/peer-inbound-face.js +28 -63
  66. package/dist/plugins/approval-ask-store-file.d.ts +16 -2
  67. package/dist/plugins/approval-ask-store-file.js +21 -1
  68. package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
  69. package/dist/plugins/approval-ask-store-memory.js +11 -8
  70. package/dist/plugins/caching-session-store.d.ts +3 -3
  71. package/dist/plugins/caching-session-store.js +3 -3
  72. package/dist/plugins/checkpoint-store-sql.d.ts +62 -37
  73. package/dist/plugins/checkpoint-store-sql.js +123 -40
  74. package/dist/plugins/file-run-store.d.ts +13 -1
  75. package/dist/plugins/file-run-store.js +11 -1
  76. package/dist/plugins/fork-routing-session-store.d.ts +8 -1
  77. package/dist/plugins/fork-routing-session-store.js +6 -0
  78. package/dist/plugins/local-checkpoint-store.d.ts +17 -8
  79. package/dist/plugins/local-checkpoint-store.js +26 -7
  80. package/dist/plugins/local-session-store.d.ts +105 -34
  81. package/dist/plugins/local-session-store.js +168 -65
  82. package/dist/plugins/local-session-window.d.ts +4 -2
  83. package/dist/plugins/memory-run-store.d.ts +2 -0
  84. package/dist/plugins/memory-run-store.js +6 -0
  85. package/dist/plugins/one-time-migrations.d.ts +12 -12
  86. package/dist/plugins/one-time-migrations.js +13 -13
  87. package/dist/plugins/pg-session-storage.d.ts +1 -9
  88. package/dist/plugins/pg-session-storage.js +2 -19
  89. package/dist/plugins/remote-env-host.d.ts +8 -4
  90. package/dist/plugins/remote-env-host.js +7 -9
  91. package/dist/plugins/remote-shell.js +12 -2
  92. package/dist/plugins/run-store-sql.d.ts +4 -0
  93. package/dist/plugins/run-store-sql.js +3 -0
  94. package/dist/plugins/schema-consistency.d.ts +5 -1
  95. package/dist/plugins/session-fork.d.ts +1 -1
  96. package/dist/plugins/session-ownership.d.ts +9 -0
  97. package/dist/plugins/session-ownership.js +6 -0
  98. package/dist/plugins/session-store.d.ts +13 -16
  99. package/dist/plugins/session-store.js +9 -10
  100. package/dist/plugins/sql-json-column.d.ts +24 -2
  101. package/dist/plugins/sql-json-column.js +38 -3
  102. package/dist/plugins/store-backend.js +3 -2
  103. package/dist/plugins/tidb-session-store.d.ts +2 -14
  104. package/dist/plugins/tidb-session-store.js +2 -20
  105. package/dist/prompt-screen.d.ts +21 -0
  106. package/dist/prompt-screen.js +8 -0
  107. package/dist/rules-consent.d.ts +63 -51
  108. package/dist/rules-consent.js +6 -10
  109. package/dist/run-acceptance.d.ts +40 -10
  110. package/dist/run-acceptance.js +38 -5
  111. package/dist/run-local.js +2 -1
  112. package/dist/runs.js +5 -1
  113. package/dist/security.d.ts +10 -7
  114. package/dist/session-agent.d.ts +39 -0
  115. package/dist/session-agent.js +16 -0
  116. package/dist/session-error-wire.d.ts +25 -26
  117. package/dist/session-error-wire.js +4 -5
  118. package/dist/session-incarnation.d.ts +2 -2
  119. package/dist/session-notify-door.d.ts +2 -2
  120. package/dist/session-notify-door.js +5 -1
  121. package/dist/tool-approval.d.ts +3 -1
  122. package/dist/tool-approval.js +47 -18
  123. package/dist/trace/core-keyset-guard.d.ts +1 -1
  124. package/dist/trace/engine-notice-wire.d.ts +1 -1
  125. package/dist/trace/engine-notice-wire.js +1 -1
  126. package/dist/trace/ledger-sink.js +12 -4
  127. package/dist/trace/model-segment.d.ts +26 -6
  128. package/dist/trace/model-segment.js +58 -9
  129. package/dist/trace/project.d.ts +8 -2
  130. package/dist/trace/project.js +6 -4
  131. package/dist/trace/redact.d.ts +77 -2
  132. package/dist/trace/redact.js +234 -99
  133. package/dist/trace/self-minted-wire.d.ts +160 -9
  134. package/dist/trace/self-minted-wire.js +52 -3
  135. package/package.json +3 -3
  136. package/wire-changes/server@7.144.0.json +291 -0
  137. package/wire-changes/server@7.145.0.json +146 -0
  138. package/dist/session-records-skipped-notice.d.ts +0 -21
  139. package/dist/session-records-skipped-notice.js +0 -27
@@ -2,7 +2,7 @@ import http from "node:http";
2
2
  import type { MemoryComplianceFaces, MemoryOriginFaces, SessionMemoryStatusFace } from "../memory-operator-faces.js";
3
3
  import type { SideQueryAccounting } from "../budget.js";
4
4
  import type { IncomingMessage } from "node:http";
5
- import { type Runner, type TaskSpec, type TaskResult, type WorkflowRunStore, type MemoryEntry, type MemoryExportBundle, type MemoryImportReport, type ConsolidationRunReceipt, type ConsolidationDriverRunRow, type SideQuerySpec, type SideQueryResult, type Brain, type EngineNotice } from "@sema-agent/core";
5
+ import { type Runner, type RunnerDeps, type TaskSpec, type TaskResult, type WorkflowRunStore, type MemoryEntry, type MemoryExportBundle, type MemoryImportReport, type ConsolidationRunReceipt, type ConsolidationDriverRunRow, type SideQuerySpec, type SideQueryResult, type Brain, type EngineNotice } from "@sema-agent/core";
6
6
  import type { TaskRequestBody } from "./wire-types.js";
7
7
  import type { ServiceConfig } from "../config-types.js";
8
8
  import { type SessionMirrorRuling } from "../web-admin-client/facade.js";
@@ -65,7 +65,7 @@ export interface RequestAuth {
65
65
  * 平铺形的直接后果 = main.ts 一个上千行的装配字面量,键与键之间没有任何「属于同一件事」的编译期表达,
66
66
  * 键落错家/从未接线只能靠源码钉逐个盯(1.300/1.301/1.304/1.307/1.310 五起真缺陷都是这个病族)。
67
67
  *
68
- * 药:七个**窄**接口 + 顶层必填八件。装配点按组构造(每组一个带类型标注的中间 const ⇒ 受 TS 多余
68
+ * 药:七个**窄**接口 + 顶层必填件(今天九件)。装配点按组构造(每组一个带类型标注的中间 const ⇒ 受 TS 多余
69
69
  * 属性检查保护),键放错组当场编译红。
70
70
  *
71
71
  * 兼容形(本批**不动消费点**):`ServiceDeps` = 平铺视图 ∩ 组槽。旧的平铺构造(96 个测试文件 +
@@ -73,8 +73,8 @@ export interface RequestAuth {
73
73
  * 入口摊平回平铺视图,server.ts 内的 ~700 处 `deps.x` 消费点原样保留。消费点迁移是后批的事——
74
74
  * 一步到位需要同批改 ~700 处 src + ~800 处 test 键位,与「先立形、后搬家」相比没有额外收益。
75
75
  */
76
- /** createHttpServer 的**必填八件**——引擎、部署配置、提交的身份与根会话(authorizer)、请求→TaskSpec 的映射、选路席、side-query 执行席、读口场景门、对端座的 desk。
77
- * 八者恒在场,故留在顶层(不进任何可选组):没有它们 server 根本起不来,包一层可选组只会把编译期
76
+ /** createHttpServer 的**必填九件**——引擎、部署配置、提交的身份与根会话(authorizer)、请求→TaskSpec 的映射、选路席、side-query 执行席、读口场景门、对端座的 desk、部署座的 mod 注册。
77
+ * 九者恒在场,故留在顶层(不进任何可选组):没有它们 server 根本起不来,包一层可选组只会把编译期
78
78
  * 错误推迟到运行期(本仓 E-HIGH-1 病族的成因就是「可选键从未接线、编译期无声」)。 */
79
79
  export interface ServiceCoreDeps {
80
80
  runner: Runner;
@@ -172,6 +172,14 @@ export interface ServiceCoreDeps {
172
172
  * 🔴 **必填**:没有 MCP / A2A 凭据的嵌入也给一只 `createPeerDesk()`(零 IO)—— 一个部署只有一张登记表,缺席不是「没有座」的另一种读法。
173
173
  */
174
174
  peerDesk: PeerDesk;
175
+ /**
176
+ * 部署座的 mod 注册(`RunnerDeps.mods`:这个部署每只 Runner 都带的同一份;起服第五段装配口 `assembleDeploymentMods` 交回,装配点把同一个值交给 Runner 与这里)。
177
+ * 本层只问它一件事:这条腿上有没有 prompt 屏(`prompt-screen.ts` 的 `promptScreenDeclared`,读注册**声明**的事件,连同任务座 `TaskSpec.mods`)——
178
+ * 有屏 ⇒ 受理座把目标落盘(run 行预览 · 续跑体 · 会话标题 · fleet 行名)推迟到引擎原样交付之后(读法全文 `run-acceptance.ts`「交付的是哪一份」)。
179
+ * 🔴 **必填**:缺席若读成「没有屏」,装了屏的部署会把屏前文本落进上面四处,而且谁也看不见 —— 机密轴上没有静默的那一侧。没有 mod 的嵌入显式传 `[]`;
180
+ * 与交给 Runner 的必须是同一个值(两处不同 = 嵌入方的装配错,本层读不出来)。
181
+ */
182
+ deploymentMods: NonNullable<RunnerDeps["mods"]>;
175
183
  }
176
184
  /** **durable 持久面**:每个键 present ⇔ 对应路由/能力位在场,absent ⇒ 501(诚实缺席),
177
185
  * 绝不静默降级。装配点 = main.ts 的 store backend 开箱段。 */
@@ -880,7 +888,7 @@ export interface ServiceDepGroups {
880
888
  deployment?: ServiceDeploymentDeps;
881
889
  knobs?: ServiceKnobDeps;
882
890
  }
883
- /** 平铺视图 = 必填八件 + 其余七组的全可选并集。**派生**自组接口,故与分组形永不漂。 */
891
+ /** 平铺视图 = 必填九件 + 其余七组的全可选并集。**派生**自组接口,故与分组形永不漂。 */
884
892
  export type FlatServiceDeps = ServiceCoreDeps & Partial<ServiceStoreDeps & ServiceCoordinatorDeps & ServiceSeamDeps & ServiceObservabilityDeps & ServiceGovernanceDeps & ServiceDeploymentDeps & ServiceKnobDeps>;
885
893
  /** createHttpServer 的入参:两形皆可(平铺=存量,分组=推荐)。同名键两形都给时,**顶层显式键赢**
886
894
  * (含显式 `undefined`)——一处装配点只该用一形,混用时以肉眼最近的那个为准。 */
@@ -66,6 +66,9 @@ export function createHttpServer(rawDeps) {
66
66
  if (typeof deps.authorize !== "function") {
67
67
  throw new Error("createHttpServer: the authorize seat is required — it is the only resolver of a submission's root session; pass `createAuthorizer(config, runner.sessions)` for a single-user embedding; refusing to start rather than run submissions on a root nobody attested");
68
68
  }
69
+ if (!Array.isArray(deps.deploymentMods)) {
70
+ throw new Error("createHttpServer: the deploymentMods seat is required — it is how the server learns whether a prompt screen runs on its legs (the same registrations the Runners carry as `mods`); pass `[]` for an embedding without mods; refusing to start rather than store objective text before the screen decides");
71
+ }
69
72
  {
70
73
  const retired = retiredServiceDepsRefusal(deps);
71
74
  if (retired !== undefined)
@@ -3,6 +3,9 @@ import type { Logger } from "../observability/logger.js";
3
3
  import type { Metrics } from "../observability/metrics.js";
4
4
  import { buildCheckpointCtx, type CheckpointCtxSealer, type SealedCheckpointCtx } from "./checkpoint-ctx.js";
5
5
  import { type RefusalBody } from "./refusal-body.js";
6
+ import type { CheckpointCtx, PreparedTaskSubmission } from "./route-ctx.js";
7
+ /** 这份续跑输入里体的目标是不是**不可展示**的那一份(`CheckpointCtx.promptScreened` 在场)。读续跑体目标的展示面只经这一只问;落盘的 JSON 逐位判形,不信型面。 */
8
+ export declare function objectiveWithheldIn(ctx: Pick<CheckpointCtx, "promptScreened">): boolean;
6
9
  /** 写不进的那一种可答复的结局(各腿把它交回自己的出口:同步 / durable 腿直接回,活流腿编码成终帧)。 */
7
10
  export interface SubmitCtxRefusal {
8
11
  readonly status: 413 | 409;
@@ -23,4 +26,13 @@ export declare function persistSubmitCtx(store: {
23
26
  readonly runStore: RunStore;
24
27
  readonly taskId: string;
25
28
  } | undefined, sessionId: string, fields: Parameters<typeof buildCheckpointCtx>[0]): Promise<SubmitCtxRefusal | undefined>;
29
+ /**
30
+ * 提交腿写续跑输入的入口(三个调用点同调这一只):体与标记按受理座提交时交出的那一份定(见文件头「体里的目标按哪一份写」),只写这一笔。
31
+ * 写不进的处置与答复 = {@link persistSubmitCtx}(本函数只定体、不另判)。
32
+ */
33
+ export declare function persistSubmissionCtx(store: {
34
+ putCtx(sessionId: string, ctx: SealedCheckpointCtx): Promise<void>;
35
+ }, deps: Parameters<typeof persistSubmitCtx>[1], claim: Parameters<typeof persistSubmitCtx>[2], prepared: Pick<PreparedTaskSubmission, "body" | "auth" | "verify" | "acceptance" | "bodyFromScreenedCtx"> & {
36
+ readonly spec: Pick<PreparedTaskSubmission["spec"], "sessionId" | "model">;
37
+ }): Promise<SubmitCtxRefusal | undefined>;
26
38
  //# sourceMappingURL=submit-ctx.d.ts.map
@@ -3,6 +3,17 @@ import { releaseClaimedRun } from "./claimed-run.js";
3
3
  import { buildCheckpointCtx, CheckpointCtxUnsealableError } from "./checkpoint-ctx.js";
4
4
  import { refusalBody } from "./refusal-body.js";
5
5
  import { limitFactsUnmeasured } from "../limit-refusal.js";
6
+ import { serviceVersion } from "../service-version.js";
7
+ import { recordFailOpen } from "../observability/fail-open.js";
8
+ import { DEFAULT_MODEL_REF } from "../model-select.js";
9
+ const WITHHELD_OBJECTIVE = "";
10
+ export function objectiveWithheldIn(ctx) {
11
+ return ctx.promptScreened === true;
12
+ }
13
+ function withheldBody(body, picked) {
14
+ const pin = typeof body.model !== "string" && typeof picked === "string" && picked !== DEFAULT_MODEL_REF ? { model: picked } : {};
15
+ return { ...body, objective: WITHHELD_OBJECTIVE, ...pin };
16
+ }
6
17
  function unsealableRefusal(e) {
7
18
  return {
8
19
  status: 409,
@@ -53,4 +64,16 @@ export async function persistSubmitCtx(store, deps, claim, sessionId, fields) {
53
64
  return rowTooLargeRefusal(tooLarge);
54
65
  }
55
66
  }
67
+ export async function persistSubmissionCtx(store, deps, claim, prepared) {
68
+ const sessionId = prepared.spec.sessionId;
69
+ const screened = prepared.acceptance.objectiveAtSubmit === undefined;
70
+ if (screened && prepared.verify !== undefined)
71
+ recordFailOpen("server.objective-delivery.verify-replay-copy", `session=${sessionId}`);
72
+ return persistSubmitCtx(store, deps, claim, sessionId, {
73
+ body: screened && prepared.verify === undefined ? withheldBody(prepared.body, prepared.spec.model) : prepared.body,
74
+ memoryScope: prepared.auth?.memoryScope,
75
+ ...(screened || prepared.bodyFromScreenedCtx === true ? { promptScreened: true } : {}),
76
+ writerVersion: serviceVersion(),
77
+ });
78
+ }
56
79
  //# sourceMappingURL=submit-ctx.js.map
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
  /**
@@ -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, leg?: (info: FileStorageCorruptReadInfo) => void): (info: FileStorageCorruptReadInfo) => void;
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] 的教训)。汇总的两个实数给了用户面(`leg` 腿 → `session.records_skipped` 帧),运维面逐条明细都在探针里。
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 与披露**同拍**的附加腿,语义同 {@link createCorruptReadSeat} 的 `leg`:**先于**记账交给它(记账故障不许吃掉用户面那一记),
37
- * 必须不抛。**收全部三级**(包括不计数的 `replay`)—— 腿要的恰是那条汇总。
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, leg) {
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,
@@ -21,7 +21,7 @@ export type FailOpenEntry = {
21
21
  export declare const FAIL_OPEN_TAGS: {
22
22
  readonly "server.approval-ask-journal.compaction-failed": {
23
23
  readonly cls: "F";
24
- readonly note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。";
24
+ readonly note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,与起服重放到删行记录时的那一次压实 —— 同一只 `compactOrRecord`;local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实(删行记录引起的压实失败,位 `removalRecordsOnDisk` 留着:下一次任何写、或下一次起服再试;起服那一次失败同样只留痕、不拒启)。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。";
25
25
  };
26
26
  readonly "server.approval-ask-journal.corrupt-record-skipped": {
27
27
  readonly cls: "F";
@@ -201,15 +201,23 @@ 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 起同 tag 另有两座同判据的臂(`SqlCheckpointStore.readParkedSkillCardFacts`:对行上可能带技能卡两位之一的行,整只快照读回的体坏、或体是对象但 core 的摘要读不动它 ⇒ 只丢**这一行**的两位〔`boundGrants` / `classifierNoRuling`〕,授予绑定那一臂〔`boundGrantDigest` / `boundGrantAbsence`〕读自子树、照在(S-1612),队列照常;`not-text` 同样原样抛)—— 计数非零的处置同上:去按 session 查那一行。";
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 另有一座:停驻行的**整行读**(`readStoredRow`;按快照摘要记忆,未命中才读)—— 运维队列行的判决 `rowVerdict` 与技能卡两位、7.145.0 起还有收件箱 / 任务视图 `listByScope` 的行投影,同经这一只读法、同一失败方向(行级隔离):整行解不出 ⇒ 判官对读回的原样值作答(恒 `damaged`),行照列、带判决;体是对象但 core 摘要读不动(`{}` / 缺 `state` 等手改行)⇒ 判官对这只对象作答;两形都只丢摘要派生的位(队列行的技能卡两位 / 收件箱行的摘要键,收件箱行退回列组事实),逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。修前收件箱对同一行整张拒(500 / 503)。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)";
205
+ };
206
+ readonly "server.approvals.queue-row-agent-unreadable": {
207
+ readonly cls: "F";
208
+ readonly note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `session-agent.ts` 的 `readSessionAgent` = 会话店的 `placementOf` 一读)。某一只会话那一读抛(店瞬断 / 超时 / local 后端的会话存档行头读不出)⇒ **这只会话的行**缺 `agent` 键,列表其余照常。放行的最坏后果 = 这一行这一次没有委派归属线索:壳的归属判官认不到它(行照列、人从队列照样决得了 —— 与本键存在之前同形);`agent` 不是授权事实(队列行本就只列调用方 scope 的卡,决断口另有属主门)。不放行的代价是一只读不出的会话打掉整张待批列表(订阅流上每一拍都是读失败)。故 F 类;必须留痕,否则「这一次没读成」与「这不是一只 placed 委派子代」在 wire 上同形。detail = 会话 id 与经出口座的错误句。计数按次(订阅流每一拍各计一次)。";
205
209
  };
206
210
  readonly "server.approvals.durable-row-checkpoint-id-missing": {
207
211
  readonly cls: "F";
208
212
  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
213
  };
210
- readonly "server.peer-inbound.notice-coordinates-unreadable": {
214
+ readonly "server.peer-inbound.queue-box-unknown": {
215
+ readonly cls: "F";
216
+ 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`)。";
217
+ };
218
+ readonly "server.session-notify.active-run-read-failed": {
211
219
  readonly cls: "F";
212
- readonly note: "S-1370(`peer-inbound-face.ts` 的 `observe`,部署级通告转发席喂它):core 的 `peer.inbound_disposition{disposition:\"held\"}` / `peer.held_settled{heldCount:0}` 通告的 `detail` 读不出坐标(`sessionId` 不是串或不合 core 的会话地址文法 / `box` 既不是那只会话的箱也不是 principal 收件箱)⇒ 这一条不进(或不出)收信方决断面的坐标表。按构造不可达:core 的两只铸点恒给这两位。放行(忽略这一条)的最坏后果:进表那一形 = 那张被扣的信不出现在 `GET /v1/approvals` 的 `pending[]` 上 —— 它仍在 core 的队列里,按 `dialogExpiry` 带 `expired` 回执结清(core 的安全默认),也仍可经 core 自己的通告面看到;出表那一形 = 坐标表多留一行(读时多查一次空队列)。不放行(抛)会把异常回抛进引擎的通告投递(转发席的隔离契约禁止)。故 F 类;计数非零 = core 改了这两条通告的 detail 形,对 core 的 d.ts 重核坐标读法。";
220
+ 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
221
  };
214
222
  readonly "server.approvals.queue-row-gate-kind-missing": {
215
223
  readonly cls: "F";
@@ -325,7 +333,7 @@ export declare const FAIL_OPEN_TAGS: {
325
333
  };
326
334
  readonly "server.park.toolcallid-read-failed": {
327
335
  readonly cls: "F";
328
- readonly note: "[4913]:durable park 投影腿在 strip 之前拿结果里的 checkpointToken 换 `pendingAction.toolCallId`(cs.get 一次读),那次读**抛了**(store 抖动 / 滚动升级期 checkpoint 格式 version guard / 行已被并发消费)⇒ 本次 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 上同形,不计数则「投影为什么总缺」在遥测里永不显形。";
336
+ 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
337
  };
330
338
  readonly "server.exec-lane.ssh-host-key-unverified": {
331
339
  readonly cls: "P-DEBT";
@@ -337,7 +345,7 @@ export declare const FAIL_OPEN_TAGS: {
337
345
  };
338
346
  readonly "server.approvals.stale-echoed-token-unreadable": {
339
347
  readonly cls: "F";
340
- readonly note: "S-02 codex R1-[medium](验真后修):decide 的 409 `approval_stale` 臂对**调用方回显的旧 token** 做归属判定(`cs.get(binding.checkpointToken)`),那次读**抛了**(store 抖动 / 版本守卫 / 行恰被清理)。修前这里是静默 `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 折叠两个判定的输入,长期抖动必须在遥测显形。";
348
+ 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
349
  };
342
350
  readonly "server.resume.reopen-confirm-unreadable": {
343
351
  readonly cls: "F";
@@ -345,7 +353,7 @@ export declare const FAIL_OPEN_TAGS: {
345
353
  };
346
354
  readonly "server.approvals.stale-current-pending-unreadable": {
347
355
  readonly cls: "F";
348
- readonly note: "S-02 件2([5522]④→[5525]):409 `approval_stale` 拒体铸 additive 指路键 `currentPending`(本会话当前 pending 的 D-1 坐标,壳一跳重定位)时,当前 pending 行的 `cs.get(token)` 读**抛了**(store 抖动 / 滚动升级期 checkpoint 格式 version guard / 行恰被并发消费)⇒ 本次拒体**缺 `currentPending` 键**,409 本体与 `terminal` 判定照旧。放行的最坏后果 = 壳退回该键到货前的行为(重拉 GET /v1/approvals 自行重定位),纯指路/便利面,不参与任何门/CAS/resume 判定,故 F 类(同族先例:`server.park.toolcallid-read-failed`,同为 cs.get 投影读失败臂)。必须留痕:键缺席与「此刻确实没有 pending」在 wire 上同形,不计数则「指路为什么总缺」在遥测里永不显形。";
356
+ 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
357
  };
350
358
  readonly "server.file-history.retention-trim-failed": {
351
359
  readonly cls: "F";
@@ -369,7 +377,7 @@ export declare const FAIL_OPEN_TAGS: {
369
377
  };
370
378
  readonly "server.run-terminal.redact-threw": {
371
379
  readonly cls: "F";
372
- readonly note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。";
380
+ readonly note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位;块界上扫描窗前移的认证扫描抛 ⇒ 窗不动,只是没省,交出的字节一个不变):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。";
373
381
  };
374
382
  readonly "server.run-terminal.provider-echo-shaped": {
375
383
  readonly cls: "F";
@@ -435,6 +443,14 @@ export declare const FAIL_OPEN_TAGS: {
435
443
  readonly cls: "F";
436
444
  readonly note: "S-1874 / S-2137(`routes/approvals-assistant.ts` 的 `GET /v1/assistant/inbox`):每行的 `objective` = 这道门所属 run 的目标预览 —— 按 run id 直读那一行的 `objectivePreview` 列(写入时已脱敏 + 截断;`GET /v1/assistant/tasks` 读同一列)。门 → run 是按键直读:门所在会话的认领持有者 / 最近一条腿,委派子代的门读派它的那条 run(停驻子代行上的 `parentTaskId`,行经判别器 `findParkedAgentForCheckpoint` 取)。某一行这几次直读失败(店抖动 / 那一行 run 的 `result` 格读不出 —— SQL `getRun` 对坏格刻意抛)⇒ **这一行**的 `objective` 落 `null`,列表其余照常。放行的最坏后果 = inbox 上这一张卡这一次不显示它属于哪个任务(纯展示位;不参与任何决裁、续跑或门判)。不放行的代价是一行 run 读不出就打掉整个用户的待批列表(人看不到要批的卡)。故 F 类;必须留痕,否则「这一次没读成」与「这道门本来就没有 run」同形。detail = 那一行的会话 id 与错误句。前身(7.97.0–7.135.x):同一格读停驻上下文、坏体落 null 的那一只 tag(objective-ctx-corrupt),随 S-1874 退役(inbox 不再读续跑上下文)。";
437
445
  };
446
+ readonly "server.objective-delivery.face-fill-failed": {
447
+ readonly cls: "F";
448
+ readonly note: "`run-acceptance.ts` 的补写口(腿上装着 prompt 屏时,本服务存 / 转目标的面在提交时不写,引擎交付之后以交付的那一份补写):某一张面的补写抛错 —— `run-preview`(run 行预览列的写一次补写,店抖动 / 行已被收割删除)、`fleet-name`(进程内 fleet 行的名;不会抛,列在闭集里是为了词全)。放行的最坏后果 = 那张面保持提交时的**空**:预览缺席(列表 / 收件箱 / fleet 行不显示这条 run 是什么任务)—— 少写,不是写错:不会写出屏前原文,不参与任何门判、续跑决裁或模型输入。不放行的代价是一次展示面的写失败打断这条正在跑的 run。故 F 类;必须留痕,否则「补写失败」与「屏改写过、本来就没有可写的那一份」同形。detail = `face=<面> err=<错误句,经运维日志出口座>`。";
449
+ };
450
+ readonly "server.objective-delivery.verify-replay-copy": {
451
+ readonly cls: "P-DEBT";
452
+ readonly note: "`submit-ctx.ts` 的 `persistSubmissionCtx`:腿上装着 prompt 屏、且这次提交是 verify 形(只回结果的腿:宿主看不到受理帧,分不出屏改没改,也看不到有没有交付)⇒ 续跑输入照旧存请求原文的目标,不按「交付的那一份」写。理由:verify 形停驻后的续跑把续跑输入里的目标交给引擎的验证器(`resumeWithVerification` 的 `objective`),留空 = 验证器拿不到任务陈述;引擎自己的首跑验证器同样读请求原文。方向明知不对(屏丢弃 / 抛错 / 改写过的目标原文仍在 checkpoint ctx 里,直到这一行被收割),待引擎把交付的那一份交给宿主(含只回结果的腿)、验证器改读交付的目标之后修掉。每一次这样的提交记一次;计数非零 = 这台部署有「prompt 屏 + verify 形」的提交,它们的续跑输入里有屏前原文。detail = `session=<会话 id>`。";
453
+ };
438
454
  readonly "server.run-store.corrupt-record-skipped": {
439
455
  readonly cls: "F";
440
456
  readonly note: "S-582(`plugins/file-run-store.ts`,local 车道的 File 形 run 店;四个盘面同一只座):盘上一条记录读不出形 —— 一行 `42` / 缺本店必填键的对象 / 中间的半截 JSON(撕尾不走本 tag,那是崩溃的正常落盘形)⇒ 跳过它继续。前三个盘面各自的最坏后果:`run.json` 坏 ⇒ 那条 run 读成**缺席**(`GET /v1/runs/:id` 404,listRuns 少一行;它若占着 claim,EEXIST 路按「行不在」判残骸接管);`events.jsonl` 一行坏 ⇒ 回放少一个事件(其余照读、按 seq 去重不变);claim 记录坏 ⇒ 走既有的撕裂 claim 路(有非终局行就收编,否则隔离出 activeDir)。第四个盘面 `run-blobs/<会话>.jsonl`(`wiring_manifest` 行容器段的块账本,`plugins/wiring-section-codec.ts`)同一只座、两个检测点:① 重放时一条块记录形不合(`digest` 不是串 / `body` 不是容器)⇒ 跳过;② 读口(`getEvents`)装回时清单行引用的块不在本会话账本里(块缺:账本行被删 / 被跳过、断电丢尾、删会话时 run 目录删不掉留下的僵尸 run)⇒ 那一帧这一次不交出(永不交出缺段的清单),每个 `(taskId, seq)` 每进程计一次,`maxSeq` / `retainedFrom` 照旧按存位;明细 `kind=section-ref taskId= seq= sections=<段:摘要,…>`。块账本整份读不出(权限 / 挂载)不走本 tag,与 `events.jsonl` 读不出同一条路(strict 拒启,否则原样抛)。都是**可用性**损失,不开任何门 ⇒ F。修前三面全零披露(店自己的 `typeof … continue` 与 core 的静默跳过);计数让「这台机器的 run 账在腐」在遥测里显形。⚠️ `RUN_STORE_STRICT_HYDRATE=on` 的射程是「文件读不出」,不含「文件里有坏行」—— strict 档下坏行照走本 tag(未改 strict 语义,见普查表第 96 行)。";
@@ -481,7 +497,7 @@ export declare const FAIL_OPEN_TAGS: {
481
497
  };
482
498
  readonly "server.session-repo.corrupt-record-skipped": {
483
499
  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 面披露(打开自己存档时的 `engine_notice` 码 `session.records_skipped`,与本 tag 无关、不动)⇒ F。**计数单位 = 一条被跳过的记录 = 一次命中**(`replay` 级是同一批记录的汇总,不计,S-616 同教训);**每命中一行探针**(`SEMA_FAILOPEN_PROBE`)带 `path` / `sessionId` / `line` / `form` / `reason` 逐条明细 —— 运维要看「哪份存档的哪一行坏了」读探针,不读本条 warn:本条是每进程每 tag 一次的告警(`detail` 是首条明细,不是全部)。修前:每命中一行 warn,一份 113 行坏记录的存档做一次列表 + 一次查看打出 342 行,存档没修好每读再发。";
500
+ 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
501
  };
486
502
  readonly "server.workflow-run.corrupt-record-skipped": {
487
503
  readonly cls: "F";
@@ -595,7 +611,7 @@ export declare const FAIL_OPEN_TAGS: {
595
611
  };
596
612
  readonly "server.remote-write.stage-seal-fallback": {
597
613
  readonly cls: "F";
598
- readonly note: "远端五条车道的写(`plugins/remote-shell.ts` 的暂存编排):准备脚本把刚建的私有暂存目录收成 0700 并读回核实(`chmod 700` 退出 0 ∧ `stat` 读回的模式低三位恰是 700 ∧ 属主 = 本身份),任一步不成 —— `chmod` 被文件系统 / 内核拒;退出 0 却没生效(不认权限位的文件系统);父目录带缺省 ACL 而掩码收不下来;目标机上没有 `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 掩码收不下来 / 缺 `stat`),写在走非原子的退路,去看那个目录。detail = `<目标路径>: <准备脚本写的原因句>`。";
614
+ 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
615
  };
600
616
  readonly "server.park.held-card-void-failed": {
601
617
  readonly cls: "F";
@@ -3,7 +3,7 @@ import { createLogger } from "./logger.js";
3
3
  export const FAIL_OPEN_TAGS = {
4
4
  "server.approval-ask-journal.compaction-failed": {
5
5
  cls: "F",
6
- note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。",
6
+ note: "S-384(`plugins/approval-ask-store-file.ts` 的 `write()` 尾巴,与起服重放到删行记录时的那一次压实 —— 同一只 `compactOrRecord`;local 车道的 File 形 ask 账):账本**压实**(整本重写成行快照)失败 —— 盘满 / 只读挂载 / `.tmp` 不可写。压实是**纯管家动作**,走到它的时候这一次写**已经 append+fsync 落盘、也已经翻进内存** ⇒ 把它的 I/O 错误抛给调用方 = 把一次已生效的人类批准报成失败(客户端重试会拿到 `ask_not_pending`),正是本店存在的理由被反过来用。所以吞 + 留痕:账本继续长(core 的 `AppendLog` 在 `closeForSwap` 之后惰性重开,一次瞬时错误不会把它变成砖),下一次写再试压实(删行记录引起的压实失败,位 `removalRecordsOnDisk` 留着:下一次任何写、或下一次起服再试;起服那一次失败同样只留痕、不拒启)。放行的最坏后果 = 账本不再收缩(盘占用按写入量线性增长),**语义零影响**(行与转移一个不差)。计数非零 = 这台机器的数据根写不动了,运维要去看盘。",
7
7
  },
8
8
  "server.approval-ask-journal.corrupt-record-skipped": {
9
9
  cls: "F",
@@ -183,15 +183,23 @@ 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 起同 tag 另有两座同判据的臂(`SqlCheckpointStore.readParkedSkillCardFacts`:对行上可能带技能卡两位之一的行,整只快照读回的体坏、或体是对象但 core 的摘要读不动它 ⇒ 只丢**这一行**的两位〔`boundGrants` / `classifierNoRuling`〕,授予绑定那一臂〔`boundGrantDigest` / `boundGrantAbsence`〕读自子树、照在(S-1612),队列照常;`not-text` 同样原样抛)—— 计数非零的处置同上:去按 session 查那一行。",
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 另有一座:停驻行的**整行读**(`readStoredRow`;按快照摘要记忆,未命中才读)—— 运维队列行的判决 `rowVerdict` 与技能卡两位、7.145.0 起还有收件箱 / 任务视图 `listByScope` 的行投影,同经这一只读法、同一失败方向(行级隔离):整行解不出 ⇒ 判官对读回的原样值作答(恒 `damaged`),行照列、带判决;体是对象但 core 摘要读不动(`{}` / 缺 `state` 等手改行)⇒ 判官对这只对象作答;两形都只丢摘要派生的位(队列行的技能卡两位 / 收件箱行的摘要键,收件箱行退回列组事实),逐次计、不进记忆,一行坏体在子树与整行两读上各计一次。修前收件箱对同一行整张拒(500 / 503)。 (`member=gate` 那第二座随 core 7.55.0 #1468 P1 阶段二退役:队列行的卡与到期分法改读 `approval_card` / `gate_kind` 两列 —— 写口与 M29 回填同一只派生落下的格 —— 本读面不再读 blob 的 `gate` 子树。)(S-2076 的 `readParkedSkillCardFacts` 两座已由上面那次 `projectStoredRow` 整行读取代,树上零命中。)",
187
+ },
188
+ "server.approvals.queue-row-agent-unreadable": {
189
+ cls: "F",
190
+ note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `session-agent.ts` 的 `readSessionAgent` = 会话店的 `placementOf` 一读)。某一只会话那一读抛(店瞬断 / 超时 / local 后端的会话存档行头读不出)⇒ **这只会话的行**缺 `agent` 键,列表其余照常。放行的最坏后果 = 这一行这一次没有委派归属线索:壳的归属判官认不到它(行照列、人从队列照样决得了 —— 与本键存在之前同形);`agent` 不是授权事实(队列行本就只列调用方 scope 的卡,决断口另有属主门)。不放行的代价是一只读不出的会话打掉整张待批列表(订阅流上每一拍都是读失败)。故 F 类;必须留痕,否则「这一次没读成」与「这不是一只 placed 委派子代」在 wire 上同形。detail = 会话 id 与经出口座的错误句。计数按次(订阅流每一拍各计一次)。",
187
191
  },
188
192
  "server.approvals.durable-row-checkpoint-id-missing": {
189
193
  cls: "F",
190
194
  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
195
  },
192
- "server.peer-inbound.notice-coordinates-unreadable": {
196
+ "server.peer-inbound.queue-box-unknown": {
197
+ cls: "F",
198
+ 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`)。",
199
+ },
200
+ "server.session-notify.active-run-read-failed": {
193
201
  cls: "F",
194
- note: "S-1370(`peer-inbound-face.ts` 的 `observe`,部署级通告转发席喂它):core 的 `peer.inbound_disposition{disposition:\"held\"}` / `peer.held_settled{heldCount:0}` 通告的 `detail` 读不出坐标(`sessionId` 不是串或不合 core 的会话地址文法 / `box` 既不是那只会话的箱也不是 principal 收件箱)⇒ 这一条不进(或不出)收信方决断面的坐标表。按构造不可达:core 的两只铸点恒给这两位。放行(忽略这一条)的最坏后果:进表那一形 = 那张被扣的信不出现在 `GET /v1/approvals` 的 `pending[]` 上 —— 它仍在 core 的队列里,按 `dialogExpiry` 带 `expired` 回执结清(core 的安全默认),也仍可经 core 自己的通告面看到;出表那一形 = 坐标表多留一行(读时多查一次空队列)。不放行(抛)会把异常回抛进引擎的通告投递(转发席的隔离契约禁止)。故 F 类;计数非零 = core 改了这两条通告的 detail 形,对 core 的 d.ts 重核坐标读法。",
202
+ 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
203
  },
196
204
  "server.approvals.queue-row-gate-kind-missing": {
197
205
  cls: "F",
@@ -307,7 +315,7 @@ export const FAIL_OPEN_TAGS = {
307
315
  },
308
316
  "server.park.toolcallid-read-failed": {
309
317
  cls: "F",
310
- note: "[4913]:durable park 投影腿在 strip 之前拿结果里的 checkpointToken 换 `pendingAction.toolCallId`(cs.get 一次读),那次读**抛了**(store 抖动 / 滚动升级期 checkpoint 格式 version guard / 行已被并发消费)⇒ 本次 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 上同形,不计数则「投影为什么总缺」在遥测里永不显形。",
318
+ 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
319
  },
312
320
  "server.exec-lane.ssh-host-key-unverified": {
313
321
  cls: "P-DEBT",
@@ -319,7 +327,7 @@ export const FAIL_OPEN_TAGS = {
319
327
  },
320
328
  "server.approvals.stale-echoed-token-unreadable": {
321
329
  cls: "F",
322
- note: "S-02 codex R1-[medium](验真后修):decide 的 409 `approval_stale` 臂对**调用方回显的旧 token** 做归属判定(`cs.get(binding.checkpointToken)`),那次读**抛了**(store 抖动 / 版本守卫 / 行恰被清理)。修前这里是静默 `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 折叠两个判定的输入,长期抖动必须在遥测显形。",
330
+ 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
331
  },
324
332
  "server.resume.reopen-confirm-unreadable": {
325
333
  cls: "F",
@@ -327,7 +335,7 @@ export const FAIL_OPEN_TAGS = {
327
335
  },
328
336
  "server.approvals.stale-current-pending-unreadable": {
329
337
  cls: "F",
330
- note: "S-02 件2([5522]④→[5525]):409 `approval_stale` 拒体铸 additive 指路键 `currentPending`(本会话当前 pending 的 D-1 坐标,壳一跳重定位)时,当前 pending 行的 `cs.get(token)` 读**抛了**(store 抖动 / 滚动升级期 checkpoint 格式 version guard / 行恰被并发消费)⇒ 本次拒体**缺 `currentPending` 键**,409 本体与 `terminal` 判定照旧。放行的最坏后果 = 壳退回该键到货前的行为(重拉 GET /v1/approvals 自行重定位),纯指路/便利面,不参与任何门/CAS/resume 判定,故 F 类(同族先例:`server.park.toolcallid-read-failed`,同为 cs.get 投影读失败臂)。必须留痕:键缺席与「此刻确实没有 pending」在 wire 上同形,不计数则「指路为什么总缺」在遥测里永不显形。",
338
+ 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
339
  },
332
340
  "server.file-history.retention-trim-failed": {
333
341
  cls: "F",
@@ -351,7 +359,7 @@ export const FAIL_OPEN_TAGS = {
351
359
  },
352
360
  "server.run-terminal.redact-threw": {
353
361
  cls: "F",
354
- note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。",
362
+ note: "三个发射座(errorMessage 终态文案 / 诊断文本 diag / 工件 artifact,probe 前缀判别;普查 56 行;补丁头 patch-head 那座随 7.83.0 / S-113 的 redactPatchHead 一并退役)+ 出口座(S-485 / RH-1:`trace/exit-seat.ts` 的 `seatText`,probe 前缀 `seat=<座表行>`;trace 帧自由文本位上抛 ⇒ 这一位换同一枚占位、投影不抛)+ 活面放行窗(`trace/model-segment.ts` 的 `createLiveModelText`,probe 前缀 `live-hold`:逐块放行口抛 ⇒ 这一拍不放、字节留在窗里;段末整段读法抛 ⇒ 余下的字节整段换同一枚占位;块界上扫描窗前移的认证扫描抛 ⇒ 窗不动,只是没省,交出的字节一个不变):S-105 最终轮 [medium]:终态 errorMessage/blockedReason/remoteEnvFailures[].message 脱敏抛出(RangeError:关键字/前缀臂那一形由 S-219 的 atLeast 铸点闭掉;JSON 秘密字段臂的转义对循环与 PEM 栅栏臂的标签交替循环由 S-265 换成手写线性扫描器闭掉 —— 已知形全部闭掉,本臂留作结构性兜底,计数恒零是证据、不归零即新形)⇒ 落固定占位 «redacted:oversized»——绝不落原文(安全轴 fail-closed),也绝不阻断终态翻转与 claim 释放(可用性)。方向刻意:一条超大错误体不得把 run 卡在 running。",
355
363
  },
356
364
  "server.run-terminal.provider-echo-shaped": {
357
365
  cls: "F",
@@ -393,6 +401,14 @@ export const FAIL_OPEN_TAGS = {
393
401
  cls: "F",
394
402
  note: "S-1874 / S-2137(`routes/approvals-assistant.ts` 的 `GET /v1/assistant/inbox`):每行的 `objective` = 这道门所属 run 的目标预览 —— 按 run id 直读那一行的 `objectivePreview` 列(写入时已脱敏 + 截断;`GET /v1/assistant/tasks` 读同一列)。门 → run 是按键直读:门所在会话的认领持有者 / 最近一条腿,委派子代的门读派它的那条 run(停驻子代行上的 `parentTaskId`,行经判别器 `findParkedAgentForCheckpoint` 取)。某一行这几次直读失败(店抖动 / 那一行 run 的 `result` 格读不出 —— SQL `getRun` 对坏格刻意抛)⇒ **这一行**的 `objective` 落 `null`,列表其余照常。放行的最坏后果 = inbox 上这一张卡这一次不显示它属于哪个任务(纯展示位;不参与任何决裁、续跑或门判)。不放行的代价是一行 run 读不出就打掉整个用户的待批列表(人看不到要批的卡)。故 F 类;必须留痕,否则「这一次没读成」与「这道门本来就没有 run」同形。detail = 那一行的会话 id 与错误句。前身(7.97.0–7.135.x):同一格读停驻上下文、坏体落 null 的那一只 tag(objective-ctx-corrupt),随 S-1874 退役(inbox 不再读续跑上下文)。",
395
403
  },
404
+ "server.objective-delivery.face-fill-failed": {
405
+ cls: "F",
406
+ note: "`run-acceptance.ts` 的补写口(腿上装着 prompt 屏时,本服务存 / 转目标的面在提交时不写,引擎交付之后以交付的那一份补写):某一张面的补写抛错 —— `run-preview`(run 行预览列的写一次补写,店抖动 / 行已被收割删除)、`fleet-name`(进程内 fleet 行的名;不会抛,列在闭集里是为了词全)。放行的最坏后果 = 那张面保持提交时的**空**:预览缺席(列表 / 收件箱 / fleet 行不显示这条 run 是什么任务)—— 少写,不是写错:不会写出屏前原文,不参与任何门判、续跑决裁或模型输入。不放行的代价是一次展示面的写失败打断这条正在跑的 run。故 F 类;必须留痕,否则「补写失败」与「屏改写过、本来就没有可写的那一份」同形。detail = `face=<面> err=<错误句,经运维日志出口座>`。",
407
+ },
408
+ "server.objective-delivery.verify-replay-copy": {
409
+ cls: "P-DEBT",
410
+ note: "`submit-ctx.ts` 的 `persistSubmissionCtx`:腿上装着 prompt 屏、且这次提交是 verify 形(只回结果的腿:宿主看不到受理帧,分不出屏改没改,也看不到有没有交付)⇒ 续跑输入照旧存请求原文的目标,不按「交付的那一份」写。理由:verify 形停驻后的续跑把续跑输入里的目标交给引擎的验证器(`resumeWithVerification` 的 `objective`),留空 = 验证器拿不到任务陈述;引擎自己的首跑验证器同样读请求原文。方向明知不对(屏丢弃 / 抛错 / 改写过的目标原文仍在 checkpoint ctx 里,直到这一行被收割),待引擎把交付的那一份交给宿主(含只回结果的腿)、验证器改读交付的目标之后修掉。每一次这样的提交记一次;计数非零 = 这台部署有「prompt 屏 + verify 形」的提交,它们的续跑输入里有屏前原文。detail = `session=<会话 id>`。",
411
+ },
396
412
  "server.run-store.corrupt-record-skipped": {
397
413
  cls: "F",
398
414
  note: "S-582(`plugins/file-run-store.ts`,local 车道的 File 形 run 店;四个盘面同一只座):盘上一条记录读不出形 —— 一行 `42` / 缺本店必填键的对象 / 中间的半截 JSON(撕尾不走本 tag,那是崩溃的正常落盘形)⇒ 跳过它继续。前三个盘面各自的最坏后果:`run.json` 坏 ⇒ 那条 run 读成**缺席**(`GET /v1/runs/:id` 404,listRuns 少一行;它若占着 claim,EEXIST 路按「行不在」判残骸接管);`events.jsonl` 一行坏 ⇒ 回放少一个事件(其余照读、按 seq 去重不变);claim 记录坏 ⇒ 走既有的撕裂 claim 路(有非终局行就收编,否则隔离出 activeDir)。第四个盘面 `run-blobs/<会话>.jsonl`(`wiring_manifest` 行容器段的块账本,`plugins/wiring-section-codec.ts`)同一只座、两个检测点:① 重放时一条块记录形不合(`digest` 不是串 / `body` 不是容器)⇒ 跳过;② 读口(`getEvents`)装回时清单行引用的块不在本会话账本里(块缺:账本行被删 / 被跳过、断电丢尾、删会话时 run 目录删不掉留下的僵尸 run)⇒ 那一帧这一次不交出(永不交出缺段的清单),每个 `(taskId, seq)` 每进程计一次,`maxSeq` / `retainedFrom` 照旧按存位;明细 `kind=section-ref taskId= seq= sections=<段:摘要,…>`。块账本整份读不出(权限 / 挂载)不走本 tag,与 `events.jsonl` 读不出同一条路(strict 拒启,否则原样抛)。都是**可用性**损失,不开任何门 ⇒ F。修前三面全零披露(店自己的 `typeof … continue` 与 core 的静默跳过);计数让「这台机器的 run 账在腐」在遥测里显形。⚠️ `RUN_STORE_STRICT_HYDRATE=on` 的射程是「文件读不出」,不含「文件里有坏行」—— strict 档下坏行照走本 tag(未改 strict 语义,见普查表第 96 行)。",
@@ -439,7 +455,7 @@ export const FAIL_OPEN_TAGS = {
439
455
  },
440
456
  "server.session-repo.corrupt-record-skipped": {
441
457
  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 面披露(打开自己存档时的 `engine_notice` 码 `session.records_skipped`,与本 tag 无关、不动)⇒ F。**计数单位 = 一条被跳过的记录 = 一次命中**(`replay` 级是同一批记录的汇总,不计,S-616 同教训);**每命中一行探针**(`SEMA_FAILOPEN_PROBE`)带 `path` / `sessionId` / `line` / `form` / `reason` 逐条明细 —— 运维要看「哪份存档的哪一行坏了」读探针,不读本条 warn:本条是每进程每 tag 一次的告警(`detail` 是首条明细,不是全部)。修前:每命中一行 warn,一份 113 行坏记录的存档做一次列表 + 一次查看打出 342 行,存档没修好每读再发。",
458
+ 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
459
  },
444
460
  "server.workflow-run.corrupt-record-skipped": {
445
461
  cls: "F",
@@ -553,7 +569,7 @@ export const FAIL_OPEN_TAGS = {
553
569
  },
554
570
  "server.remote-write.stage-seal-fallback": {
555
571
  cls: "F",
556
- note: "远端五条车道的写(`plugins/remote-shell.ts` 的暂存编排):准备脚本把刚建的私有暂存目录收成 0700 并读回核实(`chmod 700` 退出 0 ∧ `stat` 读回的模式低三位恰是 700 ∧ 属主 = 本身份),任一步不成 —— `chmod` 被文件系统 / 内核拒;退出 0 却没生效(不认权限位的文件系统);父目录带缺省 ACL 而掩码收不下来;目标机上没有 `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 掩码收不下来 / 缺 `stat`),写在走非原子的退路,去看那个目录。detail = `<目标路径>: <准备脚本写的原因句>`。",
572
+ 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
573
  },
558
574
  "server.park.held-card-void-failed": {
559
575
  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)}`);