@sema-agent/server 7.116.1 → 7.118.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 +195 -0
- package/USAGE.md +65 -41
- package/dist/approval-card.d.ts +82 -18
- package/dist/approval-card.js +46 -4
- package/dist/approval.d.ts +4 -12
- package/dist/approval.js +4 -26
- package/dist/boot/budget-tracing.js +2 -3
- package/dist/boot/config-center.d.ts +2 -2
- package/dist/boot/config-center.js +5 -7
- package/dist/boot/parked-revive-gate.d.ts +1 -7
- package/dist/boot/parked-revive-gate.js +2 -12
- package/dist/boot/resolve-spec.js +18 -16
- package/dist/boot/runner-deps.d.ts +5 -3
- package/dist/boot/runner-deps.js +6 -4
- package/dist/boot/stage-07-capability-layer.js +2 -2
- package/dist/brain.d.ts +17 -8
- package/dist/brain.js +10 -7
- package/dist/capabilities/hands-lane.d.ts +25 -0
- package/dist/capabilities/hands-lane.js +1 -1
- package/dist/capabilities/mcp-probe.d.ts +2 -2
- package/dist/config-catalog.js +3 -2
- package/dist/config-center/apply-effective.d.ts +6 -16
- package/dist/config-center/apply-effective.js +0 -6
- package/dist/config-center/facade.d.ts +1 -1
- package/dist/config-center/facade.js +1 -1
- package/dist/config-center/restart-signal.d.ts +1 -1
- package/dist/config-types.d.ts +12 -16
- package/dist/config.d.ts +32 -29
- package/dist/config.js +20 -27
- package/dist/deployment-governance.d.ts +13 -19
- package/dist/deployment-governance.js +7 -14
- package/dist/governance-overrides.d.ts +20 -0
- package/dist/governance-overrides.js +8 -0
- package/dist/host-decision.d.ts +83 -25
- package/dist/host-decision.js +31 -1
- package/dist/http/admission.js +13 -7
- package/dist/http/approval-sweeps.js +16 -13
- package/dist/http/checkpoint-ctx.d.ts +83 -24
- package/dist/http/checkpoint-ctx.js +68 -8
- package/dist/http/mcp-dial-deadline.d.ts +35 -0
- package/dist/http/mcp-dial-deadline.js +21 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +11 -5
- package/dist/http/memory-compliance-failure-reply.js +17 -8
- package/dist/http/memory-store-refusal-reply.d.ts +14 -11
- package/dist/http/memory-store-refusal-reply.js +16 -5
- package/dist/http/resume-legs.js +18 -18
- package/dist/http/retired-skill-manifest.d.ts +1 -1
- package/dist/http/route-ctx.d.ts +3 -3
- package/dist/http/routes/approvals-assistant.js +21 -24
- package/dist/http/routes/capabilities.js +5 -3
- package/dist/http/routes/mcp-reconnect.d.ts +17 -0
- package/dist/http/routes/mcp-reconnect.js +6 -1
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/runs.js +53 -33
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +3 -6
- package/dist/http/routes/workflows.js +2 -0
- package/dist/http/wire-types.d.ts +6 -1
- package/dist/memory-store-refusal.d.ts +42 -17
- package/dist/memory-store-refusal.js +25 -6
- package/dist/model-select.d.ts +16 -5
- package/dist/model-select.js +7 -3
- package/dist/model-unreachable-notice.d.ts +1 -1
- package/dist/namespaced-rule-name.d.ts +45 -39
- package/dist/namespaced-rule-name.js +36 -22
- package/dist/observability/corrupt-read-seat.d.ts +4 -0
- package/dist/observability/corrupt-read-seat.js +1 -0
- package/dist/observability/fail-open.d.ts +15 -3
- package/dist/observability/fail-open.js +15 -3
- package/dist/observability/permission-rule-events.d.ts +3 -0
- package/dist/observability/permission-rule-events.js +4 -0
- package/dist/observability/run-terminal.js +21 -1
- package/dist/operator-ask.d.ts +4 -1
- package/dist/orchestration/workflow-agent-session-index.d.ts +82 -59
- package/dist/orchestration/workflow-agent-session-index.js +80 -14
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -0
- package/dist/orchestration/workflow-completion-inbox.js +39 -17
- package/dist/orchestration/workflow-notify-journal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.js +7 -2
- package/dist/outbound-dispatcher.d.ts +47 -20
- package/dist/outbound-dispatcher.js +198 -23
- package/dist/parked-decide.d.ts +43 -48
- package/dist/parked-decide.js +54 -16
- package/dist/permission-rule-list.d.ts +20 -31
- package/dist/permission-rule-vocab.d.ts +4 -3
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plugins/approval-ask-store-sql.d.ts +17 -20
- package/dist/plugins/approval-ask-store-sql.js +0 -3
- package/dist/plugins/one-time-migrations.d.ts +25 -0
- package/dist/plugins/one-time-migrations.js +192 -6
- package/dist/plugins/pg-pool.js +1 -1
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/web-search.d.ts +20 -1
- package/dist/plugins/web-search.js +39 -10
- package/dist/plugins/workflow-run-store-sql.d.ts +7 -6
- package/dist/plugins/workflow-run-store-sql.js +5 -7
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +1 -1
- package/dist/router/route-orchestration.d.ts +2 -23
- package/dist/rule-entry-list.d.ts +88 -0
- package/dist/rule-entry-list.js +102 -0
- package/dist/rules-consent.js +3 -0
- package/dist/run-local.d.ts +4 -2
- package/dist/run-local.js +4 -3
- package/dist/runs.d.ts +1 -1
- package/dist/runs.js +1 -0
- package/dist/runtime-governance.d.ts +5 -21
- package/dist/runtime-governance.js +4 -8
- package/dist/session-policy-wire.d.ts +13 -12
- package/dist/session-policy-wire.js +11 -6
- package/dist/spec-fields.d.ts +13 -24
- package/dist/spec-fields.js +13 -17
- package/dist/standing-answer-grant.d.ts +14 -2
- package/dist/standing-answer-grant.js +8 -1
- package/dist/task-settings.d.ts +18 -18
- package/dist/task-settings.js +63 -32
- package/dist/tool-approval.d.ts +77 -145
- package/dist/tool-approval.js +80 -62
- package/dist/trace/core-keyset-guard.d.ts +6 -6
- package/dist/trace/engine-notice-wire.d.ts +4 -6
- package/dist/trace/engine-notice-wire.js +14 -1
- package/dist/trace/self-minted-wire.d.ts +16 -2
- package/dist/trace/self-minted-wire.js +7 -0
- package/dist/user-input-ledger.d.ts +24 -12
- package/dist/user-input-ledger.js +33 -14
- package/package.json +2 -2
- package/scripts/drain-check-local.mjs +103 -7
- package/scripts/drain-check.mysql.sql +59 -8
- package/scripts/drain-check.pg.sql +66 -10
|
@@ -4,6 +4,7 @@ import { isUuidV7, isUuidShape, legacyUnownedSessionOk } from "../../security.js
|
|
|
4
4
|
import { windowMessages, truncateMessageBlobs } from "../../audit.js";
|
|
5
5
|
import { redactSecrets } from "../../trace/redact.js";
|
|
6
6
|
import { recordFailOpen } from "../../observability/fail-open.js";
|
|
7
|
+
import { MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
|
|
7
8
|
import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.js";
|
|
8
9
|
import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS } from "../../task-settings.js";
|
|
9
10
|
import { readWritableSessionPermissionRules, describeSessionPermissionRulesProblem } from "../../session-policy-wire.js";
|
|
@@ -13,7 +14,6 @@ import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
|
13
14
|
import * as facts from "../../capability-facts.js";
|
|
14
15
|
import { rosterAgentId } from "./agents-roster.js";
|
|
15
16
|
const MCP_STATUS_TTL_MS = 5_000;
|
|
16
|
-
const MCP_MATERIALIZE_TIMEOUT_MS = 10_000;
|
|
17
17
|
const A2A_STATUS_TTL_MS = 5_000;
|
|
18
18
|
const A2A_MATERIALIZE_TIMEOUT_MS = 10_000;
|
|
19
19
|
const MEMORY_STATUS_TTL_MS = 5_000;
|
|
@@ -154,10 +154,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
154
154
|
mcpStatusCache.clear();
|
|
155
155
|
const panel = (async () => {
|
|
156
156
|
const matP = materializeMcpTools(specs, principal, undefined, undefined, undefined, deps.mcpRevocations);
|
|
157
|
-
|
|
158
|
-
const mat = await Promise.race([matP.catch(() => null), new Promise((r) => { timer = setTimeout(() => r(null), MCP_MATERIALIZE_TIMEOUT_MS); })]);
|
|
159
|
-
if (timer)
|
|
160
|
-
clearTimeout(timer);
|
|
157
|
+
const mat = await raceDeadline(matP, MCP_DIAL_DEADLINE_MS).catch(() => null);
|
|
161
158
|
if (!mat) {
|
|
162
159
|
void matP.then((m) => m?.dispose().catch(() => undefined)).catch(() => undefined);
|
|
163
160
|
return { servers: [], asOf: new Date().toISOString(), degraded: true };
|
|
@@ -530,7 +527,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
530
527
|
}
|
|
531
528
|
catch (err) {
|
|
532
529
|
const withheld = (coreMessage) => deps.logger?.warn?.("session_memory_erase_refused", { sessionId, err: coreMessage });
|
|
533
|
-
if (sentMemoryComplianceFailure(res, err, { kind: "session_owner", withheld }))
|
|
530
|
+
if (sentMemoryComplianceFailure(res, err, { kind: "session_owner", withheld }, deps.logger))
|
|
534
531
|
return;
|
|
535
532
|
deps.logger?.warn?.("session_memory_erase_failed", { sessionId, err: String(err) });
|
|
536
533
|
sendError(res, 500, "internal.error", "session memory erasure failed");
|
|
@@ -254,6 +254,8 @@ function projectParkRow(p) {
|
|
|
254
254
|
sessionId: p.sessionId,
|
|
255
255
|
originRunId: p.originRunId,
|
|
256
256
|
...(p.originUnconfirmed === true ? { originUnconfirmed: true } : {}),
|
|
257
|
+
...(p.parkedBy !== undefined ? { parkedBy: p.parkedBy } : {}),
|
|
258
|
+
...(p.generation !== undefined ? { generation: p.generation } : {}),
|
|
257
259
|
};
|
|
258
260
|
}
|
|
259
261
|
function summarizeWorkflowDetail(run) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* cut: ONLY TaskRequestBody (its field types are inline or core imports — no other server.ts-local satellites);
|
|
7
7
|
* sibling request/response shapes can migrate here later on the same pattern.
|
|
8
8
|
*/
|
|
9
|
-
import type { A2aServerSpec, AgentDefinition, McpServerSpec, SkillSpec } from "@sema-agent/core";
|
|
9
|
+
import type { A2aServerSpec, AgentDefinition, ApprovalReach, McpServerSpec, SkillSpec } from "@sema-agent/core";
|
|
10
10
|
import type { SettingsPermissionMode } from "../task-settings.js";
|
|
11
11
|
import type { wiringManifestFaceEventData } from "../trace/project.js";
|
|
12
12
|
import type { buildSyncSubmitBody } from "./sync-submit-body.js";
|
|
@@ -466,6 +466,11 @@ export interface TaskRequestBody {
|
|
|
466
466
|
* typeof read. Declared per [ref] 件1 ([ref] boundary-must-schema): the submit chain reads this key, and an
|
|
467
467
|
* undeclared read is a bare cast the exported type cannot audit (embedders could not even write it). */
|
|
468
468
|
interactiveTools?: boolean;
|
|
469
|
+
/** core 7.43.0 `TaskSpec.approvalReach`: the run declares that NOBODY on it can be asked to approve (the only word: `"none"`; closed set and
|
|
470
|
+
* predicate are core's `APPROVAL_REACH` / `isApprovalReach`). Passed to the spec untranslated (boot/resolve-spec.ts) and to the per-leg
|
|
471
|
+
* interactive-posture judgment (an interactive posture beside it is refused by the engine); absent ⇒ key omitted (byte-identical); an
|
|
472
|
+
* unreadable value is a 400 on submit (admission.ts). Not checkpointed by the engine ⇒ resume legs re-supply it from the persisted body. */
|
|
473
|
+
approvalReach?: ApprovalReach;
|
|
469
474
|
/** The caller's per-request settings stamp (the client-side `SemaSettings` shape). The KEY SET is deliberately
|
|
470
475
|
* NOT mirrored here — a hand-written second shape on this interface would be the classic mirror-drift form.
|
|
471
476
|
* Per-key ownership is split, not single: `parseTaskSettings` (src/task-settings.ts) defensively owns the
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* **店形拒**(store-form refusal)在本仓的唯一读法属主(纯叶:零 http / 零 boot 依赖)—— core 一只铸点(`layout.ts` `storeFormRefusal`)的**两码一族**:
|
|
3
|
+
* · `memory.target_outside_store`(core 7.31.1 #1094):记忆 store 里的一个目录经软链通到了 store **外**(或 store 根在 backend 打开 / 引擎首次
|
|
4
|
+
* 挂载之后被改指)⇒ 引擎对落点在外的删 / 写 / 重放 / 自身写一律**不做**;
|
|
5
|
+
* · `memory.scope_home_not_directory`(core 7.44.0 #1368):一只 scope home(`<memoryDir>/<label>`)不是真目录 —— 被换成软链 / 普通文件 / 特殊文件
|
|
6
|
+
* (`detail.form` ∈ `symlink` | `file` | `other`,`lstat` 判、不跟链)。修前 core 对这一形抛不带码的 `ControlPlaneCorruptError`(与真控制面损坏同类同形),
|
|
7
|
+
* 平铺布局(条目直接住在 home 里)于是答 500,而同一换法在嵌套布局下一层答 409 —— 现在两布局同答这一码。
|
|
8
|
+
* 两码的形相同:普通 `Error` + `.code` + `.detail`(`{ path }`;home 那一码多 `form`),**句子以码领头、不含任何宿主路径**(core 7.44.0 起,
|
|
9
|
+
* 路径只在 `detail.path`)。core 的读法:operator 要处置的盘形(去掉那只链 / 放回真目录),**不是**可重试的 IO 故障,也**不是**对调用方的裁决;
|
|
10
|
+
* 盘形修好之前重发恒拒。本仓据此一条规则:两码同族、409、码原样;路径只进运维行(HTTP 映射一处,见 `http/memory-store-refusal-reply.ts`)。
|
|
8
11
|
*
|
|
9
12
|
* ## 两条到达车道,两个读者(本模块各给一只,别处不许再写第二份判据)
|
|
10
13
|
* ① **抛出面**(抹除 / 出处 / 外源列表 / 清标 / bundle 导出导入 —— 凡触 store 树的 backend 面):`.code` 就是码
|
|
11
|
-
* ⇒ {@link
|
|
14
|
+
* ⇒ {@link storeFormRefusalOf}。HTTP 映射在 `http/memory-store-refusal-reply.ts`(409,operator 面一处字面量)与
|
|
12
15
|
* `http/memory-compliance-failure-reply.ts`(合规面两受众的那一只;会话所有者受众换固定句,S-930)。
|
|
13
16
|
* ② **报告面**(harvest `incident`):core 契约写明 report 车道上码**只在文本里** —— `sidecar_corrupt` 的 detail 恰两种形
|
|
14
|
-
* `memory commit refused:
|
|
15
|
-
*
|
|
17
|
+
* `memory commit refused: <码>: …` / `memory control plane refused: <码>: …`(core `docs/wire-consumption/7.31.1.md` 的 harvest 行逐字;
|
|
18
|
+
* 7.44.0 安装树 `engine.js` 两处 incident 铸点同形,home 那一码经同一只 `writeFailureText` 到这里)⇒ {@link storeFormRefusalInIncident} 只认**这两个 lead 紧跟码**
|
|
16
19
|
* 的位置:lead 与码都是 core 铸的字面,路径与引用数据全在码之后。🔴 不做全文子串找(codex 一审 C2:一条真控制面损坏若在
|
|
17
20
|
* 它引用的坏数据里恰好带着这串字,子串找会把它标成目录链 —— 两者运维动作相反)。不读散文、不猜语义;结构化码位
|
|
18
21
|
* (`HarvestReport.incident` / `.warnings` 带码)是向 core 索取的欠账。
|
|
@@ -20,19 +23,41 @@
|
|
|
20
23
|
* 那几行的前缀是**条目路径**(模型可写)—— 本仓今天不读 warnings 车道(既有面,不是本批回归),也不在模型可写的文本上
|
|
21
24
|
* 找码;这一半候 core 的结构化码位(登记在案,codex 一审 C3)。
|
|
22
25
|
*
|
|
23
|
-
* ##
|
|
24
|
-
* · journal 重放目标目录成链 ⇒ `ControlPlaneCorruptError`(无 `.code`,KL-1094-b)⇒ 路由 typed 500 `internal.memory_control_plane_corrupt
|
|
26
|
+
* ## 不是这一族的三形(core 同表「different surface」,本仓**不**自拼码,如实走各自既有臂)
|
|
27
|
+
* · journal 重放目标目录成链 ⇒ `ControlPlaneCorruptError`(无 `.code`,KL-1094-b)⇒ 路由 typed 500 `internal.memory_control_plane_corrupt`
|
|
28
|
+
* (core 7.44.0 起 scope home 非目录**不再**走这一类 —— 它有了自己的码,见上;`ControlPlaneCorruptError` 只剩真控制面损坏);
|
|
25
29
|
* · 引擎原地写撞硬链(nlink>1)⇒ 文本 `has N names (a hard link)`、无码(KL-1094-g / #1105)⇒ 走该写点既有的失败车道(harvest
|
|
26
30
|
* warnings / 挂载失败),抛出面够不着;
|
|
27
31
|
* · 解析故障(`EACCES` / `ELOOP` / `ENOTDIR`)⇒ 以 errno 本身抛 ⇒ 路由未分类 500 + 运维 warn(`String(err)` 带 core 补救句)。
|
|
32
|
+
*
|
|
33
|
+
* ## 运维行也在这里铸(两受众同一只,{@link logStoreFormRefusal})
|
|
34
|
+
* 路径不上 wire,只进这一条运维 warn —— 它是**日志行**不是 wire 错误体,所以铸点跟读法属主住在一起(不住 `http/`:`http/` 全树门
|
|
35
|
+
* `test/error-code-key-gate.test.ts` 咬的是错误体里的 `code:` 键位,日志字段名不该借 wire 层的目录去过它)。
|
|
28
36
|
*/
|
|
29
|
-
|
|
37
|
+
import type { Logger } from "./observability/logger.js";
|
|
38
|
+
/** core 的两码(`dist/core/memory-engine/layout.js` `TARGET_OUTSIDE_STORE` / `SCOPE_HOME_NOT_DIRECTORY`;core 不在包根导出它们,这两个常量是它们在本仓的唯一写点)。 */
|
|
30
39
|
export declare const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export
|
|
40
|
+
export declare const SCOPE_HOME_NOT_DIRECTORY = "memory.scope_home_not_directory";
|
|
41
|
+
/** 店形拒族(闭集;core 加第三码 ⇒ 它落未分类 500 + 运维 warn,由人裁归不归这一族)。 */
|
|
42
|
+
export declare const STORE_FORM_REFUSAL_CODES: readonly ["memory.target_outside_store", "memory.scope_home_not_directory"];
|
|
43
|
+
export type StoreFormRefusalCode = (typeof STORE_FORM_REFUSAL_CODES)[number];
|
|
44
|
+
/** 一次店形拒的读数(纯数据)。`path` / `form` 取自 core 的 `detail`(读不出 ⇒ `undefined`,不猜、不从句子里抠)。 */
|
|
45
|
+
export interface StoreFormRefusal {
|
|
46
|
+
readonly code: StoreFormRefusalCode;
|
|
47
|
+
/** core 原句(以码领头;7.44.0 起不含宿主路径)。 */
|
|
48
|
+
readonly message: string;
|
|
49
|
+
/** `detail.path`:落点 / 被改指的根 / 不是目录的 scope home —— **只给运维行**。 */
|
|
50
|
+
readonly path: string | undefined;
|
|
51
|
+
/** `detail.form`(只在 home 那一码上):原样字符串,不镜像 core 的闭集(本仓只把它写进运维行,不按它分支)。 */
|
|
52
|
+
readonly form: string | undefined;
|
|
53
|
+
}
|
|
54
|
+
/** 抛出面:`err` 是店形拒 ⇒ 读数;否则 `undefined`。形 = core 的 `Error` + `.code` + `.detail`。 */
|
|
55
|
+
export declare function storeFormRefusalOf(err: unknown): StoreFormRefusal | undefined;
|
|
56
|
+
/** 两受众共用的运维行(一处铸点):码 + core `detail` 里的宿主路径与 home 形。`logger` 缺席(只有不接 logger 的测试装配)⇒ 不落。 */
|
|
57
|
+
export declare function logStoreFormRefusal(logger: Pick<Logger, "warn"> | undefined, refusal: StoreFormRefusal): void;
|
|
58
|
+
/** 报告面:harvest `incident` 是这一族拒 ⇒ 码;否则 `undefined`(真控制面损坏的 `sidecar_corrupt` 走这一臂 —— 不被说成店形拒)。 */
|
|
59
|
+
export declare function storeFormRefusalInIncident(incident: {
|
|
35
60
|
readonly kind: string;
|
|
36
61
|
readonly detail: string;
|
|
37
|
-
}):
|
|
62
|
+
}): StoreFormRefusalCode | undefined;
|
|
38
63
|
//# sourceMappingURL=memory-store-refusal.d.ts.map
|
|
@@ -1,14 +1,33 @@
|
|
|
1
1
|
export const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
|
|
2
|
-
export
|
|
2
|
+
export const SCOPE_HOME_NOT_DIRECTORY = "memory.scope_home_not_directory";
|
|
3
|
+
export const STORE_FORM_REFUSAL_CODES = [TARGET_OUTSIDE_STORE, SCOPE_HOME_NOT_DIRECTORY];
|
|
4
|
+
const isStoreFormRefusalCode = (code) => typeof code === "string" && STORE_FORM_REFUSAL_CODES.includes(code);
|
|
5
|
+
export function storeFormRefusalOf(err) {
|
|
3
6
|
if (!(err instanceof Error))
|
|
4
7
|
return undefined;
|
|
5
|
-
const { code } = err;
|
|
6
|
-
|
|
8
|
+
const { code, detail } = err;
|
|
9
|
+
if (!isStoreFormRefusalCode(code))
|
|
10
|
+
return undefined;
|
|
11
|
+
const d = typeof detail === "object" && detail !== null ? detail : {};
|
|
12
|
+
return { code, message: err.message, path: typeof d.path === "string" ? d.path : undefined, form: typeof d.form === "string" ? d.form : undefined };
|
|
13
|
+
}
|
|
14
|
+
export function logStoreFormRefusal(logger, refusal) {
|
|
15
|
+
logger?.warn("memory_store_form_refused", {
|
|
16
|
+
code: refusal.code,
|
|
17
|
+
...(refusal.path !== undefined ? { path: refusal.path } : {}),
|
|
18
|
+
...(refusal.form !== undefined ? { form: refusal.form } : {}),
|
|
19
|
+
});
|
|
7
20
|
}
|
|
8
|
-
const
|
|
9
|
-
export function
|
|
21
|
+
const INCIDENT_LEADS = ["memory commit refused: ", "memory control plane refused: "];
|
|
22
|
+
export function storeFormRefusalInIncident(incident) {
|
|
10
23
|
if (incident.kind !== "sidecar_corrupt")
|
|
11
24
|
return undefined;
|
|
12
|
-
|
|
25
|
+
for (const lead of INCIDENT_LEADS) {
|
|
26
|
+
if (!incident.detail.startsWith(lead))
|
|
27
|
+
continue;
|
|
28
|
+
const rest = incident.detail.slice(lead.length);
|
|
29
|
+
return STORE_FORM_REFUSAL_CODES.find((code) => rest.startsWith(`${code}: `));
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
13
32
|
}
|
|
14
33
|
//# sourceMappingURL=memory-store-refusal.js.map
|
package/dist/model-select.d.ts
CHANGED
|
@@ -136,12 +136,23 @@ export declare function terminalCatalogName(ref: string, catalog: Record<string,
|
|
|
136
136
|
* 它自己)。命中保留名 ⇒ undefined,调用方接着问 {@link refusedCatalogEntry} 拿拒因码。
|
|
137
137
|
*/
|
|
138
138
|
export declare function matchCatalogModel(ref: string, catalog: Record<string, unknown>, refusals?: Readonly<Record<string, ModelEntryRefusal>>): string | undefined;
|
|
139
|
+
/** 「这个目录条目收不收图」的三态(闭集):声明了 `input` 且含 `"image"` / 声明了且不含 / 没声明。 */
|
|
140
|
+
export declare const MODEL_IMAGE_INPUTS: readonly ["yes", "no", "undeclared"];
|
|
141
|
+
export type ModelImageInput = (typeof MODEL_IMAGE_INPUTS)[number];
|
|
139
142
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
143
|
+
* 「这个目录条目收不收图」的**唯一读法**。两个读者都投影它,不各写各的:
|
|
144
|
+
* · 目录行 `GET /v1/models` 的 `vision`:`yes` ⇒ `true`,`no` ⇒ `false`,`undeclared` ⇒ **键缺席**(不替没声明的模型答「收」也不答「不收」);
|
|
145
|
+
* · 运行期的带图预检 {@link modelSupportsImages}:只有明说 `no` 才出信号。
|
|
146
|
+
* 此前两处各判各的,且对「没声明」答法相反(目录行报 false、预检放行)——客户端只读得到目录那一位,于是在手写、没声明 `input` 的
|
|
147
|
+
* 条目上把用户的图拦在了本地,而引擎其实会把图交给模型。env 车道与配置中心车道恒写 `input`,分叉只落在手写目录条目上。
|
|
148
|
+
* `input` 不是数组(手写错形)与条目不在,同归 `undeclared`:没有可信的声明。
|
|
149
|
+
*/
|
|
150
|
+
export declare function modelImageInput(model: {
|
|
151
|
+
input?: unknown;
|
|
152
|
+
} | undefined): ModelImageInput;
|
|
153
|
+
/**
|
|
154
|
+
* 带图预检:只有目录条目**明说**不收图({@link modelImageInput} 为 `"no"`)才为假 —— 提交时据此计数并告警(引擎会把这些图换成给模型的
|
|
155
|
+
* 占位句);没声明的条目为真(不出信号,图原样交给模型)。
|
|
145
156
|
*/
|
|
146
157
|
export declare function modelSupportsImages(model: {
|
|
147
158
|
input?: unknown;
|
package/dist/model-select.js
CHANGED
|
@@ -90,9 +90,13 @@ export function matchCatalogModel(ref, catalog, refusals) {
|
|
|
90
90
|
}
|
|
91
91
|
return undefined;
|
|
92
92
|
}
|
|
93
|
-
export
|
|
93
|
+
export const MODEL_IMAGE_INPUTS = ["yes", "no", "undeclared"];
|
|
94
|
+
export function modelImageInput(model) {
|
|
94
95
|
if (!model || !Array.isArray(model.input))
|
|
95
|
-
return
|
|
96
|
-
return model.input.includes("image");
|
|
96
|
+
return "undeclared";
|
|
97
|
+
return model.input.includes("image") ? "yes" : "no";
|
|
98
|
+
}
|
|
99
|
+
export function modelSupportsImages(model) {
|
|
100
|
+
return modelImageInput(model) !== "no";
|
|
97
101
|
}
|
|
98
102
|
//# sourceMappingURL=model-select.js.map
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* 重试 / 子代对同一个网关再失败,不再说一遍)。受众 user;detail = `{ code, targetHost, proxyInUse?, remedy, sessionId }` ——
|
|
24
24
|
* `proxyInUse` 只在这一跳走了代理时在场,且只是**变量名**(代理地址是基础设施细节,不上租户 wire,与 `OutboundProxyError` 的
|
|
25
25
|
* F3 裁定同一条)。`targetHost`(模型端点的 `host:port`)对 user 受众是**新披露的部署事实**(F7 裁定:它是部署自己声明的模型端点,
|
|
26
|
-
* 不是基础设施秘密,可以上;代理地址仍不上)——
|
|
26
|
+
* 不是基础设施秘密,可以上;代理地址仍不上)—— 不要读成「终局句里本就有」:代理形下终局句只带码与 `via outbound proxy (from <变量>)`、不含任何主机地址,
|
|
27
27
|
* 辅助调用形下 run 可 completed、租户面本无主机句。
|
|
28
28
|
*/
|
|
29
29
|
import type { Brain } from "@sema-agent/core";
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* ·
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
2
|
+
* 规则里的工具名**够不够得着**一只挂载工具 —— 本仓唯一的一问(判官 + 句子各一只),其余全是引擎判官 `judgeRuleToolName` 的判词。
|
|
3
|
+
*
|
|
4
|
+
* 一个名字永远匹配不到工具的成因,判官是谁:
|
|
5
|
+
* · 退役名 / 无协议前缀的 `__` 短名 / **协议名的对端段引擎铸不出**(`mcp__github.com__*`、`mcp__*`、`mcp____x`、`mcp__`)—— 引擎判官
|
|
6
|
+
* (`retired` / `unprefixed_namespace` / `unmintable_segment`,带 `guidance` 与 1:1 `currentName`)。本仓不再拿 `mintNamespacePrefix` 自比对端段:
|
|
7
|
+
* 那是同一问的第二个读者(core 7.43.0 #1355 (b) 起引擎自己给这个判词)。
|
|
8
|
+
* · **工具段为空的协议名**(`mcp__srv__`)—— 引擎判官答 `current`、规则文法收下、allow 条目读成一条精确名行,而它一只工具都够不着
|
|
9
|
+
* (引擎自己的两种拆法 —— 精确名 `ns.parse`、覆盖形 `isNamespacedCoveringRuleName` —— 都不认它)。这是引擎读不到的一形,本仓在下面点名的那些面上
|
|
10
|
+
* 拒它({@link emptyToolSegmentOf}),句子在这里({@link describeEmptyToolSegment})。翻转条件:引擎判官给这一形一个判词 ⇒ 本文件整只退役。
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* **调它的面**(点名,不是「每个面」;判官一问与本仓这一问同调):
|
|
13
|
+
* · 运维三张名表(`APPROVAL_REQUIRE` / `DENY` / `NEVER_AUTO`)与中心下发的同名表、请求 `settings.permissions.{ask,deny}`(经 `config.ts` 的 `unmatchableToolNamesRefusal`);
|
|
14
|
+
* · 会话规则写口(`session-policy-wire.ts`)与 SQL 会话规则店的写口(`assertSessionRuleNamesReachable`);
|
|
15
|
+
* · 引擎 allow 层的条目表:请求的 `settings.permissions.allow`、运维的 `APPROVAL_GRANT`、技能的两只清单 `allowedTools` / `disallowedTools`(顶层 `skills[]` 与子代
|
|
16
|
+
* `agents[].skills[]` 两处受理口)—— 经 `rule-entry-list.ts` 的 `emptyToolSegmentEntryOf`(本仓这一问;退役名 / 铸不出的判词那一半由引擎 `compileAllowList` 给)。
|
|
17
|
+
* **不调它的面**(如实,未接):`/v1/rules` 的持久规则写口与 `cc-import` 导入口(`http/routes/rules.ts`、`rules-consent.ts` 与两只持久规则店零判官调用)、子代的工具名表
|
|
18
|
+
* `agents[].allowTools` / `denyTools`(`spec-fields.ts` 只判形与条数)。在这两处写铸不出的服务器段、工具段为空的协议名仍被收下、永不命中。把这些面接上判官 = 另一件事
|
|
19
|
+
* (本版不做,也不在本文件里加特例;`unmatchableRuleNameOf` 就是现成的那一只)。
|
|
20
|
+
* **精确名的工具段归一不在这里判**:包根没有导出工具段的铸法,不手抄 —— 精确名的工具段按字面收,本仓每张表上都不判它。
|
|
19
21
|
*
|
|
20
|
-
*
|
|
21
|
-
* `rules.legacy_tool_name`)。
|
|
22
|
+
* 规则文本里「工具名那一段」怎么取也只有一种读法:{@link ruleEntryToolName}(配置表与技能清单同读)。
|
|
22
23
|
*/
|
|
23
|
-
import { type ProtocolNamespace } from "@sema-agent/core";
|
|
24
|
+
import { type ProtocolNamespace, type RuleToolNameVerdict } from "@sema-agent/core";
|
|
24
25
|
/**
|
|
25
26
|
* 一条**规则文本**里的工具名那一段(判官与旧名判据的主语)= core 包根 `parsePermissionRule` 的 `toolName`,原样 —— 引擎的技能编译器
|
|
26
27
|
* (`compileSkillGrant`)与规则编译器读条目用的就是这一只:`Bash(npm:*)` ⇒ `Bash`;`mcp__srv(*)` / `mcp__srv()` / 带首尾空格的 `mcp__srv ` ⇒ 光杆名 `mcp__srv`。
|
|
@@ -29,26 +30,31 @@ import { type ProtocolNamespace } from "@sema-agent/core";
|
|
|
29
30
|
* `unsupported.mcp_paren`),拒由引擎的文法那一问说(配置表的判据链里它排在本判官之前),本判官不抢答。
|
|
30
31
|
*/
|
|
31
32
|
export declare function ruleEntryToolName(entry: string): string;
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
| {
|
|
41
|
-
readonly kind: "
|
|
42
|
-
readonly ns: ProtocolNamespace;
|
|
43
|
-
readonly minted: string;
|
|
44
|
-
}
|
|
45
|
-
/** 对端段里带 `*`:写的是通配,而服务器 / 对端名不支持通配(规则对这一段逐字比)。 */
|
|
46
|
-
| {
|
|
47
|
-
readonly kind: "wildcard_peer";
|
|
33
|
+
/**
|
|
34
|
+
* 判官的名册:本仓的配置表 / 请求表 / 会话规则写口都不声明「部署在退役名下挂了自有工具」(本仓没有这样的工具;boot / 请求期也没有哪一跑的名册可看)
|
|
35
|
+
* ⇒ 恒为空集。引擎判官、`compileAllowList` 的第三参、会话规则店同读这一只。
|
|
36
|
+
*/
|
|
37
|
+
export declare const NO_DECLARED_TOOL_NAMES: ReadonlySet<string>;
|
|
38
|
+
/** 一个规则名永远匹配不到工具的判词(闭集):引擎判官的三种非现行判词 ∪ 引擎读不到的那一形。 */
|
|
39
|
+
export type UnmatchableRuleName = Exclude<RuleToolNameVerdict, {
|
|
40
|
+
kind: "current";
|
|
41
|
+
}> | {
|
|
42
|
+
readonly kind: "empty_tool_segment";
|
|
48
43
|
readonly ns: ProtocolNamespace;
|
|
49
44
|
};
|
|
50
|
-
/**
|
|
51
|
-
export declare function
|
|
52
|
-
/**
|
|
53
|
-
|
|
45
|
+
/** 判:引擎判官先答(非 `current` ⇒ 原样交回),判官放行的再问引擎读不到的那一形;都过 ⇒ `undefined`。 */
|
|
46
|
+
export declare function unmatchableRuleNameOf(name: string): UnmatchableRuleName | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* 判词 → 「为什么永远匹配不到 + 怎么写」(不复述条目本身 —— 调用方的句子已点名它)。引擎判词的 `guidance` 原样带出,是改法指引的**唯一**一句
|
|
49
|
+
* (本仓不在后面追加 1:1 现名:通配名上那个现名是摘要名或更窄的写法,照写不生效;现名过境给机器读的位,如会话规则拒体顶层的 `currentName`);
|
|
50
|
+
* 无前缀短名的出路从 core 的 `PROTOCOL_TABLE` 派生。闭集穷尽:判词加一种 ⇒ 编译红。
|
|
51
|
+
*/
|
|
52
|
+
export declare function describeUnmatchableRuleName(v: UnmatchableRuleName, name: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* 工具段为空的协议名(`<ns>__<peer>__`)⇒ 交回它的协议;别的名字 ⇒ `undefined`。判据只读引擎:判官答 `current`(对端段为空 / 铸不出的那些 ——
|
|
55
|
+
* `mcp__`、`mcp____x` —— 是判官自己的判词,不在这里),而引擎自己的两种拆法(精确名 `ns.parse`、覆盖形 `isNamespacedCoveringRuleName`)都不认它。纯字符串运算。
|
|
56
|
+
*/
|
|
57
|
+
export declare function emptyToolSegmentOf(name: string): ProtocolNamespace | undefined;
|
|
58
|
+
/** {@link emptyToolSegmentOf} 的句子(「为什么永远匹配不到 + 怎么写」;不复述条目本身 —— 调用方的句子已点名它)。 */
|
|
59
|
+
export declare function describeEmptyToolSegment(ns: ProtocolNamespace): string;
|
|
54
60
|
//# sourceMappingURL=namespaced-rule-name.d.ts.map
|
|
@@ -1,33 +1,47 @@
|
|
|
1
|
-
import { isNamespacedCoveringRuleName,
|
|
1
|
+
import { PROTOCOL_TABLE, isNamespacedCoveringRuleName, judgeRuleToolName, parsePermissionRule, protocolOf } from "@sema-agent/core";
|
|
2
|
+
import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
|
|
2
3
|
export function ruleEntryToolName(entry) {
|
|
3
4
|
return parsePermissionRule(entry).toolName;
|
|
4
5
|
}
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (peer.includes("*"))
|
|
13
|
-
return { kind: "wildcard_peer", ns };
|
|
14
|
-
const minted = mintNamespacePrefix(ns, peer);
|
|
15
|
-
return minted === `${ns.prefix}${peer}__` ? undefined : { kind: "unminted_peer", ns, minted };
|
|
6
|
+
export const NO_DECLARED_TOOL_NAMES = new Set();
|
|
7
|
+
export function unmatchableRuleNameOf(name) {
|
|
8
|
+
const verdict = judgeRuleToolName(name, NO_DECLARED_TOOL_NAMES);
|
|
9
|
+
if (verdict.kind !== "current")
|
|
10
|
+
return verdict;
|
|
11
|
+
const ns = emptyToolSegmentOf(name);
|
|
12
|
+
return ns === undefined ? undefined : { kind: "empty_tool_segment", ns };
|
|
16
13
|
}
|
|
17
|
-
|
|
14
|
+
function presentName(name) {
|
|
15
|
+
const clean = name.replace(CONTROL_AND_BIDI_STRIP_RE, "");
|
|
16
|
+
return clean.length <= 160 ? clean : `${clean.slice(0, 160)}…(${name.length} chars)`;
|
|
17
|
+
}
|
|
18
|
+
export function describeUnmatchableRuleName(v, name) {
|
|
18
19
|
switch (v.kind) {
|
|
19
|
-
case "
|
|
20
|
-
return
|
|
21
|
-
case "
|
|
22
|
-
return
|
|
23
|
-
case "
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
case "retired":
|
|
21
|
+
return v.guidance;
|
|
22
|
+
case "unmintable_segment":
|
|
23
|
+
return v.guidance;
|
|
24
|
+
case "unprefixed_namespace":
|
|
25
|
+
return `pre-prefix short form — the live name carries a protocol prefix: ${PROTOCOL_TABLE.map((e) => `${e.prefix}${presentName(name)}`).join(" or ")}`;
|
|
26
|
+
case "empty_tool_segment":
|
|
27
|
+
return describeEmptyToolSegment(v.ns);
|
|
27
28
|
default: {
|
|
28
29
|
const unhandled = v;
|
|
29
|
-
throw new Error(`unhandled
|
|
30
|
+
throw new Error(`unhandled rule name verdict: ${JSON.stringify(unhandled)}`);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
export function emptyToolSegmentOf(name) {
|
|
35
|
+
const ns = protocolOf(name);
|
|
36
|
+
if (ns === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (judgeRuleToolName(name, NO_DECLARED_TOOL_NAMES).kind !== "current")
|
|
39
|
+
return undefined;
|
|
40
|
+
if (ns.parse(name) !== undefined || isNamespacedCoveringRuleName(name))
|
|
41
|
+
return undefined;
|
|
42
|
+
return ns;
|
|
43
|
+
}
|
|
44
|
+
export function describeEmptyToolSegment(ns) {
|
|
45
|
+
return `incomplete ${ns.id} name — the live form is ${ns.prefix}<server>__<tool>, or ${ns.prefix}<server> / ${ns.prefix}<server>__* to cover every tool on that server`;
|
|
46
|
+
}
|
|
33
47
|
//# sourceMappingURL=namespaced-rule-name.js.map
|
|
@@ -148,6 +148,10 @@ export declare const JSONL_REPLAY_SEATS: {
|
|
|
148
148
|
readonly direction: "fail-open";
|
|
149
149
|
readonly tag: "server.workflow-agent-session-index.corrupt-record-skipped";
|
|
150
150
|
};
|
|
151
|
+
readonly "workflow-completion-inbox": {
|
|
152
|
+
readonly direction: "fail-open";
|
|
153
|
+
readonly tag: "server.workflow-completion-inbox.corrupt-record-skipped";
|
|
154
|
+
};
|
|
151
155
|
readonly "user-input-ledger": {
|
|
152
156
|
readonly direction: "fail-open";
|
|
153
157
|
readonly tag: "server.user-input-ledger.corrupt-record-skipped";
|
|
@@ -133,6 +133,7 @@ export const JSONL_REPLAY_SEATS = {
|
|
|
133
133
|
"approval-ask-audit": { direction: "fail-open", tag: "server.approval-ask-audit.corrupt-record-skipped" },
|
|
134
134
|
"workflow-notify-journal": { direction: "fail-open", tag: "server.workflow-notify-journal.corrupt-record-skipped" },
|
|
135
135
|
"workflow-agent-session-index": { direction: "fail-open", tag: "server.workflow-agent-session-index.corrupt-record-skipped" },
|
|
136
|
+
"workflow-completion-inbox": { direction: "fail-open", tag: "server.workflow-completion-inbox.corrupt-record-skipped" },
|
|
136
137
|
"user-input-ledger": { direction: "fail-open", tag: "server.user-input-ledger.corrupt-record-skipped" },
|
|
137
138
|
};
|
|
138
139
|
function corruptRefusalSentence(seat, path, reason) {
|
|
@@ -24,7 +24,11 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
24
24
|
};
|
|
25
25
|
readonly "server.workflow-park-index.sync-failed": {
|
|
26
26
|
readonly cls: "P-DEBT";
|
|
27
|
-
readonly note: "S-185 车CM(codex r1-F2 [high],验真后登记):workflow 出身 park 的 join 索引(`workflow_agent_session` / local 账本)在**一次成功的 run 写之后**同步失败 ⇒ 该次同步被吞,重试要等这条 run 的**下一次**写。而 park 恰好常常是这条 run 的**最后**一次写(park = run 终局 `failed`)⇒ 那条 park 可能永久 join
|
|
27
|
+
readonly note: "S-185 车CM(codex r1-F2 [high],验真后登记):workflow 出身 park 的 join 索引(`workflow_agent_session` / local 账本)在**一次成功的 run 写之后**同步失败 ⇒ 该次同步被吞,重试要等这条 run 的**下一次**写。而 park 恰好常常是这条 run 的**最后**一次写(park = run 终局 `failed`)⇒ 那条 park 可能永久 join 不到。**多数情形**是诚实 miss:这张卡没有别的指针 ⇒ `/decide` 结构性退回本批之前的行为(409 `conflict.resume_context_unavailable`),不误配、不伪造、不放行,丢的是「人能不能把这条批准送出去」这个能力。**7.118.0 起不止于此**:路由把指针候选当持有者的全集读,并有分叉门(两条同代次持有者 ⇒ 409 `decide.workflow_park_forked`);同一张卡上一枚**竞争**指针没写上(本臂的写失败,或写记录与写指针之间进程崩溃 —— 后者不经本臂、不计数)⇒ 分叉被判成唯一持有者 ⇒ 决定投给幸存的那一支(它确实持有这张卡,但另一支同样站在上面,引擎把这种形交给消费方拒)。归 P 类的理由:缺指针决定**车道选择**(缺行 ⇒ 选中 legacy 腿),且能让分叉门失效;归 DEBT 的理由是真正的解要一条**按子代 checkpoint 键的耐久决议回执 + 重启期回填**(与 codex r1-F3 同一件欠账,另车),分叉门失效那一形另有设计票。计数非零 = 有 park 可能决不掉、或这张卡的分叉门可能失效,运维要按 detail 里的 runId 去查那条 run 的续跑链。";
|
|
28
|
+
};
|
|
29
|
+
readonly "server.workflow-park-index.parks-unreadable": {
|
|
30
|
+
readonly cls: "F";
|
|
31
|
+
readonly note: "S-1173(`workflow-notify-journal.ts` 的 `syncAgentSessionIndex`,与上一条 `sync-failed` 同一个写点、另一臂):workflow run 记录的 `parks[]` **读不出**(在场却不是列表 / 某条目身份位或持有者两位形坏;读者 = `workflow-agent-session-index.ts` 的 `readRunParks`,整档成败制)⇒ 这一份指针投影派生不出来 ⇒ 写者**不动**这条 run 已有的指针(上一份已知良好的投影留着)。修前这一臂静默 `return`。**`parks` 缺席不进这一臂**:那是引擎契约里的合法形(更早引擎写的记录 / 准入没走完的续跑记录),读者答 `[]`(没有条目),写者照常收敛成空指针集,不计。**与 `sync-failed` 分家的理由(后果不同句,不并成一个 tag)**:`sync-failed` 是索引**写**挂了、丢的是一份已知良好的投影(park 常常是 run 的最后一次写 ⇒ 永久 join 不到,归 P-DEBT);本臂没有丢任何一份已知良好的投影 —— 读不出的是**记录本身**,引擎对条目形坏的记录整条拒续跑(`park_binding_broken`),读口对已有指针的 run 据记录响亮拒(`unproven/unreadable`),所以无需「重试这次写」,要的是查那条记录为什么读不出(投影把它写坏 / 手改)。放行的最坏后果:这条 run 的指针不被刷新(从没写过则没有指针 ⇒ 这张卡没有别的指针时 `/decide` 落 legacy 腿、409 响亮拒),多数情形方向是 fail-closed,不误配、不放行任何东西;例外与上一条同形 —— 首写就读不出的这一支没有指针,同一张卡上另一支的指针在时分叉门判不出、决定投给那一支(引擎从不写坏形,要这一支在首写之前就被写坏,比上一条的写失败更罕见);derived cache 没更新、真源读口自带响亮拒 ⇒ F 类。detail = `runId=`;计数非零 = 有记录的 `parks[]` 读不出,按 runId 去查记录。";
|
|
28
32
|
};
|
|
29
33
|
readonly "server.trace.gate-outcome-defective": {
|
|
30
34
|
readonly cls: "F";
|
|
@@ -116,7 +120,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
116
120
|
};
|
|
117
121
|
readonly "server.approvals.risk-descriptor-cell-unreadable": {
|
|
118
122
|
readonly cls: "F";
|
|
119
|
-
readonly note: "运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint.risk_descriptor` 这一格**不是合法 JSON 文本**(手改过的行 / 回滚残留 / 列语义漂;与同一 `rows.map` 里的 `rule_suggestions` 是同族坏法,两方言都是 TEXT 列)。放行的最坏后果 = **这一行**的分诊 descriptor 落 null:severity 折 0 排到有 descriptor
|
|
123
|
+
readonly note: "运维待批队列(`GET /v1/approvals` / `/stream`)的某一行,`checkpoint.risk_descriptor` 这一格**不是合法 JSON 文本**(手改过的行 / 回滚残留 / 列语义漂;与同一 `rows.map` 里的 `rule_suggestions` 是同族坏法,两方言都是 TEXT 列)。放行的最坏后果 = **这一行**的分诊 descriptor 落 null:severity 折 0 排到有 descriptor 的行之后、披露位(`allowRuleShadowed`;7.117.0 前叫 `shadowedRule`)无可脱敏、读面派生的 `governanceForced` 徽章不亮 —— 三者都是**展示/分诊**,不是执法判据(门早已 park,真按 `shellGateDoctrine` 判的 `active-run-conflict.ts` 读的是 checkpoint blob 的 `get()`,不经本读面),且 `governanceForced` 的成文语义本就是「缺席 = 没有治理来源的**证据**」。不放行的代价是整只 `rows.map` 抛出 ⇒ 一行坏 cell 打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远空),连同其余所有行一起消失。故 F 类;tag 与候选那格**分开计**,并计会让「哪一格在坏」在遥测里读不出来。";
|
|
120
124
|
};
|
|
121
125
|
readonly "server.approvals.park-row-blob-unreadable": {
|
|
122
126
|
readonly cls: "F";
|
|
@@ -296,7 +300,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
296
300
|
};
|
|
297
301
|
readonly "server.approval-card.closed-word-out-of-set": {
|
|
298
302
|
readonly cls: "F";
|
|
299
|
-
readonly note: "S-249(`approval-card.ts` 的边界窄读族;今天三个成员:`readRuleOffersAbsence`、S-934 ② 起的 `readAskClassPair`(core 7.37.0 #1214 的类对 `askClass` / `classes`,活卡帧 / 呈卡帧的卡 / 运维队列行同一只,判法 = core 屏 `screenAskClassMembers`(S-955 ⑥ / core 7.38.0 #1249,本仓零自写对判),两键同在同缺,半对 / 集外 / 首员不符 / 重复员 = 屏拒 = 读不出;detail 前缀 `askClass=` / `classes=`),与 S-721 起的 `readClosedWordSeat` —— 一座一只 core 成员筛,座是参数:`mandate`(core 7.32.0 #1092,活卡帧 / 活挂起行 / 运维队列行同一只,闭集筛 = core `isPersistedRuleMandate`)与 S-755 起的 `origin`(运维队列行读 park 行孪生座,闭集筛 = core `isAskOrigin`,与 inbox 行 core 投影处同一只筛);detail 前缀 `ruleOffersAbsence=` / `mandate=` / `origin=` 判别是哪一座):活卡帧 / `card_json` / (S-700 起)运维队列行(`parkRowFacts` 读寄存行上的 park 孪生座;队列是热读面 ⇒ 同一行每读一次计一次)的一个**闭集词**座上,键在场而词不在本仓认得的那张表里(世代差,或第三方 producer)⇒ 该座**按缺席**处置。放行的最坏后果=卡上少一行「为什么这次没有规则候选」的解释(壳退回不显示该行),它**不改变任何裁决**——门在引擎里早已判完,本座是展示/观测面;反方向(把一个消费端词表外的值原样上卡)更坏:下游按闭集写的分支会落进 default 臂或渲染出生词。本臂存在的全部理由是**判别**:修前「上游发了个生词」与「上游根本没发这个键」在遥测上同形,而前者意味着本仓的词表该跟着 core 加词了(型面另有两向编译围栏,但那只在**重新编译**时说话,跑在线上的那一版不会自己红)。detail 带座名与那个词(经 redactSecrets 截 40);数 / 布尔等原始值原样,对象 / 数组 / 函数 / null 只报形名(`<object>` / `<array>` / `<function>` / `<null>`,S-700 codex r1:格式化从不调用值自己的转换方法 —— 持久层里一格 `{\"toString\":null}` 曾让诊断本身抛出、打掉整只队列)。";
|
|
303
|
+
readonly note: "S-249(`approval-card.ts` 的边界窄读族;今天三个成员:`readRuleOffersAbsence`、S-934 ② 起的 `readAskClassPair`(core 7.37.0 #1214 的类对 `askClass` / `classes`,活卡帧 / 呈卡帧的卡 / 运维队列行同一只,判法 = core 屏 `screenAskClassMembers`(S-955 ⑥ / core 7.38.0 #1249,本仓零自写对判),两键同在同缺,半对 / 集外 / 首员不符 / 重复员 = 屏拒 = 读不出;detail 前缀 `askClass=` / `classes=`),与 S-721 起的 `readClosedWordSeat` —— 一座一只 core 成员筛,座是参数:`mandate`(core 7.32.0 #1092,活卡帧 / 活挂起行 / 运维队列行同一只,闭集筛 = core `isPersistedRuleMandate`)与 S-755 起的 `origin`(运维队列行读 park 行孪生座,闭集筛 = core `isAskOrigin`,与 inbox 行 core 投影处同一只筛)、S-1170 起的 `classifierNoRuling`(core 7.43.0 #1353 的成因词,活卡帧读 `AskRequest.classifierNoRuling`,闭集筛 = core `isAutoModeFallbackCause`)与 `differs`(core 7.44.0 #1374,载体是 `runs.ts` 的 409 `steering.duplicate_input_id` 体读的引擎拒错 `detail.differs`,闭集筛 = core `STEER_REPLAY_FACETS` 的非空子集;集外成员 / 空 / 非数组 ⇒ 不铸 `detail`,码仍是契约);detail 前缀 `ruleOffersAbsence=` / `mandate=` / `origin=` / `classifierNoRuling=` / `differs=` 判别是哪一座):活卡帧 / `card_json` / (S-700 起)运维队列行(`parkRowFacts` 读寄存行上的 park 孪生座;队列是热读面 ⇒ 同一行每读一次计一次)的一个**闭集词**座上,键在场而词不在本仓认得的那张表里(世代差,或第三方 producer)⇒ 该座**按缺席**处置。放行的最坏后果=卡上少一行「为什么这次没有规则候选」的解释(壳退回不显示该行),它**不改变任何裁决**——门在引擎里早已判完,本座是展示/观测面;反方向(把一个消费端词表外的值原样上卡)更坏:下游按闭集写的分支会落进 default 臂或渲染出生词。本臂存在的全部理由是**判别**:修前「上游发了个生词」与「上游根本没发这个键」在遥测上同形,而前者意味着本仓的词表该跟着 core 加词了(型面另有两向编译围栏,但那只在**重新编译**时说话,跑在线上的那一版不会自己红)。detail 带座名与那个词(经 redactSecrets 截 40);数 / 布尔等原始值原样,对象 / 数组 / 函数 / null 只报形名(`<object>` / `<array>` / `<function>` / `<null>`,S-700 codex r1:格式化从不调用值自己的转换方法 —— 持久层里一格 `{\"toString\":null}` 曾让诊断本身抛出、打掉整只队列)。";
|
|
300
304
|
};
|
|
301
305
|
readonly "server.pg-pool.idle-client-error": {
|
|
302
306
|
readonly cls: "F";
|
|
@@ -334,6 +338,10 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
334
338
|
readonly cls: "F";
|
|
335
339
|
readonly note: "S-977(`orchestration/workflow-agent-session-index.ts`,local 车道 workflow 出身 park 的 join 索引账本的 boot 重放;登记名 `workflow-agent-session-index`):账本**中间**一行读不出形(`42` / 数组 / 缺 `runId`·`rows` / 任一行成员缺身份位 / 半截 JSON;撕尾不走本 tag)⇒ **整行**跳过,那条 run 保留上一份已知良好的快照(不做「丢坏成员、留好成员」—— 那会铸出比真相少几条 park 的行集)。最坏后果 = 该 run 的 park 在索引里缺行 ⇒ `/decide` 找不到它、退回 legacy 腿(409 `conflict.resume_context_unavailable`):诚实 miss,不是错配 —— 赎回键由记录上的 `parks[]` 逐字比对,不读本索引。索引不开门 ⇒ F。修前:形不对的整行响亮(`workflow_agent_session_ledger_line_rejected`,同事件名保留)但**无 tag**,带换行的半截 JSON 静默 `continue`。";
|
|
336
340
|
};
|
|
341
|
+
readonly "server.workflow-completion-inbox.corrupt-record-skipped": {
|
|
342
|
+
readonly cls: "F";
|
|
343
|
+
readonly note: "S-978(`orchestration/workflow-completion-inbox.ts`,local 车道 File 完成信箱的 boot 重放;登记名 `workflow-completion-inbox`):账本**中间**一行读不出形(`42` / `null` / 数组 / 缺 `op` 或 `op` 词表外 / `enqueue` 缺 `entry.sessionId`·`entry.runId` / `ack` 缺 `sessionId`·`runId` / `drain` 缺 `sessionId` / 半截 JSON;撕尾不走本 tag)⇒ 跳过它继续。最坏后果按行种:丢 `enqueue` ⇒ 那条完成推送不进信箱(`WorkflowStatus` 轮询地板照旧兜住);丢 `ack` ⇒ 一条已送达的完成在重启后再投一次(壳按 runId 去重,至少一次的既有语义);丢 `drain`(会话清除墓碑)⇒ 被删会话里尚未送达的条目复活 —— 出帧前仍过 owner 二道闸(`emitPendingWorkflowCompletions`:条目盖的 owner 与本次调用方不符 ⇒ ack 丢弃、不出帧),同属主重领同一 sessionId 只会多收一条按 runId 去重的推送。信箱不开门、不改任何 run 的执行或授权 ⇒ F。修前:解析失败 `continue`(静默),而解析成功的 `null` 行在读 `rec.op` 时抛 TypeError ⇒ `new FileWorkflowCompletionInbox` 抛(构造点无 catch ⇒ 这一面起不来),其余非对象 / 缺键形静默忽略。boot 压实随后从内存活集重写账本 ⇒ 坏行的字节压实后不留盘,披露是它唯一的记录。";
|
|
344
|
+
};
|
|
337
345
|
readonly "server.user-input-ledger.append-failed": {
|
|
338
346
|
readonly cls: "F";
|
|
339
347
|
readonly note: "S-928(`src/user-input-ledger.ts`):200 承诺**之后**的一次账本写失败 —— detail 的 `op=` 点名是哪一种:`settle`(腿在本进程收场)/ `withdraw`(引擎没收下这次 steer)/ `converge`(收敛器判孤儿)/ `announce`(通告已投出,记「告知过」)。放行的最坏后果逐个说清:settle / withdraw 漏写 ⇒ 这次受理在账上仍是 open —— 本进程下一次收敛扫描补结清(本进程写的、已不在活腿上 ⇒ leg_over);进程在那之前就崩了 ⇒ 下一次 boot 的收敛读 run 店判(S-969 L8 起两车道同一只判词:承载它的 run 正常翻面 / 已 park ⇒ leg_over 补结清、不告知;落款死亡判决或写者已死仍 running ⇒ crashed)—— 仍会多说一句的只剩两形:withdraw 漏写后那条腿崩了(一次没变成 200 的受理被告知一次);settle 漏写后本进程续跑了同一条 run、续跑腿崩了(run 行说的是同一 taskId 上**最新**那条腿)。方向都是多说,不漏;converge 漏写 ⇒ 留在 open,下一次扫描再判(延迟,不丢);announce 漏写 ⇒ 下一条 run 再说一遍(至多一次退化成至少一次)。都是**告知面**的偏差,不开任何门、不改任何 run 的执行 ⇒ F。计数非零 = 这台机器的账本写不动了(local:数据根盘满 / 只读;SQL:库不可达),steer 此刻多半也在回 503。";
|
|
@@ -374,6 +382,10 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
374
382
|
readonly cls: "F";
|
|
375
383
|
readonly note: "7.116.0 修复轮(`approval-crash-convergence.ts` 的 `convergeCrashedAsksAtBoot`;local 车道启动收敛):前世留下的一条 `STREAM_PENDING` 问行,它的卡信封(`card_json`)读不出 ⇒ 读不出 wire `approvalId`、无从向审计账要成因词 ⇒ 成因**回落**成 `crashed_before_park`。行照样收 VOID(决断口照样 410 —— 可决性 fail-closed,不受影响);最坏后果 = 一张其实是被有序关停截断的卡,在 410 体的 `deniedReason` 上说成「进程崩了」(`crashConverged` 读面若有它的审计组,那里的成因仍按审计账判,两处可能不同词)。计数非零 = 问账里有读不出卡信封的行(位腐 / 手改 / 版本错位),去看探针 detail 点名的 askId。读数另在启动日志 `approval_ask_audit_crash_converged` 的 `causeUnreadable` 格单列。";
|
|
376
384
|
};
|
|
385
|
+
readonly "server.outbound.hop-member-unreadable": {
|
|
386
|
+
readonly cls: "F";
|
|
387
|
+
readonly note: "出网代理那一跳建连失败的 wire 投影(`outbound-dispatcher.ts` `projectHopFailure`):按 core 连接失败分类器的读法复制错误图时,某个成员的访问器抛了(或对象不可 toString)。读法与分类器同一把,所以抛了当缺席;最坏后果 = 副本上少一个成员,分类器把这一次失败读成 unclassified(终局句只剩 `via outbound proxy` 一句、不带码),不影响重试阶梯的方向。只在怪形错误对象上触发,计数即可。";
|
|
388
|
+
};
|
|
377
389
|
readonly "server.outbound.connect-observer-threw": {
|
|
378
390
|
readonly cls: "F";
|
|
379
391
|
readonly note: "S-925(`outbound-dispatcher.ts` 的 undici 诊断通道订阅者:`undici:request:create` / `:headers` / `:error`):一只订阅回调抛了。通道在发布方的调用栈里同步回调订阅者,抛出去在 Node 上是未捕获异常(整进程倒),所以每只回调整体 try、落本 tag。最坏后果 = 这一条请求的建连失败没被记下:少一行 `outbound_connect_failed`、诊断段 `outbound.lastConnectFailure` 不更新、那次模型调用不铸 `server.model_unreachable` 用户通告 —— 请求本身、它的错误、run 的终态一个字节不受影响(观察只读)。计数恒零是证据;非零 = undici 通道载荷的形变了,去看 detail 的 site。";
|