@sema-agent/server 7.135.0 → 7.136.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 +64 -2
- package/USAGE.md +62 -25
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
- package/deploy/sema-up/chart/values.yaml +1 -1
- package/dist/approval-card.d.ts +60 -4
- package/dist/approval-card.js +18 -1
- package/dist/approval-content-kind.d.ts +1 -0
- package/dist/approval-content-kind.js +1 -1
- package/dist/auth-bridge.d.ts +34 -5
- package/dist/auth-bridge.js +20 -3
- package/dist/boot/budget-tracing.d.ts +1 -2
- package/dist/boot/budget-tracing.js +2 -2
- package/dist/boot/org-memory.js +1 -1
- package/dist/boot/resolve-spec.js +10 -7
- package/dist/boot/runner-deps.js +4 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +1 -1
- package/dist/boot/stage-07-capability-layer.d.ts +1 -1
- package/dist/boot/stage-08-reapers.d.ts +1 -1
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stores.js +2 -3
- package/dist/boot/web-admin.js +10 -17
- package/dist/brain.js +12 -3
- package/dist/budget.d.ts +3 -3
- package/dist/budget.js +4 -0
- package/dist/capabilities/mcp-probe.d.ts +5 -4
- package/dist/capability-facts.d.ts +3 -7
- package/dist/capability-facts.js +3 -5
- package/dist/center-credential.d.ts +18 -4
- package/dist/center-credential.js +18 -3
- package/dist/config-catalog.js +12 -10
- package/dist/config-d-migration.js +1 -1
- package/dist/config-invariants.d.ts +1 -1
- package/dist/config-invariants.js +8 -0
- package/dist/config-lkg.d.ts +0 -38
- package/dist/config-lkg.js +1 -83
- package/dist/config-types.d.ts +12 -4
- package/dist/config.js +26 -8
- package/dist/deployment-shape.d.ts +1 -1
- package/dist/elicitation.d.ts +8 -7
- package/dist/elicitation.js +9 -8
- package/dist/file-history-disclosure.d.ts +6 -4
- package/dist/file-history-disclosure.js +22 -6
- package/dist/fleet-client.d.ts +32 -1
- package/dist/fleet-client.js +24 -4
- package/dist/fleet-lease.d.ts +7 -3
- package/dist/fleet-lease.js +31 -23
- package/dist/hooks/hook-llm.js +14 -8
- package/dist/hooks/hook-runner.d.ts +4 -4
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/http/checkpoint-ctx.d.ts +28 -9
- package/dist/http/checkpoint-ctx.js +5 -1
- package/dist/http/dispatch.js +9 -9
- package/dist/http/resume-ctx-read.d.ts +2 -16
- package/dist/http/resume-ctx-read.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +0 -2
- package/dist/http/routes/approvals-assistant.js +47 -12
- package/dist/http/routes/runs.js +2 -2
- package/dist/http/routes/session-sync.js +31 -9
- package/dist/http/routes/sessions.js +18 -14
- package/dist/http/submit-ctx.js +1 -1
- package/dist/http/wire-types.d.ts +5 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/model-route-gap.d.ts +49 -4
- package/dist/model-route-gap.js +34 -1
- package/dist/object-store-buckets.d.ts +13 -0
- package/dist/object-store-buckets.js +3 -0
- package/dist/observability/fail-open.d.ts +6 -6
- package/dist/observability/fail-open.js +6 -6
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/principal-context.d.ts +4 -1
- package/dist/observability/principal-context.js +6 -1
- package/dist/parked-decide.d.ts +4 -3
- package/dist/parked-decide.js +26 -7
- package/dist/peer-directory.d.ts +2 -1
- package/dist/peer-directory.js +5 -5
- package/dist/plugins/approval-ask-store-sql.d.ts +8 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -0
- package/dist/plugins/blob-backend.js +2 -1
- package/dist/plugins/checkpoint-index-columns.d.ts +50 -1
- package/dist/plugins/checkpoint-index-columns.js +28 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +27 -3
- package/dist/plugins/checkpoint-store-sql.js +58 -29
- package/dist/plugins/file-history-store-sql.d.ts +6 -0
- package/dist/plugins/file-history-store-sql.js +30 -23
- package/dist/plugins/local-checkpoint-store.js +4 -3
- package/dist/plugins/one-time-migrations.d.ts +21 -28
- package/dist/plugins/one-time-migrations.js +39 -123
- package/dist/plugins/remote-env-k8s.d.ts +18 -5
- package/dist/plugins/remote-env-k8s.js +24 -7
- package/dist/plugins/s3-answer.d.ts +15 -0
- package/dist/plugins/s3-answer.js +5 -0
- package/dist/plugins/snapshot-bucket-presence.d.ts +39 -4
- package/dist/plugins/snapshot-bucket-presence.js +35 -7
- package/dist/plugins/sql-errors.d.ts +39 -0
- package/dist/plugins/sql-errors.js +49 -1
- package/dist/plugins/store-fault.d.ts +4 -0
- package/dist/plugins/store-fault.js +8 -0
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -2
- package/dist/request-declaration-refusal.d.ts +94 -0
- package/dist/request-declaration-refusal.js +78 -0
- package/dist/request-image-urls.d.ts +6 -0
- package/dist/request-image-urls.js +27 -0
- package/dist/request-key-closure.d.ts +5 -0
- package/dist/request-key-closure.js +4 -1
- package/dist/runtime-caps-resolver.js +1 -1
- package/dist/sandbox-pkg-source.d.ts +28 -1
- package/dist/sandbox-pkg-source.js +1 -2
- package/dist/sealed-key.d.ts +19 -0
- package/dist/sealed-key.js +47 -4
- package/dist/session-incarnation.d.ts +16 -5
- package/dist/session-incarnation.js +7 -4
- package/dist/session-row.d.ts +3 -17
- package/dist/session-row.js +4 -0
- package/dist/session-sync.d.ts +15 -3
- package/dist/session-sync.js +5 -2
- package/dist/task-a2a.d.ts +52 -81
- package/dist/task-a2a.js +219 -89
- package/dist/task-mcp.d.ts +6 -14
- package/dist/task-mcp.js +16 -51
- package/dist/tool-approval.d.ts +23 -10
- package/dist/tool-approval.js +51 -36
- package/dist/trace/core-keyset-guard.d.ts +2 -2
- package/dist/trace/exit-seat.js +37 -13
- package/dist/trace/redact.d.ts +28 -12
- package/dist/trace/redact.js +233 -94
- package/dist/trace/self-minted-wire.d.ts +267 -0
- package/dist/trace/self-minted-wire.js +79 -0
- package/dist/url-credential-refusal.d.ts +52 -0
- package/dist/url-credential-refusal.js +14 -0
- package/dist/url-refusal.d.ts +13 -4
- package/dist/url-refusal.js +8 -2
- package/dist/workspace-space.d.ts +27 -0
- package/dist/workspace-space.js +26 -0
- package/package.json +3 -2
- package/scripts/drain-check-local.mjs +2 -1
- package/scripts/drain-check.mysql.sql +3 -1
- package/scripts/drain-check.pg.sql +3 -1
- package/skills/schedule.md +1 -1
- package/wire-changes/server@7.104.0.json +134 -0
- package/wire-changes/server@7.105.0.json +53 -0
- package/wire-changes/server@7.106.0.json +475 -0
- package/wire-changes/server@7.107.0.json +64 -0
- package/wire-changes/server@7.108.0.json +153 -0
- package/wire-changes/server@7.109.0.json +46 -0
- package/wire-changes/server@7.110.0.json +90 -0
- package/wire-changes/server@7.111.0.json +86 -0
- package/wire-changes/server@7.112.0.json +60 -0
- package/wire-changes/server@7.113.0.json +26 -0
- package/wire-changes/server@7.114.0.json +26 -0
- package/wire-changes/server@7.115.0.json +97 -0
- package/wire-changes/server@7.116.0.json +218 -0
- package/wire-changes/server@7.116.1.json +26 -0
- package/wire-changes/server@7.117.0.json +65 -0
- package/wire-changes/server@7.118.0.json +129 -0
- package/wire-changes/server@7.119.0.json +65 -0
- package/wire-changes/server@7.120.0.json +89 -0
- package/wire-changes/server@7.121.0.json +219 -0
- package/wire-changes/server@7.122.0.json +54 -0
- package/wire-changes/server@7.123.0.json +26 -0
- package/wire-changes/server@7.124.0.json +336 -0
- package/wire-changes/server@7.124.1.json +26 -0
- package/wire-changes/server@7.125.0.json +111 -0
- package/wire-changes/server@7.126.0.json +285 -0
- package/wire-changes/server@7.127.0.json +77 -0
- package/wire-changes/server@7.127.1.json +26 -0
- package/wire-changes/server@7.127.2.json +53 -0
- package/wire-changes/server@7.128.0.json +26 -0
- package/wire-changes/server@7.129.0.json +106 -0
- package/wire-changes/server@7.129.1.json +26 -0
- package/wire-changes/server@7.130.0.json +26 -0
- package/wire-changes/server@7.131.0.json +118 -0
- package/wire-changes/server@7.132.0.json +226 -0
- package/wire-changes/server@7.133.0.json +1155 -0
- package/wire-changes/server@7.134.0.json +107 -0
- package/wire-changes/server@7.135.0.json +174 -0
- package/wire-changes/server@7.136.0.json +448 -0
- package/dist/url-credential.d.ts +0 -52
- package/dist/url-credential.js +0 -49
|
@@ -64,11 +64,14 @@ export interface ModelRouteEnvReading {
|
|
|
64
64
|
* 它只与网关端点配对(没有 {@link gatewayBaseUrl} 就不装载),配对由消费方判。
|
|
65
65
|
*/
|
|
66
66
|
readonly gatewayApiKey: string | undefined;
|
|
67
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL`:空串 = 未设,各自独立(一个空的不遮蔽另一个)。
|
|
69
|
+
* 两把凭据**各是各的头**(`x-api-key` / `Authorization: Bearer`),同设是起服拒启的形 —— 读数原样交出两把,取哪种头只问 {@link judgeAnthropicCredential}。
|
|
70
|
+
*/
|
|
68
71
|
readonly anthropicApiKey: string | undefined;
|
|
69
72
|
readonly anthropicAuthToken: string | undefined;
|
|
70
73
|
readonly anthropicBaseUrl: string | undefined;
|
|
71
|
-
/** anthropic 路由装不装 = 两把凭据任一在场(`createBrain` 同判)
|
|
74
|
+
/** anthropic 路由装不装 = 两把凭据任一在场(`createBrain` 同判);只读在场性(同设由起服拒启,不在读数里判)。 */
|
|
72
75
|
readonly anthropicRouteMounted: boolean;
|
|
73
76
|
/**
|
|
74
77
|
* env 腿模型的 provider 词:显式 `MODEL_PROVIDER` 胜(原样,**不在此过闭集** —— 域外拒启是 `model-provider-word` 那条不变量的事);
|
|
@@ -90,6 +93,47 @@ export declare const csvOf: (raw: string | undefined) => string[];
|
|
|
90
93
|
* `parseModelDomain`(起服铸 `ServiceConfig`)吃它的读数。
|
|
91
94
|
*/
|
|
92
95
|
export declare function readModelRouteEnv(env: ModelRouteEnv): ModelRouteEnvReading;
|
|
96
|
+
/**
|
|
97
|
+
* **anthropic 车道凭据的唯一判官**(一名一义):两个名字各走各的头、互斥 ——
|
|
98
|
+
* · `ANTHROPIC_API_KEY` ⇒ `x-api-key`(只发它);
|
|
99
|
+
* · `ANTHROPIC_AUTH_TOKEN` ⇒ `Authorization: Bearer`(只发它);
|
|
100
|
+
* · 两个都设 ⇒ `conflict`:两个名字说的是两种头,哪个赢都是替运维猜(7.135.0 及以前是「AUTH_TOKEN 优先」,x-api-key 被静默丢弃)⇒ 起服拒启,拒句 {@link anthropicCredentialRefusal}。
|
|
101
|
+
* 空串 = 未设(与 {@link readModelRouteEnv} 同尺)。入参是两个名字各自的值 —— env 读数的两位或 `config.anthropic` 的 `apiKey` / `authToken` —— 不读 `process.env`。
|
|
102
|
+
* 读者:起服(`config.ts` 的拒启锚与跨键不变量表 `anthropic-credential-exclusive` 同一句)· brain 装配(交引擎哪种头)· hook 直连腿(哪种头、交引擎配对判官的那份值)·
|
|
103
|
+
* 车道端口 {@link laneAndEndpointFor}(哪把键)· 起服的 Bearer 部署诊断(`boot/web-admin.ts`)。
|
|
104
|
+
*/
|
|
105
|
+
export type AnthropicCredentialVerdict = {
|
|
106
|
+
readonly kind: "absent";
|
|
107
|
+
} | {
|
|
108
|
+
readonly kind: "x-api-key";
|
|
109
|
+
readonly envName: typeof MODEL_ROUTE_ENV_KEYS.anthropicApiKey;
|
|
110
|
+
readonly value: string;
|
|
111
|
+
} | {
|
|
112
|
+
readonly kind: "bearer";
|
|
113
|
+
readonly envName: typeof MODEL_ROUTE_ENV_KEYS.anthropicAuthToken;
|
|
114
|
+
readonly value: string;
|
|
115
|
+
} | {
|
|
116
|
+
readonly kind: "conflict";
|
|
117
|
+
};
|
|
118
|
+
/** 判官的入参:两个名字各自的值(`config.anthropic` 的两位与 env 读数的两位都映射成这一形)。 */
|
|
119
|
+
export interface AnthropicCredentialNames {
|
|
120
|
+
readonly apiKey?: string | undefined;
|
|
121
|
+
readonly authToken?: string | undefined;
|
|
122
|
+
}
|
|
123
|
+
export declare function judgeAnthropicCredential(names: AnthropicCredentialNames): AnthropicCredentialVerdict;
|
|
124
|
+
/** 同设拒启的机读码(拒句方括号里)。 */
|
|
125
|
+
export declare const ANTHROPIC_CREDENTIAL_CONFLICT_CODE = "config.anthropic_credential_conflict";
|
|
126
|
+
/** {@link judgeAnthropicCredential} 的拒句投影:`conflict` ⇒ 一句点名两键与出路(不回显任何值);其余 ⇒ `undefined`。 */
|
|
127
|
+
export declare function anthropicCredentialRefusal(names: AnthropicCredentialNames): string | undefined;
|
|
128
|
+
/** 一份会上线的 anthropic 车道凭据(判官的两种头形)。 */
|
|
129
|
+
export type AnthropicLaneCredential = Extract<AnthropicCredentialVerdict, {
|
|
130
|
+
kind: "x-api-key" | "bearer";
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* 判官的**取值面**:这条车道会带上的那一份(头形 + 值);缺席 ⇒ `undefined`;同设 ⇒ **抛**拒句 ——
|
|
134
|
+
* 起服已在 `loadConfig` 拒启这一形,到得了这里的只有绕过起服装配、自拼配置的嵌入方(响亮,不替它挑一个)。
|
|
135
|
+
*/
|
|
136
|
+
export declare function anthropicLaneCredentialOf(names: AnthropicCredentialNames): AnthropicLaneCredential | undefined;
|
|
93
137
|
/**
|
|
94
138
|
* **env 腿的条目表** —— 主槽别名 `default` + 主槽 id(+ 铸出的 cheap 槽);没有 `MODEL_ID` ⇒ 空表(不铸占位条目:一个不存在的模型名
|
|
95
139
|
* 进可选目录 / 当缺省,正是 3.0.0 删掉的那种病)。`parseModelDomain` 铸真 `Model` 表与判官铸路由切面都经这一只,条目名与键序不会各写一份。
|
|
@@ -116,7 +160,7 @@ export interface LaneAndEndpoint {
|
|
|
116
160
|
readonly endpointDeclared: boolean;
|
|
117
161
|
/**
|
|
118
162
|
* 这条腿此刻真会带上的凭据那把 env 键;没有会装载的凭据 ⇒ `undefined`。
|
|
119
|
-
* · anthropic
|
|
163
|
+
* · anthropic 腿:设了哪一把就是哪一把(一名一义,{@link judgeAnthropicCredential} —— 引擎装配同一只判官),空串不遮蔽另一把;两把同设 ⇒ 抛起服那一句拒句;
|
|
120
164
|
* · 网关腿:`MODEL_API_KEY`,**只在端点声明时**(凭据只与网关自己的根配对;没有网关就不装载),空串 = 没有凭据(keyless 部署)。
|
|
121
165
|
*/
|
|
122
166
|
readonly apiKeyEnvName: ModelRouteEnvName | undefined;
|
|
@@ -128,7 +172,8 @@ export interface LaneAndEndpoint {
|
|
|
128
172
|
* 键名 = {@link MODEL_ROUTE_ENV_KEYS}。`routes` 是 core 路由表的原型(`Object.hasOwn(routes, 词)` 的表;`anthropic` 键在场 ⇔ anthropic 路由装上)。
|
|
129
173
|
* **只交键名不交值**:凭据与端点的值调用方自己从 env 取,本函数的答案里没有任何 env 值。
|
|
130
174
|
*
|
|
131
|
-
* 纯:不读 `process.env`,只按键表点名取值、不枚举入参。路由表里有本部署从不装的键(表在 `mountRoutes` 之外铸)⇒ 抛(`brainLaneFor` 的响亮臂)
|
|
175
|
+
* 纯:不读 `process.env`,只按键表点名取值、不枚举入参。路由表里有本部署从不装的键(表在 `mountRoutes` 之外铸)⇒ 抛(`brainLaneFor` 的响亮臂),不折网关;
|
|
176
|
+
* anthropic 腿两把凭据同设 ⇒ 抛起服的同一句拒句({@link anthropicLaneCredentialOf}:引擎在这一形上拒启,端口不替它答一把)。
|
|
132
177
|
*/
|
|
133
178
|
export declare function laneAndEndpointFor(env: ModelRouteEnv, model: ModelRouteSubject, routes: Readonly<Record<string, unknown>>): LaneAndEndpoint;
|
|
134
179
|
//# sourceMappingURL=model-route-gap.d.ts.map
|
package/dist/model-route-gap.js
CHANGED
|
@@ -56,6 +56,39 @@ export function readModelRouteEnv(env) {
|
|
|
56
56
|
: { kind: "minted", id: rawCheapId },
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
export function judgeAnthropicCredential(names) {
|
|
60
|
+
const K = MODEL_ROUTE_ENV_KEYS;
|
|
61
|
+
const apiKey = declaredValue(names.apiKey);
|
|
62
|
+
const authToken = declaredValue(names.authToken);
|
|
63
|
+
if (apiKey !== undefined && authToken !== undefined)
|
|
64
|
+
return { kind: "conflict" };
|
|
65
|
+
if (apiKey !== undefined)
|
|
66
|
+
return { kind: "x-api-key", envName: K.anthropicApiKey, value: apiKey };
|
|
67
|
+
if (authToken !== undefined)
|
|
68
|
+
return { kind: "bearer", envName: K.anthropicAuthToken, value: authToken };
|
|
69
|
+
return { kind: "absent" };
|
|
70
|
+
}
|
|
71
|
+
export const ANTHROPIC_CREDENTIAL_CONFLICT_CODE = "config.anthropic_credential_conflict";
|
|
72
|
+
export function anthropicCredentialRefusal(names) {
|
|
73
|
+
if (judgeAnthropicCredential(names).kind !== "conflict")
|
|
74
|
+
return undefined;
|
|
75
|
+
const K = MODEL_ROUTE_ENV_KEYS;
|
|
76
|
+
return (`[${ANTHROPIC_CREDENTIAL_CONFLICT_CODE}] both ${K.anthropicApiKey} and ${K.anthropicAuthToken} are set — they are two different credentials ` +
|
|
77
|
+
`(${K.anthropicApiKey} is sent as the x-api-key header, ${K.anthropicAuthToken} as Authorization: Bearer) and the Anthropic route carries exactly one; ` +
|
|
78
|
+
`keep the one your endpoint expects and unset the other`);
|
|
79
|
+
}
|
|
80
|
+
export function anthropicLaneCredentialOf(names) {
|
|
81
|
+
const verdict = judgeAnthropicCredential(names);
|
|
82
|
+
switch (verdict.kind) {
|
|
83
|
+
case "absent":
|
|
84
|
+
return undefined;
|
|
85
|
+
case "x-api-key":
|
|
86
|
+
case "bearer":
|
|
87
|
+
return verdict;
|
|
88
|
+
case "conflict":
|
|
89
|
+
throw new Error(anthropicCredentialRefusal(names));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
59
92
|
export function envLaneTable(mainId, main, cheap) {
|
|
60
93
|
if (mainId === "")
|
|
61
94
|
return {};
|
|
@@ -74,7 +107,7 @@ export function laneAndEndpointFor(env, model, routes) {
|
|
|
74
107
|
lane,
|
|
75
108
|
endpointEnvName: K.anthropicBaseUrl,
|
|
76
109
|
endpointDeclared: declaredRootUrl(reading.anthropicBaseUrl) !== undefined,
|
|
77
|
-
apiKeyEnvName:
|
|
110
|
+
apiKeyEnvName: anthropicLaneCredentialOf({ apiKey: reading.anthropicApiKey, authToken: reading.anthropicAuthToken })?.envName,
|
|
78
111
|
};
|
|
79
112
|
case "gateway": {
|
|
80
113
|
const endpointDeclared = declaredRootUrl(reading.gatewayBaseUrl) !== undefined;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two object-store buckets this server reads from and never creates (`docs/DEPLOY-PREREQS.md` "对象存储桶"), and the name each takes when its
|
|
3
|
+
* knob is unset — ONE spelling of each default. The config loader (`config.ts`), the config catalog's default notes, the boot presence check's role
|
|
4
|
+
* table (`plugins/snapshot-bucket-presence.ts`) and the k8s adapter's refusal sentence all read these constants; a literal copied into any of them is
|
|
5
|
+
* a second source that drifts the day a default changes (the refusal would then name a bucket the loader no longer defaults to).
|
|
6
|
+
*
|
|
7
|
+
* Pure leaf: no imports.
|
|
8
|
+
*/
|
|
9
|
+
/** `SESSION_SNAPSHOT_BUCKET` unset ⇒ this bucket: snapshot-BLOB offload, and the SendUserFile private presigned track / sandbox staging. */
|
|
10
|
+
export declare const SESSION_SNAPSHOT_BUCKET_DEFAULT = "session-snapshots";
|
|
11
|
+
/** `WORKSPACE_SNAPSHOT_BUCKET` unset ⇒ this bucket: the k8s lane's workspace snapshots (cross-run space snapshots and parked-run archives). */
|
|
12
|
+
export declare const WORKSPACE_SNAPSHOT_BUCKET_DEFAULT = "workspaces";
|
|
13
|
+
//# sourceMappingURL=object-store-buckets.d.ts.map
|
|
@@ -109,7 +109,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
109
109
|
};
|
|
110
110
|
readonly "server.elicitation.open-frame-undelivered": {
|
|
111
111
|
readonly cls: "F";
|
|
112
|
-
readonly note: "MCP elicitation 的 open 帧投递失败 ⇒
|
|
112
|
+
readonly note: "MCP elicitation 的 open 帧投递失败 ⇒ 按没人应答放掉(cancel)。方向本身是 fail-closed(问不到人就是没授予),缺的只是留痕。";
|
|
113
113
|
};
|
|
114
114
|
readonly "server.question.complete-breadcrumb-dropped": {
|
|
115
115
|
readonly cls: "F";
|
|
@@ -189,7 +189,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
189
189
|
};
|
|
190
190
|
readonly "server.approvals.park-row-blob-unreadable": {
|
|
191
191
|
readonly cls: "F";
|
|
192
|
-
readonly note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `
|
|
192
|
+
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 的摘要读不动它 ⇒ 只丢**这一行**的三位〔`boundGrantDigest` / `boundGrants` / `classifierNoRuling`〕,队列照常;`not-text` 同样原样抛)—— 计数非零的处置同上:去按 session 查那一行。";
|
|
193
193
|
};
|
|
194
194
|
readonly "server.approvals.durable-row-checkpoint-id-missing": {
|
|
195
195
|
readonly cls: "F";
|
|
@@ -373,7 +373,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
373
373
|
};
|
|
374
374
|
readonly "server.redact.ppk-eat-to-end": {
|
|
375
375
|
readonly cls: "F";
|
|
376
|
-
readonly note: "S-107 第三十二轮重扫:PuTTY .ppk 容器扫描器(redact.ts redactPpkContainers)在「无合格终止 / 收口后同容器范围再见私钥字段 / 收口后到下一版本头之间夹非空白」三形下从头**吃到输入末尾**(fail-closed 取证丢弃)——终态 errorMessage 座上=整条错误文案变成 «redacted:private-key»,与 redactions_applied_total{private-key}
|
|
376
|
+
readonly note: "S-107 第三十二轮重扫:PuTTY .ppk 容器扫描器(redact.ts redactPpkContainers)在「无合格终止 / 收口后同容器范围再见私钥字段 / 收口后到下一版本头之间夹非空白」三形下从头**吃到输入末尾**(fail-closed 取证丢弃)——终态 errorMessage 座上=整条错误文案变成 «redacted:private-key»,与 redactions_applied_total{private-key} 的诚实替换同形不可分,故要有自己的计数/探针;影子扫不计;出口座有界行的 head 读法(只扫一段头)上「窗内无合格终止」是终止可能在窗外的未决 —— 照样遮到窗尾,但不是兜底,不计;计数=多少次整段吃尾。";
|
|
377
377
|
};
|
|
378
378
|
readonly "server.approval-card.closed-word-out-of-set": {
|
|
379
379
|
readonly cls: "F";
|
|
@@ -391,9 +391,9 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
391
391
|
readonly cls: "F";
|
|
392
392
|
readonly note: "S-287(`plugins/ensure-index.ts` 的 PG 臂):这口 PG **协议**面不认 `CREATE INDEX CONCURRENTLY`。今天唯一的真消费者是**仓内离线镜像的手搓 `PgQueryFn` 假件**(`pg-mem` 不是本仓依赖,`test/memory-embedder-fingerprint.test.ts` 头注已为此记过一次档,这里不重复那个错)。判据是**能力面**不是名字,且**只认阳性信号**:SQLSTATE ∈ {`0A000` feature_not_supported、`42601` syntax_error},或错误**完全不带 `code`**(= 不是驱动也不是服务端给的错误)⇒ 判「不认」,回退成普通 `CREATE INDEX IF NOT EXISTS`;**带任何其它 `code` 的一律原样抛** —— SQLSTATE 的 `55P03`/`57014`/`23505`/`42501`/`25001` 与 libuv 的 `ECONNRESET`/`EPIPE`/`ETIMEDOUT` 都在这一侧(⚠️ 不要按「5 位大写」的形状去分这两族:`EPIPE` 恰好也是 5 位大写)。放行的最坏后果 = 这一次建索引持表级 `SHARE` 锁阻塞该表的写(纯**性能/可用性**面,索引本身照样建成、语义零差别),而能走到这条臂的面**按定义**不是生产 PG。计数非零 = 有一口本以为是真 PG 的部署其实不认 CONCURRENTLY,运维要去看它到底是什么。detail = `<表>.<索引名>`。";
|
|
393
393
|
};
|
|
394
|
-
readonly "server.assistant-inbox.objective-
|
|
394
|
+
readonly "server.assistant-inbox.objective-preview-unreadable": {
|
|
395
395
|
readonly cls: "F";
|
|
396
|
-
readonly note: "S-
|
|
396
|
+
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 不再读续跑上下文)。";
|
|
397
397
|
};
|
|
398
398
|
readonly "server.run-store.corrupt-record-skipped": {
|
|
399
399
|
readonly cls: "F";
|
|
@@ -473,7 +473,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
473
473
|
};
|
|
474
474
|
readonly "server.snapshot-bucket.presence-unproven": {
|
|
475
475
|
readonly cls: "F";
|
|
476
|
-
readonly note: "S-1195(7.119.0;`plugins/snapshot-bucket-presence.ts` 的 `ensureSnapshotBucket`,boot 期核一次快照桶 `SESSION_SNAPSHOT_BUCKET`;detail = `bucket=… endpoint=<buildDisplaySafeUrl 的显示形> <HTTP 状态 | request failed: 错类>`):presigned 列举对 `MINIO_ENDPOINT` **连不上 / 403 / 5xx / 没有 NoSuchBucket 的 404**,或探针到窗尾一次都没答过(detail 写 `probe still pending when the window ended`)⇒ **证明不了桶缺**,不拒启、照常起服(只有 404 + `NoSuchBucket` 才是「缺」,那一形窗内重试、到窗拒启,不走本 tag)。三问:①错误落到哪 —— 本 tag 的计数 / 探针行 / 记录器的一次性 warn,detail 带端点显示形与状态或错类;②谁受害 —— 桶其实不存在、或凭据不能列举的部署:之后每一次快照 offload 写与 SendUserFile 私有 presigned 请求会答 404 / 403,孤儿 sweep 每分钟一条失败,运维读到的是一串失败请求而不是「桶没建」(与 7.118.x 的既有形状同形,不是新损失);③缺席倒向哪边 —— 倒向**放行起服**:没有证据既不拒启、也不伪造「桶在场」或「桶缺」,不是门 / 权限 / 凭证。最坏后果 = 缺桶的部署晚一步才暴露;不放行的代价是对象存储一次抖动 / 一次 403 就让整只服务起不来。计数非零 = 这台部署启动时没能确认快照桶,按 detail 的端点与状态去核对网络 / 凭据 / 桶。";
|
|
476
|
+
readonly note: "S-1195(7.119.0;`plugins/snapshot-bucket-presence.ts` 的 `ensureSnapshotBucket`,boot 期核一次快照桶 `SESSION_SNAPSHOT_BUCKET`;S-2021〔7.136.0〕起同一只探针、同一条规则、同一个 tag 也核 k8s 车道的工作区快照桶 `WORKSPACE_SNAPSHOT_BUCKET`——detail 里的 `bucket=` 就是被核的那只桶名;detail = `bucket=… endpoint=<buildDisplaySafeUrl 的显示形> <HTTP 状态 | request failed: 错类>`):presigned 列举对 `MINIO_ENDPOINT` **连不上 / 403 / 5xx / 没有 NoSuchBucket 的 404**,或探针到窗尾一次都没答过(detail 写 `probe still pending when the window ended`)⇒ **证明不了桶缺**,不拒启、照常起服(只有 404 + `NoSuchBucket` 才是「缺」,那一形窗内重试、到窗拒启,不走本 tag)。三问:①错误落到哪 —— 本 tag 的计数 / 探针行 / 记录器的一次性 warn,detail 带端点显示形与状态或错类;②谁受害 —— 桶其实不存在、或凭据不能列举的部署:之后每一次快照 offload 写与 SendUserFile 私有 presigned 请求会答 404 / 403,孤儿 sweep 每分钟一条失败,运维读到的是一串失败请求而不是「桶没建」(与 7.118.x 的既有形状同形,不是新损失);工作区快照桶则是每条 run 读 `latest` 得 404/403——404 + NoSuchBucket 在运行期由 `workspace_snapshot_bucket_missing` 响亮拒绝,403/5xx 走既有的非 404 读失败臂(同样响亮);③缺席倒向哪边 —— 倒向**放行起服**:没有证据既不拒启、也不伪造「桶在场」或「桶缺」,不是门 / 权限 / 凭证。最坏后果 = 缺桶的部署晚一步才暴露;不放行的代价是对象存储一次抖动 / 一次 403 就让整只服务起不来。计数非零 = 这台部署启动时没能确认快照桶,按 detail 的端点与状态去核对网络 / 凭据 / 桶。";
|
|
477
477
|
};
|
|
478
478
|
readonly "server.fleet.serving-lease-unconfirmed": {
|
|
479
479
|
readonly cls: "R";
|
|
@@ -90,7 +90,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
90
90
|
},
|
|
91
91
|
"server.elicitation.open-frame-undelivered": {
|
|
92
92
|
cls: "F",
|
|
93
|
-
note: "MCP elicitation 的 open 帧投递失败 ⇒
|
|
93
|
+
note: "MCP elicitation 的 open 帧投递失败 ⇒ 按没人应答放掉(cancel)。方向本身是 fail-closed(问不到人就是没授予),缺的只是留痕。",
|
|
94
94
|
},
|
|
95
95
|
"server.question.complete-breadcrumb-dropped": {
|
|
96
96
|
cls: "F",
|
|
@@ -170,7 +170,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
170
170
|
},
|
|
171
171
|
"server.approvals.park-row-blob-unreadable": {
|
|
172
172
|
cls: "F",
|
|
173
|
-
note: "S-700(`plugins/checkpoint-store-sql.ts` 的 `
|
|
173
|
+
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 的摘要读不动它 ⇒ 只丢**这一行**的三位〔`boundGrantDigest` / `boundGrants` / `classifierNoRuling`〕,队列照常;`not-text` 同样原样抛)—— 计数非零的处置同上:去按 session 查那一行。",
|
|
174
174
|
},
|
|
175
175
|
"server.approvals.durable-row-checkpoint-id-missing": {
|
|
176
176
|
cls: "F",
|
|
@@ -334,7 +334,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
334
334
|
"server.run-terminal.output-truncated": { cls: "F", note: "S-107:持久 error 脱后 UTF-8 字节 > 65,000(TiDB TEXT 65,535 字节)⇒ 脱后切并带标记(切在占位里不是泄漏);计数=多少条终态文案被字节封顶截断" },
|
|
335
335
|
"server.runs.abort-cause-missing": { cls: "F", note: "S-947 候裁 ⑤(主会话裁:默认值保留,miss 臂必须响):续跑腿 `http/resume-legs.ts` 的 `checkpoint.resume_aborted` 臂 —— core 只在本腿递进去的信号**已中止**时铸该码,而那只信号唯一的写者是取消动词(快路 / 耐久旗轮询,句柄登记 `cancel_verb`),所以**只有 core 契约外的形**(桩 / 非 core Runner 直接抛该码,本腿句柄从未中止)才到得了「句柄上读不到成因」这一臂。取消终局照铸,成因取本腿唯一的中止词 `cancel_verb`(取消终局恒带成因由铸点签名保证,不让它缺);detail `task=<taskId>`;计数 = 多少次取消成因是默认值而不是句柄登记的。生产上恒零是证据,不归零 = 有一条不走 core 契约的 Runner 在跑续跑腿。" },
|
|
336
336
|
"server.runs.terminal-ledger-write-failed": { cls: "F", note: "S-107(全量门 silent-degradation 棘轮抓出的五处静默 `catch {}`):run 终局链里**账本腿**(flush 缓冲 text/reasoning、append `failed` 行)与终态翻转(setTerminal)已不共命运——账本 INSERT 抛不再让 run 卡 running 到 reaper;但那条抛掉的账本行之前是**静默**吞的。detail `arm=` 四臂(flush-clean-cancel / append-clean-cancel / flush-catch / append-thrown-cancel / append-failed);S-947 起续跑腿(`http/resume-legs.ts`)两座同 tag:resume-append-resume-aborted / resume-append-thrown-cancel(取消抛出两臂的 `failed` 行,修前那两臂根本不落账本终局行):缺的是 run_events 尾巴(缓冲文本或 failed 事件),run 行本身仍是 durable truth,读面/reaper 容忍缺失,故 F 类;计数=多少次终局账本写失败。" },
|
|
337
|
-
"server.redact.ppk-eat-to-end": { cls: "F", note: "S-107 第三十二轮重扫:PuTTY .ppk 容器扫描器(redact.ts redactPpkContainers)在「无合格终止 / 收口后同容器范围再见私钥字段 / 收口后到下一版本头之间夹非空白」三形下从头**吃到输入末尾**(fail-closed 取证丢弃)——终态 errorMessage 座上=整条错误文案变成 «redacted:private-key»,与 redactions_applied_total{private-key}
|
|
337
|
+
"server.redact.ppk-eat-to-end": { cls: "F", note: "S-107 第三十二轮重扫:PuTTY .ppk 容器扫描器(redact.ts redactPpkContainers)在「无合格终止 / 收口后同容器范围再见私钥字段 / 收口后到下一版本头之间夹非空白」三形下从头**吃到输入末尾**(fail-closed 取证丢弃)——终态 errorMessage 座上=整条错误文案变成 «redacted:private-key»,与 redactions_applied_total{private-key} 的诚实替换同形不可分,故要有自己的计数/探针;影子扫不计;出口座有界行的 head 读法(只扫一段头)上「窗内无合格终止」是终止可能在窗外的未决 —— 照样遮到窗尾,但不是兜底,不计;计数=多少次整段吃尾。" },
|
|
338
338
|
"server.approval-card.closed-word-out-of-set": {
|
|
339
339
|
cls: "F",
|
|
340
340
|
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=` 判别是哪一座;第四个成员是 `approval-content-kind.ts` 的 `readApprovalCard` —— 卡词 `approvalCard` 自己的闭集窄读,活 ask / LOCAL 店停驻门 / SQL 店读出的门子树三个载体共用一只,闭集 = core `TOOL_APPROVAL_CARDS`,detail 前缀 `approvalCard=`):活卡帧 / `card_json` / (S-700 起)运维队列行(`parkRowFacts` 读寄存行上的 park 孪生座;队列是热读面 ⇒ 同一行每读一次计一次)的一个**闭集词**座上,键在场而词不在本仓认得的那张表里(世代差,或第三方 producer)⇒ 该座**按缺席**处置。放行的最坏后果=卡上少一行「为什么这次没有规则候选」的解释(壳退回不显示该行),它**不改变任何裁决**——门在引擎里早已判完,本座是展示/观测面;反方向(把一个消费端词表外的值原样上卡)更坏:下游按闭集写的分支会落进 default 臂或渲染出生词。本臂存在的全部理由是**判别**:修前「上游发了个生词」与「上游根本没发这个键」在遥测上同形,而前者意味着本仓的词表该跟着 core 加词了(型面另有两向编译围栏,但那只在**重新编译**时说话,跑在线上的那一版不会自己红)。detail 带座名与那个词(经 redactSecrets 截 40);数 / 布尔等原始值原样,对象 / 数组 / 函数 / null 只报形名(`<object>` / `<array>` / `<function>` / `<null>`,S-700 codex r1:格式化从不调用值自己的转换方法 —— 持久层里一格 `{\"toString\":null}` 曾让诊断本身抛出、打掉整只队列)。",
|
|
@@ -351,9 +351,9 @@ export const FAIL_OPEN_TAGS = {
|
|
|
351
351
|
cls: "F",
|
|
352
352
|
note: "S-287(`plugins/ensure-index.ts` 的 PG 臂):这口 PG **协议**面不认 `CREATE INDEX CONCURRENTLY`。今天唯一的真消费者是**仓内离线镜像的手搓 `PgQueryFn` 假件**(`pg-mem` 不是本仓依赖,`test/memory-embedder-fingerprint.test.ts` 头注已为此记过一次档,这里不重复那个错)。判据是**能力面**不是名字,且**只认阳性信号**:SQLSTATE ∈ {`0A000` feature_not_supported、`42601` syntax_error},或错误**完全不带 `code`**(= 不是驱动也不是服务端给的错误)⇒ 判「不认」,回退成普通 `CREATE INDEX IF NOT EXISTS`;**带任何其它 `code` 的一律原样抛** —— SQLSTATE 的 `55P03`/`57014`/`23505`/`42501`/`25001` 与 libuv 的 `ECONNRESET`/`EPIPE`/`ETIMEDOUT` 都在这一侧(⚠️ 不要按「5 位大写」的形状去分这两族:`EPIPE` 恰好也是 5 位大写)。放行的最坏后果 = 这一次建索引持表级 `SHARE` 锁阻塞该表的写(纯**性能/可用性**面,索引本身照样建成、语义零差别),而能走到这条臂的面**按定义**不是生产 PG。计数非零 = 有一口本以为是真 PG 的部署其实不认 CONCURRENTLY,运维要去看它到底是什么。detail = `<表>.<索引名>`。"
|
|
353
353
|
},
|
|
354
|
-
"server.assistant-inbox.objective-
|
|
354
|
+
"server.assistant-inbox.objective-preview-unreadable": {
|
|
355
355
|
cls: "F",
|
|
356
|
-
note: "S-
|
|
356
|
+
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 不再读续跑上下文)。",
|
|
357
357
|
},
|
|
358
358
|
"server.run-store.corrupt-record-skipped": {
|
|
359
359
|
cls: "F",
|
|
@@ -433,7 +433,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
433
433
|
},
|
|
434
434
|
"server.snapshot-bucket.presence-unproven": {
|
|
435
435
|
cls: "F",
|
|
436
|
-
note: "S-1195(7.119.0;`plugins/snapshot-bucket-presence.ts` 的 `ensureSnapshotBucket`,boot 期核一次快照桶 `SESSION_SNAPSHOT_BUCKET`;detail = `bucket=… endpoint=<buildDisplaySafeUrl 的显示形> <HTTP 状态 | request failed: 错类>`):presigned 列举对 `MINIO_ENDPOINT` **连不上 / 403 / 5xx / 没有 NoSuchBucket 的 404**,或探针到窗尾一次都没答过(detail 写 `probe still pending when the window ended`)⇒ **证明不了桶缺**,不拒启、照常起服(只有 404 + `NoSuchBucket` 才是「缺」,那一形窗内重试、到窗拒启,不走本 tag)。三问:①错误落到哪 —— 本 tag 的计数 / 探针行 / 记录器的一次性 warn,detail 带端点显示形与状态或错类;②谁受害 —— 桶其实不存在、或凭据不能列举的部署:之后每一次快照 offload 写与 SendUserFile 私有 presigned 请求会答 404 / 403,孤儿 sweep 每分钟一条失败,运维读到的是一串失败请求而不是「桶没建」(与 7.118.x 的既有形状同形,不是新损失);③缺席倒向哪边 —— 倒向**放行起服**:没有证据既不拒启、也不伪造「桶在场」或「桶缺」,不是门 / 权限 / 凭证。最坏后果 = 缺桶的部署晚一步才暴露;不放行的代价是对象存储一次抖动 / 一次 403 就让整只服务起不来。计数非零 = 这台部署启动时没能确认快照桶,按 detail 的端点与状态去核对网络 / 凭据 / 桶。",
|
|
436
|
+
note: "S-1195(7.119.0;`plugins/snapshot-bucket-presence.ts` 的 `ensureSnapshotBucket`,boot 期核一次快照桶 `SESSION_SNAPSHOT_BUCKET`;S-2021〔7.136.0〕起同一只探针、同一条规则、同一个 tag 也核 k8s 车道的工作区快照桶 `WORKSPACE_SNAPSHOT_BUCKET`——detail 里的 `bucket=` 就是被核的那只桶名;detail = `bucket=… endpoint=<buildDisplaySafeUrl 的显示形> <HTTP 状态 | request failed: 错类>`):presigned 列举对 `MINIO_ENDPOINT` **连不上 / 403 / 5xx / 没有 NoSuchBucket 的 404**,或探针到窗尾一次都没答过(detail 写 `probe still pending when the window ended`)⇒ **证明不了桶缺**,不拒启、照常起服(只有 404 + `NoSuchBucket` 才是「缺」,那一形窗内重试、到窗拒启,不走本 tag)。三问:①错误落到哪 —— 本 tag 的计数 / 探针行 / 记录器的一次性 warn,detail 带端点显示形与状态或错类;②谁受害 —— 桶其实不存在、或凭据不能列举的部署:之后每一次快照 offload 写与 SendUserFile 私有 presigned 请求会答 404 / 403,孤儿 sweep 每分钟一条失败,运维读到的是一串失败请求而不是「桶没建」(与 7.118.x 的既有形状同形,不是新损失);工作区快照桶则是每条 run 读 `latest` 得 404/403——404 + NoSuchBucket 在运行期由 `workspace_snapshot_bucket_missing` 响亮拒绝,403/5xx 走既有的非 404 读失败臂(同样响亮);③缺席倒向哪边 —— 倒向**放行起服**:没有证据既不拒启、也不伪造「桶在场」或「桶缺」,不是门 / 权限 / 凭证。最坏后果 = 缺桶的部署晚一步才暴露;不放行的代价是对象存储一次抖动 / 一次 403 就让整只服务起不来。计数非零 = 这台部署启动时没能确认快照桶,按 detail 的端点与状态去核对网络 / 凭据 / 桶。",
|
|
437
437
|
},
|
|
438
438
|
"server.fleet.serving-lease-unconfirmed": {
|
|
439
439
|
cls: "R",
|
|
@@ -291,7 +291,7 @@ export function createMetrics() {
|
|
|
291
291
|
m.counter("permission_rule_events_total", buildPermissionRuleEventsHelp());
|
|
292
292
|
m.counter("compaction_events_total", "Compaction lifecycle events by outcome (started/completed/failed/skipped) and trigger");
|
|
293
293
|
m.counter("hook_llm_calls_total", "prompt/agent hook entries that completed a model call (hooks 3b), by type");
|
|
294
|
-
m.counter("auth_bridge_verify_total", "Registry SSO JWT verifications (auth-bridge), by outcome");
|
|
294
|
+
m.counter("auth_bridge_verify_total", "Registry SSO JWT verifications (auth-bridge), by outcome: 'ok', or the refusal word from one closed set (settings-schema api/auth-bridge AUTH_BRIDGE_ERROR_CODES + api/scopes TOKEN_SCOPE_REFUSALS); a refusal sets no identity");
|
|
295
295
|
m.counter("fleet_rows_reconciled_total", "Fleet rows the #261 liveness-reconcile leg acted on, by `disposition`: 'retired' = durable was terminal, the leg projected the settled pair (terminal task frame → task_remove); 'retired_deferred' = a row that had already left declaratively (removeReason:\"orphaned\") got its settled pair BACKFILLED once durable turned terminal; 'orphaned' / 'orphaned_child' = declarative exit, NO terminal was minted (the reaper owns the death ruling); 'workflow_retired' = same projection for a workflow row. `trigger` rides ONLY the retired_deferred series (S-450): 'event' = the backfill fired on the same tick a terminal write landed through the run-store write口 (single replica), 'cycle' = it fired on the 60s reconcile cycle (cross-replica writes, and terminals flipped by the BATCH reapers, which never pass through the write口). A retired_deferred series that is 100% trigger=cycle means the event leg is not wired or this deployment\'s terminals all come from those two families");
|
|
296
296
|
m.counter("fleet_lease_issued_total", "Fleet trace-lease tokens issued");
|
|
297
297
|
m.counter("fleet_lease_rejected_total", "Fleet trace-lease requests rejected");
|
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
9
|
export declare const principalContext: AsyncLocalStorage<string>;
|
|
10
|
-
/**
|
|
10
|
+
/** 这次执行的记账身份钉表;不在任何 {@link withPrincipal} 作用域里 ⇒ `undefined`(记账按此刻身份)。 */
|
|
11
|
+
export declare function currentExecutionPins(): Map<object, string> | undefined;
|
|
12
|
+
/** Run `fn` with `principal` as the ambient context (principal-wise a no-op wrapper when principal is undefined — the outer
|
|
13
|
+
* principal, if any, stays). [ref]: also opens the execution's accounting-pin scope when none is open yet (nested calls share it). */
|
|
11
14
|
export declare function withPrincipal<T>(principal: string | undefined, fn: () => T): T;
|
|
12
15
|
/** The principal attributed to the current async execution, if any. */
|
|
13
16
|
export declare function currentPrincipal(): string | undefined;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
export const principalContext = new AsyncLocalStorage();
|
|
3
|
+
const executionPins = new AsyncLocalStorage();
|
|
4
|
+
export function currentExecutionPins() {
|
|
5
|
+
return executionPins.getStore();
|
|
6
|
+
}
|
|
3
7
|
export function withPrincipal(principal, fn) {
|
|
4
|
-
|
|
8
|
+
const run = () => (principal ? principalContext.run(principal, fn) : fn());
|
|
9
|
+
return executionPins.getStore() !== undefined ? run() : executionPins.run(new Map(), run);
|
|
5
10
|
}
|
|
6
11
|
export function currentPrincipal() {
|
|
7
12
|
return principalContext.getStore();
|
package/dist/parked-decide.d.ts
CHANGED
|
@@ -142,9 +142,10 @@ export declare function findParkedAgentForCheckpoint(agentStore: BackgroundAgent
|
|
|
142
142
|
}): Promise<ParkedAgentMatch | undefined>;
|
|
143
143
|
export interface ParkedDecideDeps {
|
|
144
144
|
agentStore: BackgroundAgentStore;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
registry
|
|
145
|
+
/** `expire`:[ref] deny 作废复活不了的卡(按卡自己的 scope CAS);`get`:引擎的 claim / 对账读卡。 */
|
|
146
|
+
checkpointStore: Pick<CheckpointStore, "get" | "expire">;
|
|
147
|
+
/** 与 reaper/scenarios 同一个 registry(claim/rollback 的 CAS 与 in-memory handle 收敛在同处;[ref] 作废之后的对账也是它)。 */
|
|
148
|
+
registry: Pick<TaskRegistry, "claimParkedAgent" | "rollbackParkedClaim" | "reconcileParkedAgents">;
|
|
148
149
|
/** [ref](core 7.32.0):按**行**解析赎回面 —— 驱动哪一只 Agent 工具(生产装配,与 spawn 同源:subRunner / bg opts /
|
|
149
150
|
* checkpointStore 同实例,[ref] 设计稿 §4),以及与它同出一张列表的继承座 `mountsCallerTool`(一层行才有;属主与全部判据
|
|
150
151
|
* 在 `parked-revive-surface.ts`)。修前是 boot 期的一只裸 Agent 工具、从不交座 ⇒ 7.32.0 起停在继承工具上的 allow 恒 422。 */
|
package/dist/parked-decide.js
CHANGED
|
@@ -231,6 +231,28 @@ function sessionGone(taskId) {
|
|
|
231
231
|
}),
|
|
232
232
|
};
|
|
233
233
|
}
|
|
234
|
+
function revivabilityOf(row, taskId) {
|
|
235
|
+
if (row.name === undefined) {
|
|
236
|
+
return { kind: "unrevivable", approveRefusal: { status: 409, body: refusalBody({ errorCode: "decide.row_unrevivable", message: "parked row carries no agent name — the revive path requires a named agent, so this approval cannot be approved; deny it to close the card (the agent then ends as failed)", facts: { taskId } }) } };
|
|
237
|
+
}
|
|
238
|
+
if (row.rootSessionId === undefined) {
|
|
239
|
+
return { kind: "unrevivable", approveRefusal: { status: 409, body: refusalBody({ errorCode: "decide.row_unrevivable", message: "this agent's row carries no root session anchor — the revive path cannot tell which session this approval belongs to, so it cannot be approved; deny it to close the card (the agent then ends as failed)", facts: { taskId } }) } };
|
|
240
|
+
}
|
|
241
|
+
return { kind: "revivable", root: row.rootSessionId };
|
|
242
|
+
}
|
|
243
|
+
async function voidUnrevivableCard(deps, req, match) {
|
|
244
|
+
const voided = await deps.checkpointStore.expire(req.token, req.scope);
|
|
245
|
+
if (!voided) {
|
|
246
|
+
return { status: 409, body: refusalBody({ errorCode: "decide.gate_moved", message: "the approval gate moved under this decide (re-parked or already settled) — re-check the pending list", facts: { taskId: match.handle } }) };
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
await deps.registry.reconcileParkedAgents({ agentStore: deps.agentStore, checkpointStore: deps.checkpointStore }, match.row.scope, Date.now());
|
|
250
|
+
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
quiet(deps.warn, "parked_unrevivable_reconcile_failed", { taskId: match.handle, error: e instanceof Error ? e.message : String(e) });
|
|
253
|
+
}
|
|
254
|
+
return { status: 200, body: { taskId: match.handle, status: "failed", decision: "deny" } };
|
|
255
|
+
}
|
|
234
256
|
export async function decideParkedAgent(deps, req, match) {
|
|
235
257
|
const row = match.row;
|
|
236
258
|
const rememberRoot = req.grantRemember !== undefined ? grantRootOf(row) : undefined;
|
|
@@ -241,13 +263,10 @@ export async function decideParkedAgent(deps, req, match) {
|
|
|
241
263
|
if (pendingTool === ASK_USER_QUESTION_TOOL_NAME && req.decision === "approve" && req.answer === undefined) {
|
|
242
264
|
return { status: 400, body: refusalBody({ errorCode: "decide.parked_answer_required", message: "pending action is AskUserQuestion — approve requires body.answer (the operator's answers[]); deny needs none", facts: { taskId: match.handle } }) };
|
|
243
265
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const root =
|
|
248
|
-
if (root === undefined) {
|
|
249
|
-
return { status: 409, body: refusalBody({ errorCode: "decide.row_unrevivable", message: "this agent's row carries no root session anchor — the revive path cannot tell which session this approval belongs to (row damaged?)", facts: { taskId: match.handle } }) };
|
|
250
|
-
}
|
|
266
|
+
const revivability = revivabilityOf(row, match.handle);
|
|
267
|
+
if (revivability.kind === "unrevivable")
|
|
268
|
+
return req.decision === "deny" ? voidUnrevivableCard(deps, req, match) : revivability.approveRefusal;
|
|
269
|
+
const root = revivability.root;
|
|
251
270
|
const faceBefore = sessionFaceOfHead(root, await deps.headOf(root));
|
|
252
271
|
if (faceBefore === undefined)
|
|
253
272
|
return sessionGone(match.handle);
|
package/dist/peer-directory.d.ts
CHANGED
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
* · `sessionId` = 会话行 id;过不了 core `isPeerSessionId` 的行、以及**箱句柄不是本 scope 独占**的行
|
|
51
51
|
* (非小写规范形 / 与别的会话折到同一只箱)**不入视图并计数披露**(不静默,见下方单射门);
|
|
52
52
|
* · `scope` = 查询参数原样(视图永不跨 scope —— 这就是设计稿 §4-3 那堵墙的全部实现);
|
|
53
|
-
* · `name` = `title
|
|
53
|
+
* · `name` = `title`,「空」= 经 core 的 `normalizePeerName` 为空(NFKC → 去控制 / 格式码点 → trim;纯空白、纯零宽 / 方向控制符都算空)⇒ `session-<id 前 8>`,
|
|
54
|
+
* `nameSource: "auto"`;墓碑行的 `label` 同一条判据;
|
|
54
55
|
* · `startedAt`/`updatedAt` = 会话行的 `firstActivityAt`/`lastActivityAt`;
|
|
55
56
|
* · `liveness` = **会话行在 ⇒ `"live"`**;`"deleted"` 来自 mailbox 墓碑(= 删除级联**在飞**那段窗口;
|
|
56
57
|
* 墓碑随箱亡,级联跑完之后那个 id 就是「不存在」—— 理由全文在 `plugins/mailbox-recipient-lifecycle.ts`),
|
package/dist/peer-directory.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { PEER_SESSION_RECORD_SCHEMA_VERSION, isPeerSessionId, peerSessionBoxHandle, SESSION_BOX_PREFIX, } from "@sema-agent/core";
|
|
1
|
+
import { PEER_SESSION_RECORD_SCHEMA_VERSION, isPeerSessionId, normalizePeerName, peerSessionBoxHandle, SESSION_BOX_PREFIX, } from "@sema-agent/core";
|
|
2
2
|
import { sessionTempoOfRunStatus } from "./plugins/store-contracts.js";
|
|
3
3
|
import { legacyUnownedAmnestyOpen } from "./security.js";
|
|
4
4
|
export const PEER_DIRECTORY_CAP = 200;
|
|
5
|
-
function
|
|
6
|
-
return `session-${sessionId.slice(0, 8)}`;
|
|
5
|
+
function displayNameOf(candidate, sessionId) {
|
|
6
|
+
return candidate != null && normalizePeerName(candidate) !== "" ? candidate : `session-${sessionId.slice(0, 8)}`;
|
|
7
7
|
}
|
|
8
8
|
function sessionIdOfBoxHandle(handle) {
|
|
9
9
|
return handle.slice(SESSION_BOX_PREFIX.length);
|
|
@@ -80,7 +80,7 @@ export function createPeerDirectory(ctx) {
|
|
|
80
80
|
schemaVersion: PEER_SESSION_RECORD_SCHEMA_VERSION,
|
|
81
81
|
sessionId: r.sessionId,
|
|
82
82
|
scope,
|
|
83
|
-
name:
|
|
83
|
+
name: displayNameOf(r.title, r.sessionId),
|
|
84
84
|
nameSource: "auto",
|
|
85
85
|
startedAt: Number.isFinite(started) ? started : 0,
|
|
86
86
|
updatedAt: Number.isFinite(updated) ? updated : 0,
|
|
@@ -120,7 +120,7 @@ export function createPeerDirectory(ctx) {
|
|
|
120
120
|
schemaVersion: PEER_SESSION_RECORD_SCHEMA_VERSION,
|
|
121
121
|
sessionId,
|
|
122
122
|
scope,
|
|
123
|
-
name:
|
|
123
|
+
name: displayNameOf(t.label, sessionId),
|
|
124
124
|
nameSource: "auto",
|
|
125
125
|
startedAt: t.retiredAt,
|
|
126
126
|
updatedAt: t.retiredAt,
|
|
@@ -428,6 +428,14 @@ export interface BatchRow {
|
|
|
428
428
|
export type AskCallCoordinate = Pick<AskRow, "taskId" | "legKey" | "toolCallId" | "sourceTaskId">;
|
|
429
429
|
/** 「这一行在这次调用上」的唯一判据(四列逐字相等):InMemory twin 的筛子与 SQL twin 的出口对齐读同一只。 */
|
|
430
430
|
export declare function askRowOnCall(row: AskRow, call: AskCallCoordinate): boolean;
|
|
431
|
+
/**
|
|
432
|
+
* 🔴 [ref] —— **一只问的属主判据**(全仓唯一;两扇决议口 —— live 应答口 `POST /v1/tool-approvals/:id/respond`、耐久决断口
|
|
433
|
+
* `POST /v1/tasks/:taskId/asks/:askId/decision` —— 与按问读口都调它):调用方是不是这只问的属主。`owner` 只有一条来源律:有行的问读行上
|
|
434
|
+
* **当下的** `owner` 列(铸行写定,只有 `/v1/adoption` 改写它;进程内任何快照 —— 包括登记在铸卡那一刻记下的那一格 —— 都改不动);
|
|
435
|
+
* 没有行的问(问账没上场 / 旧族腿)只有登记记下的那一位可读。`null` = auth-off 单用户行,恒过。
|
|
436
|
+
* 门判过的那位属主再交给决议 CAS 的作用域({@link askRowCarriesOwner},[ref])。耐久决断口的 operator 越域臂不在这里 —— 那是那扇口自己的授权门。
|
|
437
|
+
*/
|
|
438
|
+
export declare function askOwnerAdmits(owner: string | null, principal: string | undefined): boolean;
|
|
431
439
|
/**
|
|
432
440
|
* 🔴 [ref] —— **决议作用域的属主维**:这一行此刻带着的属主,是不是这次决议的门判过的那一位(逐字相等;`null` 只等于 `null`)。
|
|
433
441
|
*
|
|
@@ -89,6 +89,9 @@ export function projectAskTerminalClaimTruth(row) {
|
|
|
89
89
|
export function askRowOnCall(row, call) {
|
|
90
90
|
return row.taskId === call.taskId && row.legKey === call.legKey && row.toolCallId === call.toolCallId && row.sourceTaskId === call.sourceTaskId;
|
|
91
91
|
}
|
|
92
|
+
export function askOwnerAdmits(owner, principal) {
|
|
93
|
+
return owner === null || owner === principal;
|
|
94
|
+
}
|
|
92
95
|
export function askRowCarriesOwner(row, owner) {
|
|
93
96
|
return row !== null && row.owner === owner;
|
|
94
97
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { presignS3Url, presignS3ListUrl } from "./s3-presign.js";
|
|
3
|
+
import { isNoSuchBucketAnswer } from "./s3-answer.js";
|
|
3
4
|
import { connectJudged, mysqlDriver, packetWallStatementBytes, pgDriver, rowWallPayloadBytes, sqlWallsOf } from "./sql-driver.js";
|
|
4
5
|
import { createLogger } from "../observability/logger.js";
|
|
5
6
|
const BLOB_GC_GRACE_MS = 3_600_000;
|
|
@@ -328,7 +329,7 @@ export class MinioBlobBackend {
|
|
|
328
329
|
if (res.ok)
|
|
329
330
|
return { state: "present" };
|
|
330
331
|
const body = await res.text().catch(() => "");
|
|
331
|
-
if (res.status
|
|
332
|
+
if (isNoSuchBucketAnswer(res.status, body))
|
|
332
333
|
return { state: "missing" };
|
|
333
334
|
return { state: "unknown", detail: `HTTP ${res.status}` };
|
|
334
335
|
}
|
|
@@ -10,12 +10,19 @@
|
|
|
10
10
|
* 不在这里的:CAS 面推动的状态(`status` / `rev` / `reopen_reason` / 执行记录)、部署铸的值(`terminal_at_ms` 兜底)、部署截长脱敏的展示投影(`tool_input` /
|
|
11
11
|
* `rule_suggestions`)—— 它们不是行的不变事实,core 也不答。
|
|
12
12
|
*
|
|
13
|
+
* ## 写之前:一只判官 = {@link judgeCheckpointIndexCells}
|
|
14
|
+
* 一份文档能不能落进这些列,在写之前由**同一只**判官答 —— 写口 `put` 与 M29 的存量回填都问它,界不抄第二份。三个答案:`cells`(放得下,列格在手);`unreadable`(门或待决动作
|
|
15
|
+
* 不是对象 —— core 的派生按这两棵读,读不了会抛裸 TypeError,或对非对象照写出垃圾列格;引擎的 `judgeAsStored` 在 put 之前拦着,所以这样的文档只来自嵌入方 / 手改数据);
|
|
16
|
+
* `card_too_long`(卡词的 UTF-8 字节超出方言的列容量 {@link APPROVAL_CARD_COLUMN_MAX_BYTES} —— 严格 sql_mode 下库抛 `Data too long`,非严格下静默截成半只卡词,两形都不许到库)。
|
|
17
|
+
* 写口把后两个答案翻成类型化拒 {@link CheckpointIndexRefusedError}(零写);M29 把它们记成收据(计数 + 点名,不挡起服)。
|
|
18
|
+
*
|
|
13
19
|
* ## 读:到期 facet 是由 core 两张表**生成**的一条 SQL 表达式
|
|
14
20
|
* facet = 部署收割器对一行的 deadline 的读法(`A` = 审批门,deadline 是 SLA 拒;`B` = 无人值守 TTL,到期作废;`-` = 非门停驻)。core 的判官是
|
|
15
21
|
* `facetOf(gate)`:门上的卡是 `CARD_FACET_OVERRIDES` 的键 ⇒ 那个键的 facet,否则门型在 `PAUSE_REGISTRY` 的 `facet` 列。列上存的是卡词本身
|
|
16
22
|
* (`approval_card`,不是 facet —— 存一份 facet 会在 core 改表那天陈旧),谓词由那两张表机械生成({@link CHECKPOINT_FACET_CASES} → {@link CHECKPOINT_FACET_SQL}),
|
|
17
23
|
* 逐行与 `facetOf` 同答(`test/checkpoint-index-columns.test.ts` B 节、db 组同名文件)。本仓不写第二份判据:没有手写门型表、没有手写卡词。
|
|
18
24
|
* 卡那一侧不带「是不是审批门」的合取:列上的卡只在审批门上非 NULL(同一只派生),与 core 对生成谓词的成文形逐字相同。未登记门型 / NULL 门型 ⇒ 表达式 NULL(无 ELSE)。
|
|
25
|
+
* 拒扫腿的选行序见 {@link CHECKPOINT_SWEEP_ORDER_SQL}:卡列有词的行先取 —— 混跑窗里旧副本写的行卡列为空,它们的 facet 要等下一次起服的 M29 才确证。
|
|
19
26
|
*
|
|
20
27
|
* ## 谓词什么时候开
|
|
21
28
|
* core 的迁移条款:存量行的卡列由同一只函数回填,并且只在部署自己记下「回填跑完了」之后才开生成谓词。本仓的记录 = 起服序列:M29 跑在一次性迁移段
|
|
@@ -54,9 +61,45 @@ export declare function buildCheckpointIndexCells(cp: Checkpoint): CheckpointInd
|
|
|
54
61
|
* `approval_card` 列放得下的卡词**字节数**(UTF-8 字节,不是字符数),按方言各一格(键表对 {@link SqlDialect} 闭合:加一种方言 ⇒ 编译红)。
|
|
55
62
|
* MySQL 协议(TiDB / MySQL)的列型是 `TEXT`,上限 65,535 字节 —— 严格模式下超长写入抛 `Data too long`,非严格模式静默截成半只卡词;PG 的 `TEXT` 没有这个上限。
|
|
56
63
|
* 列型的属主是中央 DDL(`tidb-pool.ts` / `pg-pool.ts` 的 `approval_card`),本表只是那一列的容量事实(`test/checkpoint-index-columns.test.ts` 把两处同读,换列型 ⇒ 红)。
|
|
57
|
-
* 引擎照存集外词、长度不由本仓定,但引擎铸得出的卡词是闭集短词 —— 超出容量的只会是手改 /
|
|
64
|
+
* 引擎照存集外词、长度不由本仓定,但引擎铸得出的卡词是闭集短词 —— 超出容量的只会是手改 / 外来写者写下的文档;读这张表的只有 {@link judgeCheckpointIndexCells}
|
|
65
|
+
* (写口超出 ⇒ 类型化拒,M29 超出 ⇒ 计数 + 点名跳过、不挡起服)。
|
|
58
66
|
*/
|
|
59
67
|
export declare const APPROVAL_CARD_COLUMN_MAX_BYTES: Readonly<Record<SqlDialect, number>>;
|
|
68
|
+
/**
|
|
69
|
+
* 一份文档对索引列的判决(闭集:加一种答案 ⇒ 读它的 `switch` 编译红)。
|
|
70
|
+
* · `cells` —— 放得下,列格在手;
|
|
71
|
+
* · `unreadable` —— `member` 指的那一棵(`gate` / `pendingAction`)不是对象:core 的派生读不了它;
|
|
72
|
+
* · `card_too_long` —— 门上的卡词按 UTF-8 字节超出方言的列容量(`bytes` > `maxBytes`)。
|
|
73
|
+
*/
|
|
74
|
+
export type CheckpointIndexJudgement = {
|
|
75
|
+
readonly kind: "cells";
|
|
76
|
+
readonly cells: CheckpointIndexCells;
|
|
77
|
+
} | {
|
|
78
|
+
readonly kind: "unreadable";
|
|
79
|
+
readonly member: "gate" | "pendingAction";
|
|
80
|
+
} | {
|
|
81
|
+
readonly kind: "card_too_long";
|
|
82
|
+
readonly bytes: number;
|
|
83
|
+
readonly maxBytes: number;
|
|
84
|
+
};
|
|
85
|
+
/** 不是 `cells` 的两个答案 —— 写口把它们带进 {@link CheckpointIndexRefusedError}。 */
|
|
86
|
+
export type CheckpointIndexRefusal = Exclude<CheckpointIndexJudgement, {
|
|
87
|
+
readonly kind: "cells";
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* **写之前**的唯一判官(写口 `put` 与 M29 回填共读;理由见头注「写之前」)。先看门与待决动作是不是对象 —— `Checkpoint` 的类型说它们必填,但嵌入方 /
|
|
91
|
+
* 手改数据不受类型约束,而 core 的 `checkpointIndexFacts` 对缺门 / 缺待决动作抛裸 TypeError、对非对象的门写出 `gate_kind` 为 undefined 的列格 ——
|
|
92
|
+
* 再派生,最后按方言的列容量数卡词的 UTF-8 **字节**(不是字符数)。纯函数:不读钟、不写任何东西。
|
|
93
|
+
*/
|
|
94
|
+
export declare function judgeCheckpointIndexCells(cp: Checkpoint, dialect: SqlDialect): CheckpointIndexJudgement;
|
|
95
|
+
/**
|
|
96
|
+
* 写口 `put` 对一份放不进索引列的文档的拒(类型化,零写;`refusal` 是机读位,与 M29 收据读的是同一个判决)。这是店错误,不是 wire 码 —— 调用方(引擎的停驻写、嵌入方)
|
|
97
|
+
* 怎么收场由它们决定;句子不带卡词本身(卡词是外来数据,只报字节数)。
|
|
98
|
+
*/
|
|
99
|
+
export declare class CheckpointIndexRefusedError extends Error {
|
|
100
|
+
readonly refusal: CheckpointIndexRefusal;
|
|
101
|
+
constructor(sessionId: unknown, refusal: CheckpointIndexRefusal);
|
|
102
|
+
}
|
|
60
103
|
/** facet 的词(core 登记表 `facet` 列的值域)。 */
|
|
61
104
|
type Facet = (typeof PAUSE_REGISTRY)[GateKind]["facet"];
|
|
62
105
|
/** 生成谓词的一条 WHEN:某一列的值落在这几个词里 ⇒ 这个 facet。 */
|
|
@@ -77,5 +120,11 @@ export declare const CHECKPOINT_FACET_CASES: readonly FacetCase[];
|
|
|
77
120
|
* 列名不带表限定:两条读腿都只查 `checkpoint` 一张表。拒扫腿读 `= 'A'`,收割的作废分支读 `COALESCE(…, '') <> 'A'`(NULL 门型的行走作废,与修前同向)。
|
|
78
121
|
*/
|
|
79
122
|
export declare const CHECKPOINT_FACET_SQL: Readonly<Record<SqlDialect, string>>;
|
|
123
|
+
/**
|
|
124
|
+
* SLA 拒扫腿(`listExpiredApprovalGates`)的选行序:**卡列有词的行先取**,其后 deadline、token。卡列为 NULL 的审批行有两种来历 —— 引擎没给卡的门(照常是审批 SLA),或混跑窗里
|
|
125
|
+
* 不认这一列的旧副本写的行(可能是引擎要拒收 `sla_timeout` 的问答卡,facet 要等下一次起服的 M29 回填才确证);列上没有任何东西能把两者分开,所以不在谓词里猜,而在序里:
|
|
126
|
+
* 有卡词的行 facet 已确证,先占窗;卡列为空的行排在它们之后,各自仍按 deadline 升序。LIMIT 仍是调用方的界,不加旋钮。两方言同一句(`CASE` 在 MySQL 协议与 PG 上同形)。
|
|
127
|
+
*/
|
|
128
|
+
export declare const CHECKPOINT_SWEEP_ORDER_SQL = "CASE WHEN approval_card IS NULL THEN 1 ELSE 0 END ASC, deadline ASC, token ASC";
|
|
80
129
|
export {};
|
|
81
130
|
//# sourceMappingURL=checkpoint-index-columns.d.ts.map
|