@sema-agent/server 7.149.0 → 7.150.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 +122 -9
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +39 -15
- package/dist/approval-card.d.ts +1 -1
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +61 -25
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/session-faces.js +21 -21
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-06-runners.js +1 -2
- package/dist/boot/stage-07-capability-layer.js +1 -1
- package/dist/boot/stage-10-http-server.d.ts +33 -1
- package/dist/boot/stage-10-http-server.js +9 -4
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/capability-facts.d.ts +65 -56
- package/dist/capability-facts.js +42 -35
- package/dist/config-catalog.js +1 -1
- package/dist/config-types.d.ts +12 -11
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +64 -28
- package/dist/device-ws-protocol.d.ts +20 -6
- package/dist/device-ws-protocol.js +9 -2
- package/dist/engine-identity.d.ts +7 -1
- package/dist/engine-identity.js +5 -0
- package/dist/field-conflict.d.ts +2 -2
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +2 -2
- package/dist/http/approval-sweeps.js +2 -1
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +18 -63
- package/dist/http/checkpoint-ctx.js +1 -24
- package/dist/http/claim-heartbeat.d.ts +4 -4
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/dispatch.js +2 -2
- package/dist/http/durable-run-leg.js +4 -4
- package/dist/http/owner-access.d.ts +243 -19
- package/dist/http/owner-access.js +184 -5
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.js +16 -1
- package/dist/http/resume-legs.js +18 -14
- package/dist/http/route-ctx.d.ts +23 -11
- package/dist/http/routes/a2a-serve.js +15 -14
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +8 -9
- package/dist/http/routes/capabilities.js +4 -3
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/projects.d.ts +1 -0
- package/dist/http/routes/projects.js +5 -3
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +23 -30
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.js +3 -7
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +18 -44
- package/dist/http/routes/tasks.js +9 -8
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +8 -4
- package/dist/http/server.js +5 -1
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +1 -2
- package/dist/http/submit-ctx.js +3 -2
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/leader/endpoint.js +9 -8
- package/dist/leg-facts.d.ts +8 -2
- package/dist/leg-facts.js +1 -0
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +5 -5
- package/dist/observability/fail-open.js +5 -5
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/owner-faces.d.ts +27 -3
- package/dist/owner-faces.js +2 -0
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/local-checkpoint-store.d.ts +4 -1
- package/dist/plugins/local-checkpoint-store.js +3 -0
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/one-time-migrations.d.ts +74 -49
- package/dist/plugins/one-time-migrations.js +134 -69
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/posix-shell-fs.js +4 -2
- package/dist/plugins/remote-env-adb.js +3 -2
- package/dist/plugins/remote-env-device.js +8 -6
- package/dist/plugins/remote-env-e2b.d.ts +3 -1
- package/dist/plugins/remote-env-e2b.js +11 -8
- package/dist/plugins/remote-env-host.d.ts +1 -1
- package/dist/plugins/remote-env-host.js +20 -11
- package/dist/plugins/remote-env-k8s.js +3 -2
- package/dist/plugins/remote-env-local-docker.js +3 -2
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/remote-shell.d.ts +3 -1
- package/dist/plugins/remote-shell.js +3 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +6 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +7 -5
- package/dist/plugins/schema-consistency.d.ts +7 -5
- package/dist/plugins/schema-consistency.js +29 -16
- package/dist/plugins/schema-drift-sentence.js +1 -1
- package/dist/plugins/serving-requirement.d.ts +49 -0
- package/dist/plugins/serving-requirement.js +53 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +42 -3
- package/dist/plugins/stop-then-start-sentence.js +44 -0
- package/dist/plugins/store-backend.d.ts +1 -1
- package/dist/plugins/store-contracts.d.ts +12 -2
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/tidb-pool.js +4 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +66 -0
- package/dist/project-context.js +70 -0
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/run-cancel-card.d.ts +1 -1
- package/dist/run-cancel-card.js +2 -1
- package/dist/security.d.ts +1 -1
- package/dist/session-agent.d.ts +1 -10
- package/dist/session-agent.js +0 -6
- package/dist/session-incarnation.d.ts +18 -4
- package/dist/session-incarnation.js +4 -1
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync.js +3 -3
- package/dist/stores-sql/checkpoint-store-sql.d.ts +21 -2
- package/dist/stores-sql/checkpoint-store-sql.js +106 -18
- package/dist/stores-sql/retention-store-sql.d.ts +1 -1
- package/dist/task-cwd.d.ts +4 -3
- package/dist/task-settings.d.ts +13 -0
- package/dist/task-settings.js +13 -7
- package/dist/tool-approval.d.ts +7 -6
- package/dist/tool-approval.js +41 -37
- package/dist/trace/engine-notice-wire.d.ts +14 -0
- package/dist/trace/engine-notice-wire.js +18 -1
- package/dist/trace/project.d.ts +4 -3
- package/dist/trace/project.js +3 -2
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/self-minted-wire.d.ts +150 -17
- package/dist/trace/self-minted-wire.js +54 -16
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
- package/package.json +2 -2
- package/wire-changes/server@7.150.0.json +335 -0
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ## 判定(三条,按序;别的一律不放)
|
|
11
11
|
* · 这次提交自带 taskId 而命中的行**不是**那一条(`Idempotency-Key` 指向别的行)⇒ 冲突;
|
|
12
|
-
* · 调用方读不到这一行(属主门 = `qualsOf`,「这个调用方读得到这一行 run 吗」的唯一谓词,经属主存取器 `owner-access.ts`
|
|
12
|
+
* · 调用方读不到这一行(属主门 = `qualsOf`,「这个调用方读得到这一行 run 吗」的唯一谓词,经属主存取器 `owner-access.ts` 读与判 —— 按钥匙读行也只在那里:
|
|
13
|
+
* `readReplayHit`;建行撞唯一键时观察到的行经同一只判 `replayHitOf`)⇒ 冲突;
|
|
13
14
|
* 冲突 ⇒ `409 conflict.run_exists`,体里**不回显**那条行的任何标识(不给跨租户预言机)。先于下一条判:读不到的行不比体。
|
|
14
15
|
* · 这次提交带 `Idempotency-Key`(`caller.idem` 在场)、那一行绑的**就是这把键**,而它记着的请求体指纹与这次不同 ⇒
|
|
15
16
|
* `409 conflict.idempotency_payload_mismatch`(同形 `{ error, errorCode }`,不回显键与那一行);**不**回放首发、不新建、那一行不动。
|
|
@@ -33,6 +34,7 @@ import type { RunIdemBinding, RunRecord } from "../plugins/store-contracts.js";
|
|
|
33
34
|
import type { RunStore } from "../plugins/store-backend.js";
|
|
34
35
|
import type { ServiceConfig } from "../config-types.js";
|
|
35
36
|
import type { SubmitOutcome } from "./idempotency.js";
|
|
37
|
+
import { type ReplayHit } from "./owner-access.js";
|
|
36
38
|
import type { Subject } from "../owner-brands.js";
|
|
37
39
|
/** 提交腿的回执形(闭集;穷举 `switch`,加一形不写这里 = 编译红)。 */
|
|
38
40
|
export type SubmitReplayFace = "durable" | "sync";
|
|
@@ -56,7 +58,18 @@ export declare function isReplayedOutcome(outcome: SubmitOutcome): boolean;
|
|
|
56
58
|
/** 一份提交回执是不是 {@link replayOfExistingRun} 铸的**冲突**体(判别位 = 机器码;铸点就在下面,码与它同文件)—— 把回执渲成别的协议形的
|
|
57
59
|
* 调用方(A2A)按它分句,不另抄码。 */
|
|
58
60
|
export declare function isRunExistsConflictBody(body: unknown): boolean;
|
|
61
|
+
/** 进门按一把提交钥匙(`Idempotency-Key` 铸的键 / 调用方自铸的 `body.taskId`)读行作答:没命中 ⇒ `undefined`(这是一次新提交);命中 ⇒ 本文件的唯一回执。 */
|
|
62
|
+
export declare function replayOfKey(key: {
|
|
63
|
+
readonly idemKey: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly taskId: string;
|
|
66
|
+
}, caller: ReplayCaller, face: SubmitReplayFace, deps: {
|
|
67
|
+
config: ServiceConfig;
|
|
68
|
+
}, runStore: Pick<RunStore, "getRun" | "getRunByIdem" | "bindIdemBodyFingerprint" | "observeRun">): Promise<SubmitOutcome | undefined>;
|
|
69
|
+
/** 建行撞唯一键时观察到的那一行(店的观察臂交回的既有行)作答:与按钥匙读到的同一只判、同一张回执。 */
|
|
59
70
|
export declare function replayOfExistingRun(seen: RunRecord, caller: ReplayCaller, face: SubmitReplayFace, deps: {
|
|
60
71
|
config: ServiceConfig;
|
|
61
|
-
}, runStore: RunStore): Promise<SubmitOutcome>;
|
|
72
|
+
}, runStore: Pick<RunStore, "bindIdemBodyFingerprint" | "observeRun">): Promise<SubmitOutcome>;
|
|
73
|
+
/** 一次命中的回执(判已在属主存取器里落成 {@link ReplayHit}):占用 ⇒ 冲突;读得到 ⇒ 体指纹 → 观察口 → 按提交腿的形答。 */
|
|
74
|
+
export declare function answerReplay(hit: ReplayHit, caller: ReplayCaller, face: SubmitReplayFace, runStore: Pick<RunStore, "bindIdemBodyFingerprint" | "observeRun">): Promise<SubmitOutcome>;
|
|
62
75
|
//# sourceMappingURL=submit-replay.d.ts.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { claimCallerOf } from "../security.js";
|
|
1
|
+
import { readReplayHit, replayHitOf, runRowAt } from "./owner-access.js";
|
|
3
2
|
import { syncSubmitBodyOfRow } from "./sync-submit-body.js";
|
|
4
3
|
import { refusalBody } from "./refusal-body.js";
|
|
5
4
|
export function replayedOutcome(outcome) {
|
|
@@ -15,11 +14,18 @@ export function isReplayedOutcome(outcome) {
|
|
|
15
14
|
export function isRunExistsConflictBody(body) {
|
|
16
15
|
return typeof body === "object" && body !== null && body.errorCode === "conflict.run_exists";
|
|
17
16
|
}
|
|
17
|
+
export async function replayOfKey(key, caller, face, deps, runStore) {
|
|
18
|
+
const hit = await readReplayHit(caller.subject, deps.config, runStore, key, caller.clientTaskId);
|
|
19
|
+
return hit === undefined ? undefined : answerReplay(hit, caller, face, runStore);
|
|
20
|
+
}
|
|
18
21
|
export async function replayOfExistingRun(seen, caller, face, deps, runStore) {
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
return answerReplay(replayHitOf(caller.subject, deps.config, seen, caller.clientTaskId), caller, face, runStore);
|
|
23
|
+
}
|
|
24
|
+
export async function answerReplay(hit, caller, face, runStore) {
|
|
25
|
+
if (hit.kind === "occupied") {
|
|
21
26
|
return { status: 409, body: refusalBody({ errorCode: "conflict.run_exists", message: "a run already exists for this submission's taskId or Idempotency-Key" }) };
|
|
22
27
|
}
|
|
28
|
+
const seen = hit.row;
|
|
23
29
|
if (caller.idem !== undefined) {
|
|
24
30
|
const held = await runStore.bindIdemBodyFingerprint(seen.taskId, caller.idem);
|
|
25
31
|
if (held !== null && held !== caller.idem.bodyFingerprint) {
|
|
@@ -109,7 +109,8 @@ export interface TaskRequestBody {
|
|
|
109
109
|
* `RunnerDeps.loadProjectMemory` —— 项目层、声明的指令文件、它们喂的那几处一并缺席(引擎自己的 git 状态车道、记忆引擎、技能 / hooks / MCP 不受影响)。
|
|
110
110
|
* 原样投给引擎;拼写门与 `fileHistory` 同一张单成员关断词表(`request-value-closure.ts`:别的值 fresh 400 `request.field_invalid`、续跑重放同判),
|
|
111
111
|
* 引擎读到的恒是这一个词;子代随父继承(引擎的夹紧表)。
|
|
112
|
-
* 本服务自铸的 `wiring_manifest.instructions` 段在这样的腿上缺席(loader 没被调就没有陈述)。能力位 `projectMemory`。
|
|
112
|
+
* 本服务自铸的 `wiring_manifest.instructions` 段在这样的腿上缺席(loader 没被调就没有陈述)。能力位 `projectMemory`。
|
|
113
|
+
* 7.150.0 起同一个词也关掉这条 run 从项目登记簿继承的项目简报(`project-context.ts`;继承来的 `cwd` 不受它管 —— 位置不是上下文内容)。 */
|
|
113
114
|
projectMemory?: TaskSpec["projectMemory"];
|
|
114
115
|
/** Explicit model selection (CLI `/model` picker + `run --model <ref>`). An INTENT by catalog
|
|
115
116
|
* name (e.g. "deepseek-pro") — resolveSpec gates it against the SAME allow-list as an inline `@name` mention
|
|
@@ -450,7 +451,9 @@ export interface TaskRequestBody {
|
|
|
450
451
|
* 同一个 id 的两种大小写写法落同一只记忆盘)。多租户 DB 记忆面下它把派生
|
|
451
452
|
* scope 从 user 盘切到项目盘(`proj:<tenant>/<projectId>`)并以 config.projects[projectId].defaultScopes
|
|
452
453
|
* 作 memory.scopes 种子;单用户部署忽略派生(memoryScopeFor 不变),仅 defaultScopes 种子生效。
|
|
453
|
-
* Rides the persisted body onto resume legs(与 memoryWrite 同姿势)。
|
|
454
|
+
* Rides the persisted body onto resume legs(与 memoryWrite 同姿势)。
|
|
455
|
+
* 7.150.0 起它(或会话行上声明过的项目)也选这条 run **继承的项目上下文**(`project-context.ts`;能力位 `projectInheritance`):登记对提交者可见且带内容证明 ⇒
|
|
456
|
+
* 项目简报进系统提示追加折叠的中段、射程内第一条 folder 填缺席的 `cwd`;判一次、随 run 冻结。项目继承来的成员参与的拒,`fields` 以本键为坐标。 */
|
|
454
457
|
projectId?: string;
|
|
455
458
|
/** [#40 / TOC cwd seam, SDK 0.0.36] The TOC client's launch directory — the agent's HOST execution-env workspace
|
|
456
459
|
* runs HERE (CC-parity: `sema` in a project dir operates on THAT project). An ABSOLUTE host path. 🔒 honored ONLY
|
|
@@ -572,7 +575,7 @@ export interface TaskRequestBody {
|
|
|
572
575
|
* `transport.env`(stdio)/ `transport.headers`(http)是这台 server 的**件**:server 交给引擎的声明里不带它们,件由部署的对端座在起子进程 / 发请求时按原字节作答
|
|
573
576
|
* (只对胜出部署同名判的条目登记;件的名与值由引擎在每次发送时判,不合 ⇒ 那一台不连、兄弟照挂)。 */
|
|
574
577
|
mcpServers?: RequestMcpServerSpec[];
|
|
575
|
-
/** [
|
|
578
|
+
/** [[ref] 车1] Caller-supplied per-request A2A peers (remote agents this task may call), aligned to
|
|
576
579
|
* core `A2aServerSpec`. 🔒 honored on a SINGLE-USER deployment (task-a2a.ts `a2aInjectionHonored`, the same
|
|
577
580
|
* predicate `capabilities.a2aInjection` advertises) — the requester is the super-admin of their OWN worker,
|
|
578
581
|
* on ANY execution lane (an A2A call is a plain outbound HTTPS request from the worker, so the lane where
|
package/dist/leader/endpoint.js
CHANGED
|
@@ -6,6 +6,7 @@ import { idemKeyOf } from "../http/idempotency.js";
|
|
|
6
6
|
import { refusalBody } from "../http/refusal-body.js";
|
|
7
7
|
import { LIVENESS_HEARTBEAT_MS } from "../config-invariants.js";
|
|
8
8
|
import { seatText } from "../trace/exit-seat.js";
|
|
9
|
+
import { readVisibleLeaderRow } from "../http/owner-access.js";
|
|
9
10
|
function statusForLeaderResult(result) {
|
|
10
11
|
if (result.conflict)
|
|
11
12
|
return "needs_human";
|
|
@@ -62,7 +63,7 @@ export function createLeaderEndpoint(runLeader, opts) {
|
|
|
62
63
|
? setInterval(() => {
|
|
63
64
|
if (ac.signal.aborted)
|
|
64
65
|
return;
|
|
65
|
-
void
|
|
66
|
+
void readDrivenRow(id).then((row) => {
|
|
66
67
|
if (row === undefined || row.status !== "running")
|
|
67
68
|
abortLocal(id, "stall_verdict");
|
|
68
69
|
else if (row.cancelRequested)
|
|
@@ -139,13 +140,13 @@ export function createLeaderEndpoint(runLeader, opts) {
|
|
|
139
140
|
}
|
|
140
141
|
})();
|
|
141
142
|
}
|
|
142
|
-
function
|
|
143
|
+
function readDrivenRow(id) {
|
|
143
144
|
return opts.store.getRun(id);
|
|
144
145
|
}
|
|
145
146
|
const opErr = (e) => seatText("operator-log-error", e instanceof Error ? e.message : String(e));
|
|
146
147
|
async function cancelFlagAfterSettle(id) {
|
|
147
148
|
try {
|
|
148
|
-
return (await
|
|
149
|
+
return (await readDrivenRow(id))?.cancelRequested === true;
|
|
149
150
|
}
|
|
150
151
|
catch (e) {
|
|
151
152
|
opts.logger?.error?.("leader_cancel_flag_reread_failed", { id, err: opErr(e), effect: "if a cancel landed on this run just before its terminal write, its worker parks are expired only when the cancel is re-sent" });
|
|
@@ -305,8 +306,8 @@ export function createLeaderEndpoint(runLeader, opts) {
|
|
|
305
306
|
if (m) {
|
|
306
307
|
const id = m[1];
|
|
307
308
|
if (opts.store) {
|
|
308
|
-
const run = await
|
|
309
|
-
if (!run
|
|
309
|
+
const run = await readVisibleLeaderRow(opts.store, id, ownerOk);
|
|
310
|
+
if (!run)
|
|
310
311
|
return NOT_FOUND;
|
|
311
312
|
return getBody(run);
|
|
312
313
|
}
|
|
@@ -327,15 +328,15 @@ export function createLeaderEndpoint(runLeader, opts) {
|
|
|
327
328
|
}
|
|
328
329
|
async function cancel(id, ownerOk) {
|
|
329
330
|
if (opts.store) {
|
|
330
|
-
const row = await
|
|
331
|
-
if (!row
|
|
331
|
+
const row = await readVisibleLeaderRow(opts.store, id, ownerOk);
|
|
332
|
+
if (!row)
|
|
332
333
|
return NOT_FOUND;
|
|
333
334
|
if (row.status === "running") {
|
|
334
335
|
if (await opts.store.requestCancel(id)) {
|
|
335
336
|
abortLocal(id, "cancel_verb");
|
|
336
337
|
return { status: 202, body: { leaderRunId: id, status: "cancelling", cancelRequested: true } };
|
|
337
338
|
}
|
|
338
|
-
const now = await
|
|
339
|
+
const now = await readVisibleLeaderRow(opts.store, id, ownerOk);
|
|
339
340
|
if (!now)
|
|
340
341
|
return NOT_FOUND;
|
|
341
342
|
return answerTerminal(id, now);
|
package/dist/leg-facts.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 一条腿的**部署事实**(执行车道 · run 技能名册 · 受理见证 · 登记的工作目录)—— server 自有的载体,**不搭引擎 spec 的车**。
|
|
2
|
+
* 一条腿的**部署事实**(执行车道 · run 技能名册 · 受理见证 · 登记的工作目录 · 继承的项目上下文)—— server 自有的载体,**不搭引擎 spec 的车**。
|
|
3
3
|
*
|
|
4
|
-
* 规则:`TaskSpec` 是引擎的类型面,上面只放引擎读的成员。本仓装配器(`boot/resolve-spec.ts` 的 `createResolveSpec`)
|
|
4
|
+
* 规则:`TaskSpec` 是引擎的类型面,上面只放引擎读的成员。本仓装配器(`boot/resolve-spec.ts` 的 `createResolveSpec`)同时还判出五件
|
|
5
5
|
* 只有 server 自己读的事实 —— 它们以装配器**自己的输出对象**为键登记在这一张表里(单一铸点 {@link mintLegFacts}),由两只漏斗
|
|
6
6
|
* (受理 `http/admission.ts` 的 `prepareSpec` · 续跑 `http/resume-legs.ts` 的 `resolveResumeSpec`)在拿到装配输出的**同一只对象**时
|
|
7
7
|
* 读一次(唯一读口 {@link legFactsOf},读在 `stampSpecRoot` 复制之前),此后作普通值随 `PreparedTaskSubmission.legFacts` /
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import type { ScenarioHands } from "./capabilities/hands-lane.js";
|
|
19
19
|
import type { RunSkillEntry } from "./capabilities/skills.js";
|
|
20
20
|
import type { DelegationRootWitness } from "./delegated-session-owner.js";
|
|
21
|
+
import type { ProjectContext } from "./project-context.js";
|
|
21
22
|
/** 一条腿的部署事实(冻结记录)。 */
|
|
22
23
|
export interface LegFacts {
|
|
23
24
|
/** 执行车道:`none` ⇒ 无手孪生 Runner。读者 = 生产选路器。 */
|
|
@@ -31,6 +32,11 @@ export interface LegFacts {
|
|
|
31
32
|
* 读者 = 三只组合入口(同步 / 后台 / 续跑腿的梯子与验证门):经 `compositionLegRoot`(`task-cwd.ts`)交给它们驱动的每一条腿当交活方的工作目录。
|
|
32
33
|
*/
|
|
33
34
|
readonly registeredCwd?: string;
|
|
35
|
+
/**
|
|
36
|
+
* 这条 run 继承到的项目上下文(`project-context.ts`):新提交腿在装配器头部判出的那一份,续跑腿是从续跑重建输入重放的那一份。缺席 = 没继承。
|
|
37
|
+
* 读者 = 提交腿写续跑重建输入的那一笔(`submit-ctx.ts` `persistSubmissionCtx` → `CheckpointCtx.projectContext`):判一次、随 run 冻结。
|
|
38
|
+
*/
|
|
39
|
+
readonly projectContext?: ProjectContext;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
42
|
* 铸事实(**单一属主**:只允许 `createResolveSpec` 的出口调用)。同一只对象被第二次铸 ⇒ 当场抛 —— 两个写者是漂移的成因,
|
package/dist/leg-facts.js
CHANGED
|
@@ -7,6 +7,7 @@ export function mintLegFacts(resolved, facts) {
|
|
|
7
7
|
skills: Object.freeze(facts.skills.map((e) => Object.freeze({ ...e }))),
|
|
8
8
|
sessionWitness: Object.freeze({ ...facts.sessionWitness }),
|
|
9
9
|
...(facts.registeredCwd !== undefined ? { registeredCwd: facts.registeredCwd } : {}),
|
|
10
|
+
...(facts.projectContext !== undefined ? { projectContext: Object.freeze({ ...facts.projectContext }) } : {}),
|
|
10
11
|
}));
|
|
11
12
|
return resolved;
|
|
12
13
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP
|
|
3
|
-
*
|
|
2
|
+
* MCP 授权记录(core 7.59.0 `McpAuthorization`:`{ reason, authorizeUrl?, resourceMetadataUrl? }`,与 `errorCode: "unauthorized"` 同在)的**出门投影** ——
|
|
3
|
+
* 一条记录无论坐在哪个投影载体里,离开本服务只经这一张处置表、这一只投影。五个投影点同读它:状态行投影(`wiring_manifest.mcp[]` 行;账本帧、面板的
|
|
4
|
+
* `lastLegMcp.mcp[]`、能力面两口读的都是它的产物)、重拨回执的 `status`、会话 MCP 面板的 `servers[]`、通告 `mcp.authorization_required` 的 `detail`
|
|
5
|
+
* (登记 `NOTICE_DETAIL_RECORDS`,`trace/engine-notice-wire.ts`)、会话历史读面里工具结果卡的 `details.authorization`(登记 `TOOL_CARD_RECORDS`,`trace/tool-card.ts`)。
|
|
6
|
+
* (工具卡的读者 `trace/tool-card.ts` 是后者的那一只:活面 `tool_end.structured` 上挂着授权记录的自注册卡同读。)记录成员是**结构位**:只经本表出门,
|
|
7
|
+
* 不过自由文本的脱敏、深扫与截断。会话同步拉取口不是投影:它把存档逐字复制给属主,存档里带不带远端的地址由引擎的写入决定。
|
|
4
8
|
*
|
|
5
|
-
*
|
|
6
|
-
* 判据直读引擎的 `MCP_AUTHORIZATION_REASONS`(不抄词表);词出闭集、非串、整只不是对象 ⇒
|
|
7
|
-
*
|
|
8
|
-
* (
|
|
9
|
+
* `reason` 是闭集词(`rejected` = 端点答 401 且对端座的重问没给出能过的凭据 / `scope` = 403 `insufficient_scope` / `none` = 对端座答「未授权」):
|
|
10
|
+
* 判据直读引擎的 `MCP_AUTHORIZATION_REASONS`(不抄词表);词出闭集、非串、整只不是对象 ⇒ 整条记录缺席(最弱断言,不铸词)。
|
|
11
|
+
* 两只地址今天不出门:`authorizeUrl` 只来自对端座 —— 座在,但今天没有会答需授权的凭据来源(地址的唯一入口与它的判法随那一臂立);
|
|
12
|
+
* `resourceMetadataUrl` 是远端在挑战头里自报的地址(终态 `strip`:没有消费方需要它 —— 客户端不跑授权发现;摆在「去授权」旁边的远端地址是钓鱼面)。
|
|
9
13
|
*/
|
|
10
|
-
import { type McpAuthorizationReason } from "@sema-agent/core";
|
|
11
|
-
|
|
14
|
+
import { type McpAuthorization, type McpAuthorizationReason } from "@sema-agent/core";
|
|
15
|
+
import { type FaceOf } from "./trace/projection-table.js";
|
|
16
|
+
/** 授权记录的处置表(五个投影点同读;`core-keyset-guard.ts` 读表 —— 门与投影一个写者):`reason` 认得才出门(闭集词;在场而认不得 ⇒ 丢并计一次),两只地址不出门。 */
|
|
12
17
|
export declare const MCP_AUTHORIZATION_DISPOSITIONS: {
|
|
13
18
|
readonly reason: {
|
|
14
19
|
readonly forward: (w: unknown) => w is McpAuthorizationReason;
|
|
@@ -16,12 +21,11 @@ export declare const MCP_AUTHORIZATION_DISPOSITIONS: {
|
|
|
16
21
|
readonly authorizeUrl: "strip";
|
|
17
22
|
readonly resourceMetadataUrl: "strip";
|
|
18
23
|
};
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
24
|
+
/** 记录的成员名 = 表的键(冻结拷贝;成员集只有表一处写)。平铺载体(通告 `detail`)按它认哪几位是这条记录。 */
|
|
25
|
+
export declare const MCP_AUTHORIZATION_MEMBERS: readonly string[];
|
|
26
|
+
type TableFace = FaceOf<McpAuthorization, typeof MCP_AUTHORIZATION_DISPOSITIONS>;
|
|
27
|
+
/** 本投影的产物 = 表的出门型({@link FaceOf}:表翻一格,型随之变);记录级规则「`reason` 在 ⇔ 记录在」在出口上,所以 `reason` 必在。 */
|
|
28
|
+
export type McpAuthorizationFace = TableFace & Required<Pick<TableFace, "reason">>;
|
|
25
29
|
export declare function projectMcpAuthorization(v: unknown): McpAuthorizationFace | undefined;
|
|
26
30
|
export {};
|
|
27
31
|
//# sourceMappingURL=mcp-authorization-face.d.ts.map
|
|
@@ -6,10 +6,11 @@ export const MCP_AUTHORIZATION_DISPOSITIONS = {
|
|
|
6
6
|
authorizeUrl: "strip",
|
|
7
7
|
resourceMetadataUrl: "strip",
|
|
8
8
|
};
|
|
9
|
+
export const MCP_AUTHORIZATION_MEMBERS = Object.freeze(Object.keys(MCP_AUTHORIZATION_DISPOSITIONS));
|
|
9
10
|
export function projectMcpAuthorization(v) {
|
|
10
11
|
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
11
12
|
return undefined;
|
|
12
|
-
const
|
|
13
|
-
return reason
|
|
13
|
+
const face = projectByTable("mcp.authorization", MCP_AUTHORIZATION_DISPOSITIONS, v, undefined);
|
|
14
|
+
return face.reason === undefined ? undefined : { ...face, reason: face.reason };
|
|
14
15
|
}
|
|
15
16
|
//# sourceMappingURL=mcp-authorization-face.js.map
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* 找码;这一半候 core 的结构化码位(登记在案,codex 一审 C3)。
|
|
31
31
|
*
|
|
32
32
|
* ## 不是这一族的形(core 同表「different surface」,本仓**不**自拼码,如实走各自既有臂;今两形 + 一只已退的形)
|
|
33
|
-
* · journal 重放目标目录成链 ⇒ `ControlPlaneCorruptError`(无 `.code`,
|
|
33
|
+
* · journal 重放目标目录成链 ⇒ `ControlPlaneCorruptError`(无 `.code`,[ref])⇒ 路由 typed 500 `internal.memory_control_plane_corrupt`
|
|
34
34
|
* (core 7.44.0 起 scope home 非目录**不再**走这一类 —— 它有了自己的码,见上;`ControlPlaneCorruptError` 只剩真控制面损坏);
|
|
35
35
|
* · (已不存在的一形)引擎原地写撞硬链(nlink>1):≤ 引擎 7.55.x 是无码文本 `has N names (a hard link) … not written`、走该写点既有的失败车道;
|
|
36
36
|
* 引擎 7.56.0 起那只写给**这个名字**另建一个新文件(原子改名落位,其余名字保留原文件),拒绝与那句文本一并消失 —— 本仓从未读过那句文本,零码;
|
|
@@ -41,7 +41,7 @@ export declare function createCorruptReadFailOpenSeat(tag: FailOpenTag, leg?: (i
|
|
|
41
41
|
* 这一座里有安全轴的脸(session-policy),所以每命中一行 warn 保留(降成「每进程一次」是降级,[ref] 的裁定);**在此之上**,认出的脸另记账:
|
|
42
42
|
* · session-policy 脸 ⇒ R 类 tag(`server.session-policy.corrupt-read-fail-open`)—— 计数逐次 + 探针行 + 一次性 warn。core 7.39.2 起按键读拒;
|
|
43
43
|
* core 7.41.0 [ref] 起本会话的枚举拒、别的会话的抹除不动它、重绑带走它 —— 但只对**有归属**的坏行(行里的 `__sid`,否则同名高水位标记的 `__sid`);
|
|
44
|
-
* 无从归属的坏行仍按「无规则」(core 已知限制
|
|
44
|
+
* 无从归属的坏行仍按「无规则」(core 已知限制 [ref] 接受:无从归属 ≠ 本会话);座上分不出读法 ⇒ 这一脸每一发都计(含已拒的)。
|
|
45
45
|
* 抹除扫走无归属坏行那一形 core 是否披露、座上数不数得到,未亲核。放行是 core 的裁定、本仓不包层(源头修复纪律),所以**只记账、不改放行**(R 类:有界放行,计数长期保留);
|
|
46
46
|
* · 其余脸 ⇒ 不计(见 {@link DurableAbsenceFace})。
|
|
47
47
|
* 记账**先于** warn:记账是总函数,warn 可能抛(core 的 guard 会吞掉那个抛),一次日志故障不许吃掉计数。
|
|
@@ -197,7 +197,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
197
197
|
};
|
|
198
198
|
readonly "server.approvals.queue-row-agent-unreadable": {
|
|
199
199
|
readonly cls: "F";
|
|
200
|
-
readonly note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `
|
|
200
|
+
readonly note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `http/owner-access.ts` 的 `readSessionAgent` = 会话店的 `placementOf` 一读)。某一只会话那一读抛(店瞬断 / 超时 / local 后端的会话存档行头读不出)⇒ **这只会话的行**缺 `agent` 键,列表其余照常。放行的最坏后果 = 这一行这一次没有委派归属线索:壳的归属判官认不到它(行照列、人从队列照样决得了 —— 与本键存在之前同形);`agent` 不是授权事实(队列行本就只列调用方 scope 的卡,决断口另有属主门)。不放行的代价是一只读不出的会话打掉整张待批列表(订阅流上每一拍都是读失败)。故 F 类;必须留痕,否则「这一次没读成」与「这不是一只 placed 委派子代」在 wire 上同形。detail = 会话 id 与经出口座的错误句。计数按次(订阅流每一拍各计一次)。";
|
|
201
201
|
};
|
|
202
202
|
readonly "server.approvals.durable-row-checkpoint-id-missing": {
|
|
203
203
|
readonly cls: "F";
|
|
@@ -569,13 +569,13 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
569
569
|
readonly cls: "R";
|
|
570
570
|
readonly ruling: "C-R296";
|
|
571
571
|
readonly bound: "FLEET_LEASE_OUTAGE_MAX_MS";
|
|
572
|
-
readonly note: "`fleet/serving-lease.ts`
|
|
572
|
+
readonly note: "`fleet/serving-lease.ts` 的「没确认」一段(两个调用点一只函数、一行 warn `fleet_serving_lease_unconfirmed`、一只连败计数;detail = `worker=<w> generation=<g> why=<…>`):① `renewOnce`(中心宣告了位之后每一次续租;`why=<不可达句 | HTTP <状态> | verdict=unknown>`)—— 中心这一次**没有确认**本实例该不该服务:不可达 / 超时 / 非 2xx / 答复读不成判决,或答 `unknown`(此刻没有本实例的生命周期对象);② `noteHeartbeat` 的沉默臂(fleet 成员还没听到任何声明的推定期,每一拍心跳;`why=heartbeat:<HTTP <状态> | 请求抛出的那句 | reply-unreadable:<因> | not-sent:<那句>>`,不带中心体片段)—— 成员起步即推定在围栏内,心跳没换来中心的声明。按设计**什么都不改**(规则 2 第三臂):到期之前照常 `granted`,过期后 / 推定期 `expired` 照常接单,直到最后一次授予的到期(没有授予 ⇒ 围栏在本进程生效的时刻,推定 = 本进程起点)满 `FLEET_LEASE_OUTAGE_MAX_MS`(`T_max`)才拒新工作(503 `state.lease_expired`,在飞不动、永不自停)。只在围栏生效时计(中心以不带位的声明解除围栏之后,在飞续租迟到的失败不计)。一段的收尾 = 续租判决(`granted` / `denied`)或中心以不带位的声明解除围栏,一行 `fleet_serving_lease_recovered`(`by: verdict | not-enforced`);宣告本身不是确认。归 R:方向与上界由裁定写定 —— 实例只在中心权威终止(`denied`)或运维覆盖时被替换,`T_max` 只是引擎自己「失联后最多再接单多久」的准入上界,不是替换依据;没确认不是被拒。放行的最坏后果 = 一只其实已被取代的实例在中心失联期间多服务至多「租约剩余 + `T_max`」(中心的代际下限持久,恢复后第一次续租即拒);从起步起一直没听到中心的成员**每个不间断进程**至多服务 `T_max`(钟不跨重启:重启即重计)。计数长期保留:持续非零 = 中心长时间没确认本实例,去看 detail 的 why(连不上 / 令牌被拒 / 中心不认识这只实例 / 答复不是声明)。";
|
|
573
573
|
};
|
|
574
574
|
readonly "server.fleet.serving-lease-capability-absent": {
|
|
575
575
|
readonly cls: "R";
|
|
576
576
|
readonly ruling: "C-R296";
|
|
577
577
|
readonly bound: "FLEET_LEASE_OUTAGE_MAX_MS";
|
|
578
|
-
readonly note: "`fleet/serving-lease.ts` 的 `
|
|
578
|
+
readonly note: "`fleet/serving-lease.ts` 的 `noteHeartbeat` 读数臂(fleet 成员每一次中心能力声明;detail = `worker=<w> generation=<g> was=<presumed|on|off>`):中心心跳答复里**显式的** `capabilities` 声明对象在、却**没有宣告** `servingLease`(中心关着围栏开关 / 共享令牌 / 降级中心 / 位撤掉)⇒ 规则 1:租约不生效,`leaseState: none`,零续租、零 503 —— 这只 fleet 成员此刻**不受围栏**。推定期的第一条声明就不带位(`was=presumed`)⇒ 推定作废(`expired → none`),钟不起,之后不限时(直到中心第一次宣告,那一拍起钟)。不是声明的答复不进这一臂(体读不出 / 不是对象 / 没有 `capabilities` 键 / 形坏 —— 那是沉默,推定、位与钟原样,`fleet-client.ts` `capabilityReadingOf`);已被拒的实例不进(拒是黏的,位消失不复活)。归 R:能力门控是契约规则(中心声明不执行 = 中心不执行围栏),裁定写定替换只来自中心权威终止或运维覆盖;位只开关围栏、不碰钟 —— 位缺席期间 `T_max` 的钟照走(最后一次授予的到期 / 围栏在本进程第一次生效的时刻),位一回来即按它判,所以位的抖动绕不过 `FLEET_LEASE_OUTAGE_MAX_MS`。放行的最坏后果 = 中心声明不执行围栏期间,一只被取代的实例照常服务(这一段由中心的选择定界,不由引擎)。计数长期保留:非零 = 这台中心没宣告租约能力。";
|
|
579
579
|
};
|
|
580
580
|
readonly "server.workspace-cache.unavailable": {
|
|
581
581
|
readonly cls: "F";
|
|
@@ -611,11 +611,11 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
611
611
|
};
|
|
612
612
|
readonly "server.fleet.announce-reply-unreadable": {
|
|
613
613
|
readonly cls: "P-DEBT";
|
|
614
|
-
readonly note: "7.121.0 修复验证轮(`fleet-client.ts` 的公告环,fleet 成员每一拍心跳 2xx 答复;detail = `why=<body|not-an-object|invalid-capabilities> leaseState=<此刻的租约态>`)
|
|
614
|
+
readonly note: "7.121.0 修复验证轮(`fleet-client.ts` 的公告环,fleet 成员每一拍心跳 2xx 答复;detail = `why=<body|not-an-object|capabilities-absent|invalid-capabilities> leaseState=<此刻的租约态>`):答复不是能力声明(体读不出 / 不是对象 / 没有 `capabilities` 键 / `capabilities` 键在场而形坏 —— settings-schema `readCapabilityReading` 的 `unreadable`〔没有键那一因自 25.0.0 起〕,外加本仓的 `body`)⇒ 这一拍是沉默(交租约客户端 `silent`,`why=reply-unreadable:<因>`),推定、租约的状态与钟原样。**一律**计数(不论租约此刻什么态):推定期(成员还没听到任何声明,`leaseState=expired`)的坏答复同时是一拍「没确认」(另计 `server.fleet.serving-lease-unconfirmed`),推定与钟照走、满 `T_max` 拒新工作;租约已生效时计数说明中心的答复在坏、围栏靠的是上一次声明。归 P 类:围栏轴;归 DEBT:本进程判不出中心为什么答坏体,收口条件 = 中心契约 / 监控(中心侧对心跳答复形的执法)落地。每段连拍另有一行 warn `fleet_announce_reply_unreadable`(带 `why`)。";
|
|
615
615
|
};
|
|
616
616
|
readonly "server.fleet.denied-marker-unpersisted": {
|
|
617
617
|
readonly cls: "P-DEBT";
|
|
618
|
-
readonly note: "7.121.0(`fleet/serving-lease.ts` 的 `enterDenied`,中心以正面证据拒了本实例的服务租约那一拍;detail = `worker=<w> generation=<g>`):拒要落成数据根下一只文件(重启后起步即排空),而这一次**没落下** —— 没有数据根,或写失败(盘满 / 只读挂载 / 目录不在)。本进程照样被拒、照样当拍排空、到期自停;放行的是**重启之后**:同代际重启的实例不记得被拒,在第一次续租得到答复之前会接新工作(中心宣告了能力位时,第一次续租就再被拒一次 ——
|
|
618
|
+
readonly note: "7.121.0(`fleet/serving-lease.ts` 的 `enterDenied`,中心以正面证据拒了本实例的服务租约那一拍;detail = `worker=<w> generation=<g>`):拒要落成数据根下一只文件(重启后起步即排空),而这一次**没落下** —— 没有数据根,或写失败(盘满 / 只读挂载 / 目录不在)。本进程照样被拒、照样当拍排空、到期自停;放行的是**重启之后**:同代际重启的实例不记得被拒,在第一次续租得到答复之前会接新工作(中心宣告了能力位时,第一次续租就再被拒一次 —— 中心的代际下限是持久的;中心那时不可达 / 心跳一直不通则按推定围栏接单到本进程起点满 `FLEET_LEASE_OUTAGE_MAX_MS`,每个进程各一段;重启后第一条声明就不带位 ⇒ 中心的话,不限时)。归 P 类:这是围栏的记忆;归 DEBT:进程内无法把「记不住」变成 fail-closed(「起步首次答复之前零容忍」形已否决:中心宕几秒 + 一次重启就停数据面),收口条件 = 契约给出持久拒位的公告位(心跳 / `/health` 上说「这一次拒只在本进程」,中心据此对该实例下一次续租照拒、并能看见它)。denied 行的 `sticky` 同拍说 `process-only`,不声称跨重启记得。计数非零 = 这台机器的数据根写不进,或部署没有数据根。";
|
|
619
619
|
};
|
|
620
620
|
readonly "server.sql.tidb-row-cap-unread": {
|
|
621
621
|
readonly cls: "F";
|
|
@@ -178,7 +178,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
178
178
|
},
|
|
179
179
|
"server.approvals.queue-row-agent-unreadable": {
|
|
180
180
|
cls: "F",
|
|
181
|
-
note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `
|
|
181
|
+
note: "S-3000(`routes/approvals-assistant.ts` 的 `sessionAgentsOf`):运维待批队列(`GET /v1/approvals` 的 `pending[]` 与 `/v1/approvals/stream` 的 `pending` 帧)每一只停驻行带它那只会话在委派树里的位置 `agent`(会话视图的同名键,唯一读口 `http/owner-access.ts` 的 `readSessionAgent` = 会话店的 `placementOf` 一读)。某一只会话那一读抛(店瞬断 / 超时 / local 后端的会话存档行头读不出)⇒ **这只会话的行**缺 `agent` 键,列表其余照常。放行的最坏后果 = 这一行这一次没有委派归属线索:壳的归属判官认不到它(行照列、人从队列照样决得了 —— 与本键存在之前同形);`agent` 不是授权事实(队列行本就只列调用方 scope 的卡,决断口另有属主门)。不放行的代价是一只读不出的会话打掉整张待批列表(订阅流上每一拍都是读失败)。故 F 类;必须留痕,否则「这一次没读成」与「这不是一只 placed 委派子代」在 wire 上同形。detail = 会话 id 与经出口座的错误句。计数按次(订阅流每一拍各计一次)。",
|
|
182
182
|
},
|
|
183
183
|
"server.approvals.durable-row-checkpoint-id-missing": {
|
|
184
184
|
cls: "F",
|
|
@@ -520,13 +520,13 @@ export const FAIL_OPEN_TAGS = {
|
|
|
520
520
|
cls: "R",
|
|
521
521
|
ruling: "C-R296",
|
|
522
522
|
bound: "FLEET_LEASE_OUTAGE_MAX_MS",
|
|
523
|
-
note: "`fleet/serving-lease.ts`
|
|
523
|
+
note: "`fleet/serving-lease.ts` 的「没确认」一段(两个调用点一只函数、一行 warn `fleet_serving_lease_unconfirmed`、一只连败计数;detail = `worker=<w> generation=<g> why=<…>`):① `renewOnce`(中心宣告了位之后每一次续租;`why=<不可达句 | HTTP <状态> | verdict=unknown>`)—— 中心这一次**没有确认**本实例该不该服务:不可达 / 超时 / 非 2xx / 答复读不成判决,或答 `unknown`(此刻没有本实例的生命周期对象);② `noteHeartbeat` 的沉默臂(fleet 成员还没听到任何声明的推定期,每一拍心跳;`why=heartbeat:<HTTP <状态> | 请求抛出的那句 | reply-unreadable:<因> | not-sent:<那句>>`,不带中心体片段)—— 成员起步即推定在围栏内,心跳没换来中心的声明。按设计**什么都不改**(规则 2 第三臂):到期之前照常 `granted`,过期后 / 推定期 `expired` 照常接单,直到最后一次授予的到期(没有授予 ⇒ 围栏在本进程生效的时刻,推定 = 本进程起点)满 `FLEET_LEASE_OUTAGE_MAX_MS`(`T_max`)才拒新工作(503 `state.lease_expired`,在飞不动、永不自停)。只在围栏生效时计(中心以不带位的声明解除围栏之后,在飞续租迟到的失败不计)。一段的收尾 = 续租判决(`granted` / `denied`)或中心以不带位的声明解除围栏,一行 `fleet_serving_lease_recovered`(`by: verdict | not-enforced`);宣告本身不是确认。归 R:方向与上界由裁定写定 —— 实例只在中心权威终止(`denied`)或运维覆盖时被替换,`T_max` 只是引擎自己「失联后最多再接单多久」的准入上界,不是替换依据;没确认不是被拒。放行的最坏后果 = 一只其实已被取代的实例在中心失联期间多服务至多「租约剩余 + `T_max`」(中心的代际下限持久,恢复后第一次续租即拒);从起步起一直没听到中心的成员**每个不间断进程**至多服务 `T_max`(钟不跨重启:重启即重计)。计数长期保留:持续非零 = 中心长时间没确认本实例,去看 detail 的 why(连不上 / 令牌被拒 / 中心不认识这只实例 / 答复不是声明)。",
|
|
524
524
|
},
|
|
525
525
|
"server.fleet.serving-lease-capability-absent": {
|
|
526
526
|
cls: "R",
|
|
527
527
|
ruling: "C-R296",
|
|
528
528
|
bound: "FLEET_LEASE_OUTAGE_MAX_MS",
|
|
529
|
-
note: "`fleet/serving-lease.ts` 的 `
|
|
529
|
+
note: "`fleet/serving-lease.ts` 的 `noteHeartbeat` 读数臂(fleet 成员每一次中心能力声明;detail = `worker=<w> generation=<g> was=<presumed|on|off>`):中心心跳答复里**显式的** `capabilities` 声明对象在、却**没有宣告** `servingLease`(中心关着围栏开关 / 共享令牌 / 降级中心 / 位撤掉)⇒ 规则 1:租约不生效,`leaseState: none`,零续租、零 503 —— 这只 fleet 成员此刻**不受围栏**。推定期的第一条声明就不带位(`was=presumed`)⇒ 推定作废(`expired → none`),钟不起,之后不限时(直到中心第一次宣告,那一拍起钟)。不是声明的答复不进这一臂(体读不出 / 不是对象 / 没有 `capabilities` 键 / 形坏 —— 那是沉默,推定、位与钟原样,`fleet-client.ts` `capabilityReadingOf`);已被拒的实例不进(拒是黏的,位消失不复活)。归 R:能力门控是契约规则(中心声明不执行 = 中心不执行围栏),裁定写定替换只来自中心权威终止或运维覆盖;位只开关围栏、不碰钟 —— 位缺席期间 `T_max` 的钟照走(最后一次授予的到期 / 围栏在本进程第一次生效的时刻),位一回来即按它判,所以位的抖动绕不过 `FLEET_LEASE_OUTAGE_MAX_MS`。放行的最坏后果 = 中心声明不执行围栏期间,一只被取代的实例照常服务(这一段由中心的选择定界,不由引擎)。计数长期保留:非零 = 这台中心没宣告租约能力。",
|
|
530
530
|
},
|
|
531
531
|
"server.workspace-cache.unavailable": {
|
|
532
532
|
cls: "F",
|
|
@@ -562,11 +562,11 @@ export const FAIL_OPEN_TAGS = {
|
|
|
562
562
|
},
|
|
563
563
|
"server.fleet.announce-reply-unreadable": {
|
|
564
564
|
cls: "P-DEBT",
|
|
565
|
-
note: "7.121.0 修复验证轮(`fleet-client.ts` 的公告环,fleet 成员每一拍心跳 2xx 答复;detail = `why=<body|not-an-object|invalid-capabilities> leaseState=<此刻的租约态>`)
|
|
565
|
+
note: "7.121.0 修复验证轮(`fleet-client.ts` 的公告环,fleet 成员每一拍心跳 2xx 答复;detail = `why=<body|not-an-object|capabilities-absent|invalid-capabilities> leaseState=<此刻的租约态>`):答复不是能力声明(体读不出 / 不是对象 / 没有 `capabilities` 键 / `capabilities` 键在场而形坏 —— settings-schema `readCapabilityReading` 的 `unreadable`〔没有键那一因自 25.0.0 起〕,外加本仓的 `body`)⇒ 这一拍是沉默(交租约客户端 `silent`,`why=reply-unreadable:<因>`),推定、租约的状态与钟原样。**一律**计数(不论租约此刻什么态):推定期(成员还没听到任何声明,`leaseState=expired`)的坏答复同时是一拍「没确认」(另计 `server.fleet.serving-lease-unconfirmed`),推定与钟照走、满 `T_max` 拒新工作;租约已生效时计数说明中心的答复在坏、围栏靠的是上一次声明。归 P 类:围栏轴;归 DEBT:本进程判不出中心为什么答坏体,收口条件 = 中心契约 / 监控(中心侧对心跳答复形的执法)落地。每段连拍另有一行 warn `fleet_announce_reply_unreadable`(带 `why`)。",
|
|
566
566
|
},
|
|
567
567
|
"server.fleet.denied-marker-unpersisted": {
|
|
568
568
|
cls: "P-DEBT",
|
|
569
|
-
note: "7.121.0(`fleet/serving-lease.ts` 的 `enterDenied`,中心以正面证据拒了本实例的服务租约那一拍;detail = `worker=<w> generation=<g>`):拒要落成数据根下一只文件(重启后起步即排空),而这一次**没落下** —— 没有数据根,或写失败(盘满 / 只读挂载 / 目录不在)。本进程照样被拒、照样当拍排空、到期自停;放行的是**重启之后**:同代际重启的实例不记得被拒,在第一次续租得到答复之前会接新工作(中心宣告了能力位时,第一次续租就再被拒一次 ——
|
|
569
|
+
note: "7.121.0(`fleet/serving-lease.ts` 的 `enterDenied`,中心以正面证据拒了本实例的服务租约那一拍;detail = `worker=<w> generation=<g>`):拒要落成数据根下一只文件(重启后起步即排空),而这一次**没落下** —— 没有数据根,或写失败(盘满 / 只读挂载 / 目录不在)。本进程照样被拒、照样当拍排空、到期自停;放行的是**重启之后**:同代际重启的实例不记得被拒,在第一次续租得到答复之前会接新工作(中心宣告了能力位时,第一次续租就再被拒一次 —— 中心的代际下限是持久的;中心那时不可达 / 心跳一直不通则按推定围栏接单到本进程起点满 `FLEET_LEASE_OUTAGE_MAX_MS`,每个进程各一段;重启后第一条声明就不带位 ⇒ 中心的话,不限时)。归 P 类:这是围栏的记忆;归 DEBT:进程内无法把「记不住」变成 fail-closed(「起步首次答复之前零容忍」形已否决:中心宕几秒 + 一次重启就停数据面),收口条件 = 契约给出持久拒位的公告位(心跳 / `/health` 上说「这一次拒只在本进程」,中心据此对该实例下一次续租照拒、并能看见它)。denied 行的 `sticky` 同拍说 `process-only`,不声称跨重启记得。计数非零 = 这台机器的数据根写不进,或部署没有数据根。",
|
|
570
570
|
},
|
|
571
571
|
"server.sql.tidb-row-cap-unread": {
|
|
572
572
|
cls: "F",
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
/**
|
|
3
|
+
* **启动协议行**(闭集):起本进程的那一方(壳 / 嵌入宿主 / 测试夹具)从 stdout 读这几行起步 —— `listening` 带内核分给本进程的口(`port`)与
|
|
4
|
+
* 实绑地址(`boundAddress`),读者拿它们找到并认出自己起的这只引擎。它们是协议,不是诊断:**在不在不随 `LOG_LEVEL`**(档位只滤诊断行;
|
|
5
|
+
* 档位调高而协议行跟着消失 ⇒ 读者要么拒起、要么各自替部署把档位压回 info,同一个事实多出几份读法)。除此之外与任何一行同路:同一只出口座
|
|
6
|
+
* (脱敏)、同一条流(按行上的 `level` 分流)、行上的 `level` 照写 —— 按 `level` 字段筛日志的管道照旧筛得掉它。
|
|
7
|
+
*/
|
|
8
|
+
export declare const STARTUP_PROTOCOL_EVENTS: readonly ["listening"];
|
|
2
9
|
export interface Logger {
|
|
3
10
|
debug(msg: string, fields?: Record<string, unknown>): void;
|
|
4
11
|
info(msg: string, fields?: Record<string, unknown>): void;
|
|
@@ -3,6 +3,8 @@ import { OVERSIZED_REDACTION_PLACEHOLDER, seatText } from "../trace/exit-seat.js
|
|
|
3
3
|
import { errorKindOf } from "./err-text.js";
|
|
4
4
|
import { buildFailOpenAnchor, installFailOpenAnnounceExit } from "./fail-open.js";
|
|
5
5
|
const ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
6
|
+
export const STARTUP_PROTOCOL_EVENTS = ["listening"];
|
|
7
|
+
const STARTUP_PROTOCOL = new Set(STARTUP_PROTOCOL_EVENTS);
|
|
6
8
|
const LOG_LINE_WITHHELD = "log_line_withheld";
|
|
7
9
|
const SECRET_SCREEN_FAILED = "secret_screen_failed";
|
|
8
10
|
const UNFORMATTABLE = "unformattable";
|
|
@@ -61,7 +63,7 @@ const diagnosticStream = (stream) => (stdoutReservedForAnswer ? "stderr" : strea
|
|
|
61
63
|
export function createLogger(minLevel = "info") {
|
|
62
64
|
swallowStdioErrors();
|
|
63
65
|
const emit = (level, msg, fields) => {
|
|
64
|
-
if (ORDER[level] < ORDER[minLevel])
|
|
66
|
+
if (ORDER[level] < ORDER[minLevel] && !STARTUP_PROTOCOL.has(msg))
|
|
65
67
|
return;
|
|
66
68
|
const ts = new Date().toISOString();
|
|
67
69
|
const line = serializeEntry({ ts, level, msg }, fields);
|
|
@@ -132,7 +132,7 @@ export declare function redactModelText(raw: string, before?: string): string;
|
|
|
132
132
|
* 它进引擎之前已**准入一次**:三只 brain 在建调用的那一行(`brain/tool-call-id.js` 的 `admitToolCallId`)—— 缺席 ⇒ 车道兜底铸;
|
|
133
133
|
* 在形(可见 ASCII 1–128 且不含 `~`)⇒ 原样;越界 ⇒ 单射折叠成引擎 id(`<前 32 码元,越界字符记 `-`>~<sha256 前 32 hex>`),原字节只挂在
|
|
134
134
|
* 转录的 `ToolCall.wireId` 上、只回给 provider。⇒ 一方 brain 在 7.107.0 起新铸的调用,到达本仓任何一张脸的 `toolCallId` 恒在形。
|
|
135
|
-
* 残余两条([ref],如实):① ≤7.106.0 写下的存量行(待批 park 行 `boundCallId` / 检查点 `pendingAction.toolCallId` / 转录)是服务商原串逐字 —— 新版不对存量行二次准入(e2e G4 钉);② 宿主自己的 `Brain`(不经三只一方 adapter)铸的 id 不准入(core
|
|
135
|
+
* 残余两条([ref],如实):① ≤7.106.0 写下的存量行(待批 park 行 `boundCallId` / 检查点 `pendingAction.toolCallId` / 转录)是服务商原串逐字 —— 新版不对存量行二次准入(e2e G4 钉);② 宿主自己的 `Brain`(不经三只一方 adapter)铸的 id 不准入(core [ref];本仓生产装配的 brain 恒是 `createBrain` 的一方 adapter 外套委托装饰,这一形只经嵌入 / 测试注入的 brain 到达)。两条残余里的 id 仍是跨面 join 键、每张脸同值,只是形状不保证(本闸照旧不动它们:动一张脸 = join 断)。
|
|
136
136
|
*
|
|
137
137
|
* 🔴 **本闸只施加在「这个值出现的每一张脸都被覆盖到」的回声上**(codex r1 F1,实测成立的回归后改判):工具调用 id 是
|
|
138
138
|
* **跨面 join 键** —— 同一枚 id 同时逐字出现在 `tool_start` / `tool_end` / 审批卡等逐帧面上。只在结果面动它 ⇒ 结果面与逐帧面
|
package/dist/owner-faces.d.ts
CHANGED
|
@@ -112,9 +112,10 @@ export type FaceDoor = "P401" | "I401" | "I401r" | "none";
|
|
|
112
112
|
* · `deleted_false` —— 200 `{deleted:false}`(删除口幂等形:没删到东西);
|
|
113
113
|
* · `run_exists` —— 409 `conflict.run_exists`(提交重放:这把键 / 这只 taskId 已被占用);
|
|
114
114
|
* · `attach_absent` —— 404 `resume.session_not_found`「requireExistingSession: session does not exist …」(提交挂接:认领面没有「没有就建」可镜像,占用 = 不存在那一体);
|
|
115
|
+
* · `workflow_missing` —— 404 `not_found.workflow` "workflow not found"(工作流按 id 四口;没有 / 看不见 / 会话断言不符同体);
|
|
115
116
|
* · `omit` —— 本模块不下发:调用点把「看不见」当「没有」走它自己的缺席路径(协议口的 RpcError / leader 404 / 嵌套可选字段省略)。
|
|
116
117
|
*/
|
|
117
|
-
export type FaceProjection = "run_missing" | "task_missing" | "decision_missing" | "session_missing" | "exemption_missing" | "deleted_false" | "run_exists" | "attach_absent" | "omit";
|
|
118
|
+
export type FaceProjection = "run_missing" | "task_missing" | "decision_missing" | "session_missing" | "exemption_missing" | "deleted_false" | "workflow_missing" | "run_exists" | "attach_absent" | "omit";
|
|
118
119
|
/** 属主读不出(会话店交出具名拒「属主读不出」)时本口怎么读:`fold` = 读作没有这一行(同一只投影,原故障进运维日志一行);`raise` = 原故障照常上抛。 */
|
|
119
120
|
export type FaceUnreadable = "fold" | "raise";
|
|
120
121
|
/**
|
|
@@ -126,8 +127,8 @@ export type FaceUnreadable = "fold" | "raise";
|
|
|
126
127
|
*/
|
|
127
128
|
export type FacePlacementUnreadable = "raise" | "ordinary";
|
|
128
129
|
export interface Face {
|
|
129
|
-
/** 行的种类:run / 会话行(路由经 `http/owner-access.ts` 的门判)、停驻行 scope 列(`scope`)、ask 行 / 活登记 / 活问(`ask`)、收件条目(`inbox`)、列表面(`list`)。 */
|
|
130
|
-
readonly resource: "run" | "session" | "scope" | "ask" | "inbox" | "list";
|
|
130
|
+
/** 行的种类:run / 会话行(路由经 `http/owner-access.ts` 的门判)、工作流行(`workflow`:属主 = 引擎写下的 `scope` 列)、停驻行 scope 列(`scope`)、ask 行 / 活登记 / 活问(`ask`)、收件条目(`inbox`)、列表面(`list`)。 */
|
|
131
|
+
readonly resource: "run" | "session" | "workflow" | "scope" | "ask" | "inbox" | "list";
|
|
131
132
|
/** 行资格里本口放哪几格。 */
|
|
132
133
|
readonly grants: readonly RowQual[];
|
|
133
134
|
/** fleet 资格里本口放哪几格(D1 列,见模块头注)。 */
|
|
@@ -385,6 +386,26 @@ export declare const FACES: {
|
|
|
385
386
|
readonly unreadable: "raise";
|
|
386
387
|
readonly placementUnreadable: "ordinary";
|
|
387
388
|
};
|
|
389
|
+
readonly "workflow.read": {
|
|
390
|
+
readonly resource: "workflow";
|
|
391
|
+
readonly grants: readonly ["owner"];
|
|
392
|
+
readonly fleet: readonly [];
|
|
393
|
+
readonly operator: false;
|
|
394
|
+
readonly door: "P401";
|
|
395
|
+
readonly projection: "workflow_missing";
|
|
396
|
+
readonly unreadable: "raise";
|
|
397
|
+
readonly placementUnreadable: "raise";
|
|
398
|
+
};
|
|
399
|
+
readonly "workflow.steer": {
|
|
400
|
+
readonly resource: "workflow";
|
|
401
|
+
readonly grants: readonly ["owner"];
|
|
402
|
+
readonly fleet: readonly [];
|
|
403
|
+
readonly operator: false;
|
|
404
|
+
readonly door: "P401";
|
|
405
|
+
readonly projection: "workflow_missing";
|
|
406
|
+
readonly unreadable: "raise";
|
|
407
|
+
readonly placementUnreadable: "raise";
|
|
408
|
+
};
|
|
388
409
|
readonly "scope.decide": {
|
|
389
410
|
readonly resource: "scope";
|
|
390
411
|
readonly grants: readonly ["owner", "open"];
|
|
@@ -456,6 +477,9 @@ export type SessionFaceId = {
|
|
|
456
477
|
export type ListFaceId = {
|
|
457
478
|
[F in FaceId]: (typeof FACES)[F]["resource"] extends "list" ? F : never;
|
|
458
479
|
}[FaceId];
|
|
480
|
+
export type WorkflowFaceId = {
|
|
481
|
+
[F in FaceId]: (typeof FACES)[F]["resource"] extends "workflow" ? F : never;
|
|
482
|
+
}[FaceId];
|
|
459
483
|
/**
|
|
460
484
|
* **只看「验过的主体 + 运维位」的面**(派生型:行资格 ⊆ {owner, open} ∧ fleet 列空):这几只面的可见性与部署形、fleet 事实都无关 ——
|
|
461
485
|
* 面表里给其中一行加上 `j4` / 任一 fleet 格,它就掉出本型,{@link keyAdmits} 的调用点编译红(那时它要一只完整的 {@link Caller})。
|
package/dist/owner-faces.js
CHANGED
|
@@ -74,6 +74,8 @@ export const FACES = {
|
|
|
74
74
|
"session.policy": { resource: "session", grants: ["owner", "open", "anon_tree"], fleet: ["dev_open"], operator: true, door: "I401r", projection: "session_missing", unreadable: "raise", placementUnreadable: "ordinary" },
|
|
75
75
|
"session.notify": { resource: "session", grants: ["owner", "open", "anon_tree"], fleet: ["dev_open"], operator: true, door: "P401", projection: "session_missing", unreadable: "raise", placementUnreadable: "raise" },
|
|
76
76
|
"session.attach": { resource: "session", grants: ["owner", "open"], fleet: [], operator: false, door: "none", projection: "attach_absent", unreadable: "raise", placementUnreadable: "ordinary" },
|
|
77
|
+
"workflow.read": { resource: "workflow", grants: ["owner"], fleet: [], operator: false, door: "P401", projection: "workflow_missing", unreadable: "raise", placementUnreadable: "raise" },
|
|
78
|
+
"workflow.steer": { resource: "workflow", grants: ["owner"], fleet: [], operator: false, door: "P401", projection: "workflow_missing", unreadable: "raise", placementUnreadable: "raise" },
|
|
77
79
|
"scope.decide": { resource: "scope", grants: ["owner", "open"], fleet: [], operator: true, door: "none", projection: "omit", unreadable: "raise", placementUnreadable: "raise" },
|
|
78
80
|
"ask.decide": { resource: "ask", grants: ["owner", "open"], fleet: [], operator: true, door: "none", projection: "omit", unreadable: "raise", placementUnreadable: "raise" },
|
|
79
81
|
"ask.answer": { resource: "ask", grants: ["owner", "open"], fleet: [], operator: false, door: "none", projection: "omit", unreadable: "raise", placementUnreadable: "raise" },
|
package/dist/peer-seat.d.ts
CHANGED
|
@@ -66,7 +66,7 @@ export type PeerBinding = {
|
|
|
66
66
|
readonly url: string;
|
|
67
67
|
readonly cardUrl?: string;
|
|
68
68
|
};
|
|
69
|
-
/** Why the seat refused a question. Closed: a
|
|
69
|
+
/** Why the seat refused a question. Closed: a word belongs to a row of the seat's per-kind table (or to the handle row's own two refusals). */
|
|
70
70
|
export type PeerSeatRefusalReason = "handle_not_held" | "binding_mismatch" | "kind_env" | "kind_vault" | "kind_assertion" | "kind_unknown";
|
|
71
71
|
/**
|
|
72
72
|
* The desk's own failures, each loud:
|