@sema-agent/server 7.136.0 → 7.138.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 +501 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +149 -34
- package/deploy/sema-up/README.md +14 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/approval-content-kind.d.ts +6 -0
- package/dist/approval-content-kind.js +7 -0
- package/dist/approval-gate-currency.d.ts +48 -6
- package/dist/approval-gate-currency.js +16 -9
- package/dist/approval-hmac.d.ts +13 -1
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.js +3 -3
- package/dist/audit.js +1 -0
- package/dist/auth-bridge.js +2 -2
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/execution-env.d.ts +24 -1
- package/dist/boot/execution-env.js +69 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +15 -1
- package/dist/boot/resolve-spec.d.ts +7 -0
- package/dist/boot/resolve-spec.js +36 -26
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +2 -13
- package/dist/boot/stage-05-execution-env.d.ts +6 -13
- package/dist/boot/stage-05-execution-env.js +17 -5
- package/dist/boot/stage-06-runners.d.ts +6 -13
- package/dist/boot/stage-06-runners.js +10 -3
- package/dist/boot/stage-07-capability-layer.d.ts +7 -13
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +7 -13
- package/dist/boot/stage-08-reapers.js +2 -1
- package/dist/boot/stage-09-leader.d.ts +7 -13
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +7 -13
- package/dist/boot/stage-10-http-server.js +6 -3
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/broker/broker.d.ts +89 -0
- package/dist/broker/broker.js +287 -0
- package/dist/broker/constants.d.ts +39 -0
- package/dist/broker/constants.js +15 -0
- package/dist/broker/http1.d.ts +111 -0
- package/dist/broker/http1.js +256 -0
- package/dist/broker/lease-book.d.ts +87 -0
- package/dist/broker/lease-book.js +142 -0
- package/dist/broker/lease-file.d.ts +60 -0
- package/dist/broker/lease-file.js +127 -0
- package/dist/broker/main.d.ts +2 -0
- package/dist/broker/main.js +20 -0
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/engine-capabilities.js +1 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capabilities/scenarios.d.ts +23 -8
- package/dist/capabilities/scenarios.js +13 -8
- package/dist/capabilities/skills.d.ts +28 -5
- package/dist/capabilities/skills.js +8 -0
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/center-credential-renewer.js +5 -1
- package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
- package/dist/checkpoint-ctx-seal-m28.js +1 -1
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +16 -7
- package/dist/config-types.d.ts +24 -7
- package/dist/config.d.ts +1 -1
- package/dist/config.js +42 -13
- package/dist/deployment-governance.d.ts +2 -2
- package/dist/deployment-governance.js +7 -9
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/file-history-disclosure.d.ts +4 -2
- package/dist/file-history-disclosure.js +2 -0
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +12 -54
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +4 -3
- package/dist/http/caller-trust.d.ts +2 -1
- package/dist/http/caller-trust.js +1 -3
- package/dist/http/checkpoint-ctx.d.ts +48 -7
- package/dist/http/checkpoint-ctx.js +40 -0
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +18 -10
- package/dist/http/durable-run-leg.d.ts +5 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/principal-gate.d.ts +15 -10
- package/dist/http/principal-gate.js +48 -9
- package/dist/http/resume-legs.d.ts +7 -31
- package/dist/http/resume-legs.js +185 -126
- package/dist/http/route-ctx.d.ts +38 -53
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +24 -10
- package/dist/http/routes/capabilities.js +23 -11
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -7
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +13 -8
- package/dist/http/routes/session-sync.js +42 -6
- package/dist/http/routes/sessions.js +6 -3
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +794 -780
- package/dist/http/server.d.ts +35 -25
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +6 -1
- package/dist/http/wire-types.d.ts +66 -33
- package/dist/identity-source.d.ts +65 -0
- package/dist/identity-source.js +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-store-refusal.d.ts +3 -3
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +2 -0
- package/dist/model-entry-refusal.js +11 -0
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/model-select.d.ts +6 -17
- package/dist/model-select.js +0 -3
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/namespaced-rule-name.d.ts +1 -1
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/operator-ask.d.ts +2 -2
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +2 -2
- package/dist/org-memory-admission.js +39 -2
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +17 -10
- package/dist/peer-directory.js +2 -0
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-list.d.ts +2 -2
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
- package/dist/plugins/checkpoint-store-sql.js +14 -14
- package/dist/plugins/file-history-store-sql.js +10 -16
- package/dist/plugins/file-run-store.js +8 -2
- package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
- package/dist/plugins/k8s-exec-protocol.js +116 -28
- package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
- package/dist/plugins/k8s-pod-delete-failure.js +17 -0
- package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
- package/dist/plugins/k8s-pod-reaper.js +122 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -17
- package/dist/plugins/local-checkpoint-store.js +3 -4
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-run-store.js +2 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +34 -12
- package/dist/plugins/one-time-migrations.js +51 -9
- package/dist/plugins/permission-rule-store-file.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
- package/dist/plugins/permission-rule-store-sql.js +37 -30
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +20 -7
- package/dist/plugins/remote-env-adb.d.ts +6 -1
- package/dist/plugins/remote-env-adb.js +2 -1
- package/dist/plugins/remote-env-device.d.ts +6 -1
- package/dist/plugins/remote-env-device.js +5 -1
- package/dist/plugins/remote-env-e2b.d.ts +5 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-file-error.d.ts +8 -1
- package/dist/plugins/remote-env-file-error.js +7 -1
- package/dist/plugins/remote-env-host.d.ts +10 -2
- package/dist/plugins/remote-env-host.js +8 -2
- package/dist/plugins/remote-env-k8s.d.ts +140 -11
- package/dist/plugins/remote-env-k8s.js +277 -15
- package/dist/plugins/remote-env-local-docker.d.ts +5 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +6 -1
- package/dist/plugins/remote-env-ssh.js +2 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.js +10 -4
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +24 -3
- package/dist/plugins/session-ownership.js +24 -5
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/sql-errors.d.ts +23 -2
- package/dist/plugins/sql-errors.js +15 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/store-contracts.d.ts +10 -1
- package/dist/plugins/store-fault.d.ts +2 -2
- package/dist/plugins/store-fault.js +4 -2
- package/dist/plugins/tidb-pool.js +13 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +18 -7
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +31 -2
- package/dist/request-value-closure.js +7 -1
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +2 -2
- package/dist/rules-consent.js +12 -7
- package/dist/run-local.d.ts +2 -2
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +8 -2
- package/dist/runtime-governance.d.ts +5 -5
- package/dist/sandbox-git-lease.d.ts +49 -0
- package/dist/sandbox-git-lease.js +60 -0
- package/dist/sandbox-git-plane.d.ts +84 -0
- package/dist/sandbox-git-plane.js +105 -0
- package/dist/security.d.ts +16 -4
- package/dist/security.js +8 -3
- package/dist/server-secret-env.d.ts +12 -3
- package/dist/server-secret-env.js +18 -2
- package/dist/session-error-wire.d.ts +14 -6
- package/dist/session-error-wire.js +2 -1
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-policy-wire.js +2 -2
- package/dist/session-sync.d.ts +1 -1
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +44 -14
- package/dist/spec-fields.js +33 -12
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
- package/dist/stored-request-prompt-profile-m30.js +25 -0
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +34 -21
- package/dist/task-mcp.js +46 -22
- package/dist/task-settings.d.ts +2 -2
- package/dist/tool-approval.d.ts +43 -9
- package/dist/tool-approval.js +57 -15
- package/dist/tool-rule-names.d.ts +5 -0
- package/dist/trace/core-keyset-guard.d.ts +34 -19
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +5 -2
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/ledger-sink.d.ts +4 -5
- package/dist/trace/ledger-sink.js +3 -7
- package/dist/trace/project.d.ts +62 -10
- package/dist/trace/project.js +49 -9
- package/dist/trace/redact.d.ts +18 -6
- package/dist/trace/redact.js +154 -60
- package/dist/trace/self-minted-wire.d.ts +500 -7
- package/dist/trace/self-minted-wire.js +182 -1
- package/dist/trace/wire-projection-faces.d.ts +7 -5
- package/dist/trace/wire-projection-faces.js +9 -4
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/apply-effective.js +0 -1
- package/dist/web-admin-client/center-request.d.ts +23 -4
- package/dist/web-admin-client/center-request.js +42 -8
- package/dist/web-admin-client/http-client.js +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +10 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
- package/package.json +3 -3
- package/wire-changes/server@7.137.0.json +825 -0
- package/wire-changes/server@7.138.0.json +446 -0
package/dist/model-route-gap.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBlankCredential } from "@sema-agent/core";
|
|
1
2
|
import { brainLaneFor, declaredRootUrl } from "./model-provider.js";
|
|
2
3
|
import { DEFAULT_MODEL_REF } from "./model-select.js";
|
|
3
4
|
export const MODEL_ROUTE_ENV_KEYS = {
|
|
@@ -22,14 +23,15 @@ export function mintedCheapId(slot) {
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
const declaredValue = (v) => (v !== undefined && v !== "" ? v : undefined);
|
|
26
|
+
export const declaredCredential = (v) => (v !== undefined && !isBlankCredential(v) ? v : undefined);
|
|
25
27
|
export const csvOf = (raw) => (raw ?? "")
|
|
26
28
|
.split(",")
|
|
27
29
|
.map((s) => s.trim())
|
|
28
30
|
.filter(Boolean);
|
|
29
31
|
export function readModelRouteEnv(env) {
|
|
30
32
|
const K = MODEL_ROUTE_ENV_KEYS;
|
|
31
|
-
const anthropicApiKey =
|
|
32
|
-
const anthropicAuthToken =
|
|
33
|
+
const anthropicApiKey = declaredCredential(env[K.anthropicApiKey]);
|
|
34
|
+
const anthropicAuthToken = declaredCredential(env[K.anthropicAuthToken]);
|
|
33
35
|
const anthropicBaseUrl = declaredValue(env[K.anthropicBaseUrl]);
|
|
34
36
|
const anthropicRouteMounted = anthropicApiKey !== undefined || anthropicAuthToken !== undefined;
|
|
35
37
|
const explicitProvider = declaredValue(env[K.provider]);
|
|
@@ -58,8 +60,8 @@ export function readModelRouteEnv(env) {
|
|
|
58
60
|
}
|
|
59
61
|
export function judgeAnthropicCredential(names) {
|
|
60
62
|
const K = MODEL_ROUTE_ENV_KEYS;
|
|
61
|
-
const apiKey =
|
|
62
|
-
const authToken =
|
|
63
|
+
const apiKey = declaredCredential(names.apiKey);
|
|
64
|
+
const authToken = declaredCredential(names.authToken);
|
|
63
65
|
if (apiKey !== undefined && authToken !== undefined)
|
|
64
66
|
return { kind: "conflict" };
|
|
65
67
|
if (apiKey !== undefined)
|
|
@@ -111,7 +113,7 @@ export function laneAndEndpointFor(env, model, routes) {
|
|
|
111
113
|
};
|
|
112
114
|
case "gateway": {
|
|
113
115
|
const endpointDeclared = declaredRootUrl(reading.gatewayBaseUrl) !== undefined;
|
|
114
|
-
const credentialLoaded = endpointDeclared && reading.gatewayApiKey !== undefined
|
|
116
|
+
const credentialLoaded = endpointDeclared && declaredCredential(reading.gatewayApiKey) !== undefined;
|
|
115
117
|
return { lane, endpointEnvName: K.gatewayBaseUrl, endpointDeclared, apiKeyEnvName: credentialLoaded ? K.gatewayApiKey : undefined };
|
|
116
118
|
}
|
|
117
119
|
}
|
package/dist/model-select.d.ts
CHANGED
|
@@ -187,11 +187,10 @@ export declare function matchCatalogModel(ref: string, catalog: Record<string, u
|
|
|
187
187
|
export declare const MODEL_IMAGE_INPUTS: readonly ["yes", "no", "undeclared"];
|
|
188
188
|
export type ModelImageInput = (typeof MODEL_IMAGE_INPUTS)[number];
|
|
189
189
|
/**
|
|
190
|
-
*
|
|
190
|
+
* 「这个目录条目收不收图」的**唯一读法**。读者都投影它,不各写各的:
|
|
191
191
|
* · 目录行 `GET /v1/models` 的 `vision`:`yes` ⇒ `true`,`no` ⇒ `false`,`undeclared` ⇒ **键缺席**(不替没声明的模型答「收」也不答「不收」);
|
|
192
|
-
* ·
|
|
193
|
-
*
|
|
194
|
-
* 条目上把用户的图拦在了本地,而引擎其实会把图交给模型。env 车道与 web-admin 车道恒写 `input`,分叉只落在手写目录条目上。
|
|
192
|
+
* · 配置目录 `GET /v1/config/catalog` 的 `MODEL_VISION` 行。
|
|
193
|
+
* 「图被换成占位句」这件事实不在本仓判:引擎 7.56.0([ref])在真替换的那一刻铸给人(`model.capability_downgraded`,会话流),本仓提交面的带图预检随之退役。
|
|
195
194
|
* `input` 不是数组(手写错形)与条目不在,同归 `undeclared`:没有可信的声明。
|
|
196
195
|
*/
|
|
197
196
|
export declare function modelImageInput(model: {
|
|
@@ -212,19 +211,9 @@ export interface ModelCapabilityDecl {
|
|
|
212
211
|
/**
|
|
213
212
|
* 能力位声明 ⇒ `Model` 上的两个键,**缺席不铸键**:`reasoning` 原样;`vision` 翻成 `input`(`true` ⇒ `["text","image"]`,`false` ⇒ `["text"]`)。
|
|
214
213
|
* env 腿(`MODEL_REASONING` / `MODEL_VISION`)、cheap 槽(`MODEL_CHEAP_*`)与中心腿(`models[].reasoning` / `vision`)都经它铸 —— 三条腿一个铸法、一个「缺席」的意思。
|
|
215
|
-
* 读回的唯一读法是 {@link modelReasoningDecl} 与 {@link modelImageInput}(
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* `input` 缺席 ⇒ 支持图(`modelSupportsVision`:`model?.input === undefined ? true : …`),`reasoning` 缺席 ⇒ 真值判假(`!!model.reasoning`)。所以交给引擎的目录里缺席的键是安全的,
|
|
219
|
-
* 只是型面还没跟上;返回型因此对 `Pick<Model, …>` 说了一句「可能为空」的谎,把断言收在这一处 —— 调用点的 `Model` 字面量照旧带 `Model` 注解(其余每个键仍被 tsc 逐个核,
|
|
220
|
-
* 读表门按注解收字面量的 core 键)。型面归引擎:引擎把这两位放成可选之日,本接缝(返回型 + 这一处断言)整件删除。
|
|
214
|
+
* 读回的唯一读法是 {@link modelReasoningDecl} 与 {@link modelImageInput}(`GET /v1/models` 与配置目录同读)。
|
|
215
|
+
* 引擎 7.56.0([ref])起 `Model.reasoning` / `Model.input` 在型面上就是可选(缺席 = 未声明,引擎一只读法 `capabilityOf`:图的未声明照常交给模型、
|
|
216
|
+
* 推理的未声明不发思考档),所以本函数的返回型就是引擎的型,无断言。
|
|
221
217
|
*/
|
|
222
218
|
export declare function mintCapabilityKeys(decl: ModelCapabilityDecl): Pick<Model, "reasoning" | "input">;
|
|
223
|
-
/**
|
|
224
|
-
* 带图预检:只有目录条目**明说**不收图({@link modelImageInput} 为 `"no"`)才为假 —— 提交时据此计数并告警(引擎会把这些图换成给模型的
|
|
225
|
-
* 占位句);没声明的条目为真(不出信号,图原样交给模型)。
|
|
226
|
-
*/
|
|
227
|
-
export declare function modelSupportsImages(model: {
|
|
228
|
-
input?: unknown;
|
|
229
|
-
} | undefined): boolean;
|
|
230
219
|
//# sourceMappingURL=model-select.d.ts.map
|
package/dist/model-select.js
CHANGED
|
@@ -137,7 +137,4 @@ export function mintCapabilityKeys(decl) {
|
|
|
137
137
|
keys[CAPABILITY_MODEL_KEYS.input] = decl.vision ? ["text", "image"] : ["text"];
|
|
138
138
|
return keys;
|
|
139
139
|
}
|
|
140
|
-
export function modelSupportsImages(model) {
|
|
141
|
-
return modelImageInput(model) !== "no";
|
|
142
|
-
}
|
|
143
140
|
//# sourceMappingURL=model-select.js.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 部署声明的 mod 包 —— `MODS_ROOT` + `MODS_PACKAGES` 的**唯一读法**,以及部署座装配(`boot/deployment-mods.ts`)全部失败的**唯一词表与拒句**。
|
|
3
|
+
*
|
|
4
|
+
* ## 规则(一句)
|
|
5
|
+
* mod 包只从运维的部署声明装载;声明只说四件宿主的事实 —— 装哪个目录(`dir`)、叫什么(`name`,须与包自己的名逐字同)、站哪一档(`tier`)、
|
|
6
|
+
* 交给它什么(`options`);包里的三件文件只有引擎一只读者(`loadModPackage`),本仓**不读包内任何文件、不算摘要**。
|
|
7
|
+
*
|
|
8
|
+
* ## 声明的形
|
|
9
|
+
* · `MODS_ROOT` —— 绝对路径;声明的每只包解析真实路径之后必须**严格**落在它(的真实路径)之下(按路径分量判,不是前缀;根本身不是包目录)。
|
|
10
|
+
* 单设它而不声明包 = 无事(形照判)。
|
|
11
|
+
* · `MODS_PACKAGES` —— JSON 数组,每项闭集四键 `{ name, dir, tier, options? }`:`name` 非空串;`dir` 绝对路径;`tier` ∈ `prepend | user | append`
|
|
12
|
+
* (宿主必填 —— 包不自报档;站不站得住由引擎的座 × 档表判,部署座三档都许);`options` 任意 JSON 值,原样交包的 `register`。
|
|
13
|
+
* 缺席 / 空串 = 不声明(部署座只有本仓自铸的注册,与没有这两根旋钮的版本逐字节同)。
|
|
14
|
+
* · `MODS_PACKAGES` 是一份声明、不是凭据值:配置目录只回在场位与长度(不回显);`options` 不是凭据通道 —— 本服务不替包扣凭据(声明与包自己读的环境变量
|
|
15
|
+
* 都不在自有凭据声明里,宿主车道 `inheritEnv: "all"` 下模型的子进程照样继承)。
|
|
16
|
+
*
|
|
17
|
+
* ## 失败(两类,一张闭集词表,一种拒句)
|
|
18
|
+
* · **声明 / 文件系统**(本仓判;任何一只包被装载之前,整张声明全部判完):
|
|
19
|
+
* `config_invalid`(某一席的形不对 —— 整段 JSON、某一项、`MODS_ROOT`)· `root_missing`(声明了包而 `MODS_ROOT` 没设)·
|
|
20
|
+
* `name_missing` · `duplicate_name` · `root_unreadable` · `dir_unreadable` · `outside_root` · `not_a_directory`;
|
|
21
|
+
* · **读包者 / 准入**(引擎判,本仓只透传):`package_refused`(读包者拒了这只包)· `name_mismatch`(包自己的名与声明的不同)·
|
|
22
|
+
* `admission_refused`(整列交引擎准入被拒)。
|
|
23
|
+
* 任一失败 = 拒启。拒句一行:`deployment mods refused: <词>(<主语>)[: <细节>]`,整行经出口座 `boot-refusal-line`(剥控制与双向字符、凭据形换记号、
|
|
24
|
+
* ≤ 512 码元含截断记号)—— 读包者 / 准入的机器码原样留在主语括号里;本仓写的句子不回显声明的值(路径、`options`),主语只点名是哪一席(`MODS_PACKAGES[2]`)
|
|
25
|
+
* 或哪只包;读包者 / 准入 / 包自己交回的话原样透传(过出口座),其中可能点名包目录 —— 那是运维要的诊断,包本身是受信代码。
|
|
26
|
+
*/
|
|
27
|
+
import type { ModRegistrationTier } from "@sema-agent/core";
|
|
28
|
+
/** 声明的一只包(宿主的四件事实)。 */
|
|
29
|
+
export interface DeclaredModPackage {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly dir: string;
|
|
32
|
+
readonly tier: ModRegistrationTier;
|
|
33
|
+
/** 缺席 = 声明里没写这一键(交给 `register` 的就是 `undefined`)。 */
|
|
34
|
+
readonly options?: unknown;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 部署声明(`loadConfig` 读一次;两只起服入口的装配都读这一份)。两种形,形即律:
|
|
38
|
+
* · **没声明包** —— 没有 `packages` 这一席(变量缺席 / 空串 / 显式 `[]` 同一形);`root` 只在单设了 `MODS_ROOT` 时在(形照判、无事,配置目录照回);
|
|
39
|
+
* · **声明了包** —— 至少一只,且**必有根**:「有包无根」「有根空表」都不是可表示的值(`root_missing` 只在本模块的读法里判,装配口没有这一臂)。
|
|
40
|
+
* 读者按 `d.packages === undefined` 分两形(`packages` 是判别位:没声明那一形上它只能缺席)。
|
|
41
|
+
*/
|
|
42
|
+
export type ModsDeclaration = {
|
|
43
|
+
readonly root?: string;
|
|
44
|
+
readonly packages?: never;
|
|
45
|
+
} | {
|
|
46
|
+
readonly root: string;
|
|
47
|
+
readonly packages: readonly [DeclaredModPackage, ...DeclaredModPackage[]];
|
|
48
|
+
};
|
|
49
|
+
/** 声明里的一席:整根旋钮,或 `MODS_PACKAGES` 的第几项。 */
|
|
50
|
+
export type DeclarationSeat = "MODS_ROOT" | "MODS_PACKAGES" | {
|
|
51
|
+
readonly entry: number;
|
|
52
|
+
};
|
|
53
|
+
/** 一次失败(词 + 主语 + 细节)。细节只有两种来源:本仓写死的句子,或读包者 / 准入交回的话(过出口座)。**失败词的唯一来源是本联合各成员的 `word`。** */
|
|
54
|
+
export type DeploymentModsRefusal = {
|
|
55
|
+
readonly word: "config_invalid";
|
|
56
|
+
readonly seat: DeclarationSeat;
|
|
57
|
+
readonly why: string;
|
|
58
|
+
} | {
|
|
59
|
+
readonly word: "root_missing";
|
|
60
|
+
} | {
|
|
61
|
+
readonly word: "name_missing";
|
|
62
|
+
readonly entry: number;
|
|
63
|
+
} | {
|
|
64
|
+
readonly word: "duplicate_name";
|
|
65
|
+
readonly entry: number;
|
|
66
|
+
readonly first: number;
|
|
67
|
+
} | {
|
|
68
|
+
readonly word: "root_unreadable";
|
|
69
|
+
readonly cause: string;
|
|
70
|
+
} | {
|
|
71
|
+
readonly word: "dir_unreadable";
|
|
72
|
+
readonly entry: number;
|
|
73
|
+
readonly cause: string;
|
|
74
|
+
} | {
|
|
75
|
+
readonly word: "outside_root";
|
|
76
|
+
readonly entry: number;
|
|
77
|
+
} | {
|
|
78
|
+
readonly word: "not_a_directory";
|
|
79
|
+
readonly entry: number;
|
|
80
|
+
} | {
|
|
81
|
+
readonly word: "package_refused";
|
|
82
|
+
readonly name: string;
|
|
83
|
+
readonly code: string | undefined;
|
|
84
|
+
readonly reason: string;
|
|
85
|
+
} | {
|
|
86
|
+
readonly word: "name_mismatch";
|
|
87
|
+
readonly name: string;
|
|
88
|
+
readonly packageName: string;
|
|
89
|
+
} | {
|
|
90
|
+
readonly word: "admission_refused";
|
|
91
|
+
readonly code: string | undefined;
|
|
92
|
+
readonly reason: string;
|
|
93
|
+
};
|
|
94
|
+
/** 失败词(拒句的 `<词>`)= 联合成员的 `word`,不另写一份。渲染是穷尽 `switch`(加成员不加臂 = 编译红)。 */
|
|
95
|
+
export type DeploymentModsRefusalWord = DeploymentModsRefusal["word"];
|
|
96
|
+
/** 失败词闭集(运行期全集;「每词至少一格」的钉读它)。 */
|
|
97
|
+
export declare const DEPLOYMENT_MODS_REFUSALS: readonly DeploymentModsRefusalWord[];
|
|
98
|
+
/** 一次失败的拒句(一行;整行经出口座 `boot-refusal-line`:剥控制与双向字符、凭据形换记号、≤ 512 码元含截断记号)。 */
|
|
99
|
+
export declare function buildDeploymentModsRefusalLine(r: DeploymentModsRefusal): string;
|
|
100
|
+
/** 部署座装配的拒启(两只起服入口同一只类型;`refusal` 是机读的那一份,`message` 是它的拒句)。 */
|
|
101
|
+
export declare class DeploymentModsRefusedError extends Error {
|
|
102
|
+
readonly refusal: DeploymentModsRefusal;
|
|
103
|
+
constructor(refusal: DeploymentModsRefusal);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 声明的形(纯函数,`loadConfig` 调;文件系统那一半在装配里):`MODS_ROOT` 的形 → `MODS_PACKAGES` 是不是 JSON 数组 → 逐项(序号升序;每项:是对象 →
|
|
107
|
+
* 键闭集 → `name` → `dir` → `tier` → 与前面的项重名)→ 声明了包而没设根。第一处不过即拒,拒句不回显声明的值。
|
|
108
|
+
*/
|
|
109
|
+
export declare function parseModsDeclaration(rootRaw: string | undefined, packagesRaw: string | undefined): ModsDeclaration;
|
|
110
|
+
//# sourceMappingURL=mods-declaration.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { seatText } from "./trace/exit-seat.js";
|
|
3
|
+
const DECLARABLE_TIERS = { prepend: true, user: true, append: true };
|
|
4
|
+
const TIER_WORDS = Object.keys(DECLARABLE_TIERS);
|
|
5
|
+
const isDeclarableTier = (v) => typeof v === "string" && Object.hasOwn(DECLARABLE_TIERS, v);
|
|
6
|
+
const ENTRY_KEYS = new Set(["name", "dir", "tier", "options"]);
|
|
7
|
+
const REFUSAL_WORDS = {
|
|
8
|
+
config_invalid: true,
|
|
9
|
+
root_missing: true,
|
|
10
|
+
name_missing: true,
|
|
11
|
+
duplicate_name: true,
|
|
12
|
+
root_unreadable: true,
|
|
13
|
+
dir_unreadable: true,
|
|
14
|
+
outside_root: true,
|
|
15
|
+
not_a_directory: true,
|
|
16
|
+
package_refused: true,
|
|
17
|
+
name_mismatch: true,
|
|
18
|
+
admission_refused: true,
|
|
19
|
+
};
|
|
20
|
+
export const DEPLOYMENT_MODS_REFUSALS = Object.keys(REFUSAL_WORDS);
|
|
21
|
+
const seatLabel = (seat) => (typeof seat === "string" ? seat : `MODS_PACKAGES[${seat.entry}]`);
|
|
22
|
+
const entryLabel = (entry) => seatLabel({ entry });
|
|
23
|
+
const nameLabel = (name) => JSON.stringify(name);
|
|
24
|
+
function refusalText(r) {
|
|
25
|
+
const line = (subject, detail) => `deployment mods refused: ${r.word}${subject !== undefined ? `(${subject})` : ""}${detail !== undefined ? `: ${detail}` : ""}`;
|
|
26
|
+
switch (r.word) {
|
|
27
|
+
case "config_invalid":
|
|
28
|
+
return line(seatLabel(r.seat), r.why);
|
|
29
|
+
case "root_missing":
|
|
30
|
+
return line("MODS_ROOT", "MODS_PACKAGES declares packages but MODS_ROOT is not set — every declared package must resolve under that root");
|
|
31
|
+
case "name_missing":
|
|
32
|
+
return line(entryLabel(r.entry), "name must be a non-empty string — the package's own name (its .claude-plugin/plugin.json `name`), spelled exactly");
|
|
33
|
+
case "duplicate_name":
|
|
34
|
+
return line(entryLabel(r.entry), `same name as ${entryLabel(r.first)} — each declared package is one registration and a name is its identity`);
|
|
35
|
+
case "root_unreadable":
|
|
36
|
+
return line("MODS_ROOT", `its real path cannot be resolved (${r.cause})`);
|
|
37
|
+
case "dir_unreadable":
|
|
38
|
+
return line(entryLabel(r.entry), `dir's real path cannot be resolved (${r.cause})`);
|
|
39
|
+
case "outside_root":
|
|
40
|
+
return line(entryLabel(r.entry), "dir does not resolve strictly under MODS_ROOT (real paths, compared by path components; the root itself is not a package directory)");
|
|
41
|
+
case "not_a_directory":
|
|
42
|
+
return line(entryLabel(r.entry), "dir does not resolve to a directory");
|
|
43
|
+
case "package_refused":
|
|
44
|
+
return line(r.code !== undefined ? `${nameLabel(r.name)}, ${r.code}` : nameLabel(r.name), r.reason);
|
|
45
|
+
case "name_mismatch":
|
|
46
|
+
return line(nameLabel(r.name), `the package names itself ${nameLabel(r.packageName)} — the declared name must be the package's own name, spelled exactly`);
|
|
47
|
+
case "admission_refused":
|
|
48
|
+
return line(r.code, r.reason);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function buildDeploymentModsRefusalLine(r) {
|
|
52
|
+
return seatText("boot-refusal-line", refusalText(r));
|
|
53
|
+
}
|
|
54
|
+
export class DeploymentModsRefusedError extends Error {
|
|
55
|
+
refusal;
|
|
56
|
+
constructor(refusal) {
|
|
57
|
+
super(buildDeploymentModsRefusalLine(refusal));
|
|
58
|
+
this.refusal = refusal;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function refuse(r) {
|
|
62
|
+
throw new DeploymentModsRefusedError(r);
|
|
63
|
+
}
|
|
64
|
+
const isPlainRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
65
|
+
export function parseModsDeclaration(rootRaw, packagesRaw) {
|
|
66
|
+
const root = rootRaw === undefined || rootRaw === "" ? undefined : rootRaw;
|
|
67
|
+
if (root !== undefined && !isAbsolute(root))
|
|
68
|
+
refuse({ word: "config_invalid", seat: "MODS_ROOT", why: "must be an absolute path" });
|
|
69
|
+
const undeclared = root !== undefined ? { root } : {};
|
|
70
|
+
if (packagesRaw === undefined || packagesRaw.trim() === "")
|
|
71
|
+
return undeclared;
|
|
72
|
+
let parsed;
|
|
73
|
+
try {
|
|
74
|
+
parsed = JSON.parse(packagesRaw);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
refuse({ word: "config_invalid", seat: "MODS_PACKAGES", why: "is not valid JSON" });
|
|
78
|
+
}
|
|
79
|
+
if (!Array.isArray(parsed))
|
|
80
|
+
refuse({ word: "config_invalid", seat: "MODS_PACKAGES", why: "must be a JSON array of { name, dir, tier, options? }" });
|
|
81
|
+
const packages = [];
|
|
82
|
+
const firstIndexOf = new Map();
|
|
83
|
+
for (const [entry, item] of parsed.entries()) {
|
|
84
|
+
if (!isPlainRecord(item))
|
|
85
|
+
refuse({ word: "config_invalid", seat: { entry }, why: "must be an object { name, dir, tier, options? }" });
|
|
86
|
+
const unknown = Object.keys(item).filter((k) => !ENTRY_KEYS.has(k));
|
|
87
|
+
if (unknown.length > 0)
|
|
88
|
+
refuse({ word: "config_invalid", seat: { entry }, why: `has keys outside { name, dir, tier, options }: ${unknown.map((k) => JSON.stringify(k)).join(", ")}` });
|
|
89
|
+
const { name, dir, tier } = item;
|
|
90
|
+
if (typeof name !== "string" || name === "")
|
|
91
|
+
refuse({ word: "name_missing", entry });
|
|
92
|
+
if (typeof dir !== "string" || !isAbsolute(dir))
|
|
93
|
+
refuse({ word: "config_invalid", seat: { entry }, why: "dir must be an absolute path" });
|
|
94
|
+
if (!isDeclarableTier(tier))
|
|
95
|
+
refuse({ word: "config_invalid", seat: { entry }, why: `tier must be one of ${TIER_WORDS.join(", ")} — the host declares it, a package never does` });
|
|
96
|
+
const first = firstIndexOf.get(name);
|
|
97
|
+
if (first !== undefined)
|
|
98
|
+
refuse({ word: "duplicate_name", entry, first });
|
|
99
|
+
firstIndexOf.set(name, entry);
|
|
100
|
+
packages.push({ name, dir, tier, ...(Object.hasOwn(item, "options") ? { options: item.options } : {}) });
|
|
101
|
+
}
|
|
102
|
+
const [head, ...tail] = packages;
|
|
103
|
+
if (head === undefined)
|
|
104
|
+
return undeclared;
|
|
105
|
+
if (root === undefined)
|
|
106
|
+
refuse({ word: "root_missing" });
|
|
107
|
+
return { root, packages: [head, ...tail] };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=mods-declaration.js.map
|
|
@@ -42,7 +42,7 @@ export type UnmatchableRuleName = Exclude<RuleToolNameVerdict, {
|
|
|
42
42
|
/**
|
|
43
43
|
* **运维名表的态度** —— 一个常量,判官与匹配器同读(core 7.55.0 [ref])。本仓的名表消费者(env `APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO`、
|
|
44
44
|
* 中心下发的 `approvalRequire`、请求 `settings.permissions` 的 neverAuto 座)全是**限制表**(要求审批 / 硬拦 / 禁自动答):引擎对一个名字在限制表里的读法
|
|
45
|
-
* (`judgeRuleToolName(name, 名册, behavior)` 收不收、`
|
|
45
|
+
* (`judgeRuleToolName(name, 名册, behavior)` 收不收、`isCoveringRuleName(name, behavior)` 够着哪些工具)只分「限制 / 放行」两侧 —— 整个协议的名字
|
|
46
46
|
* `mcp__*` / `mcp__*__*` 在 deny 与 ask 里同读成这一协议的每一只工具。受理口的判(`config.ts`)与运行期的匹配(`approval.ts`)读同一个态度,一张表不会一边收、一边什么也不拦。
|
|
47
47
|
*/
|
|
48
48
|
export declare const NAME_TABLE_BEHAVIOR: "deny";
|
|
@@ -9,4 +9,9 @@ export declare function errorText(e: unknown): string;
|
|
|
9
9
|
* `name` 的 getter 抛、或它交回的不是字符串(拼进模板串会抛的 Symbol 等)⇒ `<unreadable>`。
|
|
10
10
|
*/
|
|
11
11
|
export declare function errorKindOf(err: unknown): string;
|
|
12
|
+
/**
|
|
13
|
+
* 错误自带的机器码(`err.code` 串:Node 的 `ENOENT`、引擎的 `config.mods_invalid` …)—— 第三只读口,同一处兜底 {@link readOr}:`code` 的 getter 抛 / 代理抛 /
|
|
14
|
+
* 不是串 ⇒ `undefined`(没有码,不编一个)。调用方按自己的形判(什么样的码配进一句拒句)再用它。
|
|
15
|
+
*/
|
|
16
|
+
export declare function errorCodeOf(err: unknown): string | undefined;
|
|
12
17
|
//# sourceMappingURL=err-text.d.ts.map
|
|
@@ -21,4 +21,13 @@ export function errorKindOf(err) {
|
|
|
21
21
|
return typeof name === "string" ? name : KIND_UNREADABLE;
|
|
22
22
|
}, KIND_UNREADABLE);
|
|
23
23
|
}
|
|
24
|
+
export function errorCodeOf(err) {
|
|
25
|
+
const code = readOr(() => {
|
|
26
|
+
if (!(err instanceof Error) || !("code" in err))
|
|
27
|
+
return "";
|
|
28
|
+
const c = err.code;
|
|
29
|
+
return typeof c === "string" ? c : "";
|
|
30
|
+
}, "");
|
|
31
|
+
return code === "" ? undefined : code;
|
|
32
|
+
}
|
|
24
33
|
//# sourceMappingURL=err-text.js.map
|
|
@@ -193,7 +193,7 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
193
193
|
};
|
|
194
194
|
readonly "server.approvals.durable-row-checkpoint-id-missing": {
|
|
195
195
|
readonly cls: "F";
|
|
196
|
-
readonly note: "7.133.0(`checkpoint-identity.ts` 的 `durableRowIdentity`;两只店的 `listPending` + `/v1/assistant/inbox` handler):三处 durable 读面(运维队列行 `GET /v1/approvals` 与 `/v1/approvals/stream` 的 `pending` 帧;停驻收件 `GET /v1/assistant/inbox` 的行)读到一行停驻门**没有可用的 `checkpointId`** ⇒ 这一行**照列、`checkpointId` 键缺席**(消费方按「这一行没有可 join 的身份」处理)。detail = `face=<approvals-queue|assistant-inbox> why=<absent|untrusted>`:`absent` = 行上没有这一格(core 5.42.0 之前停驻的老行 —— core 明写不回填);`untrusted` = 在场却没过信任边界(非串 / 空串 / 超长 / 含 resume token —— 数据污染;没过边界的值不上 wire)。放行(列、键缺席)的最坏后果 = 消费方对这一行做不了跨面 join(三面对账少一行)—— 行本身、决断口(`/v1/approvals/:sessionId/decide`,按会话)、到期收割都照常。不放行有两种形:整只拒的代价是一行老 / 坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧);把这一行藏起来的代价更糟 —— 人看不到要批的东西(审批面上的 fail-open,方向反了)。故 F 类;必须留痕(两种成因从此可分)。计数非零 = 有老 / 坏行在飞(列着、没身份);`/stream` 每 3s 一拍重读,同一行每拍计一次(量值 = 行 × 拍数,在场才是信号)。";
|
|
196
|
+
readonly note: "7.133.0(`checkpoint-identity.ts` 的 `durableRowIdentity`;两只店的 `listPending` + `/v1/assistant/inbox` handler):三处 durable 读面(运维队列行 `GET /v1/approvals` 与 `/v1/approvals/stream` 的 `pending` 帧;停驻收件 `GET /v1/assistant/inbox` 的行)读到一行停驻门**没有可用的 `checkpointId`** ⇒ 这一行**照列、`checkpointId` 键缺席**(消费方按「这一行没有可 join 的身份」处理)。detail = `face=<approvals-queue|assistant-inbox> why=<absent|untrusted>`:`absent` = 行上没有这一格(core 5.42.0 之前停驻的老行 —— core 明写不回填);`untrusted` = 在场却没过信任边界(非串 / 空串 / 超长 / 含 resume token —— 数据污染;没过边界的值不上 wire)。放行(列、键缺席)的最坏后果 = 消费方对这一行做不了跨面 join(三面对账少一行)—— 行本身、决断口(`/v1/approvals/:sessionId/decide`,按会话)、到期收割都照常。不放行有两种形:整只拒的代价是一行老 / 坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧);把这一行藏起来的代价更糟 —— 人看不到要批的东西(审批面上的 fail-open,方向反了)。故 F 类;必须留痕(两种成因从此可分)。计数非零 = 有老 / 坏行在飞(列着、没身份);`/stream` 每 3s 一拍重读,同一行每拍计一次(量值 = 行 × 拍数,在场才是信号)。 7.137.0 起第四面:park 账本行(`GET /v1/runs/:id/events` 的 `suspended` / `needs_review`;唯一构造器 `trace/project.ts` 的 `parkEventData`,写时判一次,detail `face=run-events-park`)—— 暂停因由上的门身份没过信任边界 ⇒ 行照写、`checkpointId` 键缺席(决断方回显不了这道门,退回不带键的决断或从 run 结果取原值;行本身、门、待批调用身份照常)。 第五面:回决门族的 200 体(`/decide` / `/resume` / `/plan_review` 执行之前从选中的那一行捕获一次,`http/resume-legs.ts` 三处;detail `face=decision-receipt`)—— 选中那一行的门身份没过信任边界 ⇒ 结清证据照铸、体上 `checkpointId` 键缺席(决断方只是对不上身份;位、决定、续跑都照常)。每次走到捕获点的决断计一次(计的是选中那一行的事实,与这次决断随后走哪条车道无关)。";
|
|
197
197
|
};
|
|
198
198
|
readonly "server.approvals.queue-row-gate-kind-missing": {
|
|
199
199
|
readonly cls: "F";
|
|
@@ -279,6 +279,10 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
279
279
|
readonly cls: "F";
|
|
280
280
|
readonly note: "S-690(`instruction-source-notice.ts announceInstructionSource`,项目指令换源通告的唯一铸点;detail 的 `op` 点名哪一步):基线**读**失败或超期(会话店抖动 / 列形坏 / 2s 期限到,detail 带 `timeout=`)⇒ 本 run 不比也不写;基线**写**失败或超期 ⇒ 本 run 的换源帧照发(它对本 run 为真),下一 run 可能再说一遍同一次换源(超期后才落地的写由 CAS 挡住,盖不掉更新的基线);通告**出口**抛 ⇒ 本 run 缺这一帧。放行的最坏后果 = 一次换源没被说出来或被多说一次 —— 通告是**披露**面,不参与任何门 / 裁决,模型读到的指令本身不受影响。不放行的代价严重不对称:铸点跑在 core 的 `loadProjectMemory` 席内,抛回去 core 会把这次 prepare 的项目记忆整块丢掉(不注入),为一条通告赔上指令本身。计数让「某台部署的会话店一直读不出基线」与「这台部署从来没换过源」在遥测上分得开。";
|
|
281
281
|
};
|
|
282
|
+
readonly "server.session-workspace.record-degraded": {
|
|
283
|
+
readonly cls: "F";
|
|
284
|
+
readonly note: "会话行的位置与项目那一格(`session_meta.workspace` / local `session-workspaces.json`;唯一写者 `session-workspace.ts` 的腿记录座,唯一列属主 `plugins/session-workspace-cell.ts`;detail 的 `op` 点名哪一步):`op=write` 一次写失败(库抖 / 盘满 / 锁等待超时)⇒ 行停在上一帧,下一帧照写;`op=read` 一格读不出(被带外改坏)⇒ 读作没有记录,下一帧整格重写;`op=frame` 一帧投不成存储形(引擎不会铸出这种帧)⇒ 这一帧不记。这一格是宿主对**引擎判过的答案**的记录,不是判据 —— 引擎每条腿都重判项目(有记号就判记号,声明不等响亮拒)。放行的最坏后果 = 这只会话的下一条不带 `projectId` 的提交续声明的是旧的项目或不声明(没有记号的检出里这只会话少一次续声明);不放行的代价是把一条在跑的腿、或这只会话往后的每一次提交,为一份记录摔掉。计数非零 = 这台部署的会话店写不动 / 有人改过库。";
|
|
285
|
+
};
|
|
282
286
|
readonly "server.engine-notice.wire-sink-threw": {
|
|
283
287
|
readonly cls: "F";
|
|
284
288
|
readonly note: "#310:`engine_notice` 分流器把一条白名单通告投给某条 run 腿的登记口时,那只口抛了(live 口写向已断/已撕裂的 SSE socket,或 durable 口的账本写同步抛)。放行的最坏后果 = **这一条通告的这一个终点**缺席:①日志终点在分流之前已经逐字打过(事实一条不丢);②两个终点注册成两只独立 sink ⇒ live 抛不牵连 durable(断连后仍看得见的那半保住);③同会话其余口照投。故 F 类。不放行的代价是把异常回抛给 core 的 `deliverEngineNotice` —— 它会吞掉,于是同一次失败**既没有留痕也没有第二只口**,正是本 tag 要根除的形。留痕是承重的:静默吞掉之后「wire 腿为什么总有几条通告不到」在遥测里与「core 本来就没发」同形。";
|
|
@@ -499,6 +503,18 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
499
503
|
readonly cls: "F";
|
|
500
504
|
readonly note: "k8s 车道工作区空间结束时对**快照对象**的回收(`plugins/remote-env-k8s.ts` `createSpaceReclaimer` 的对象部分;与上一条同一只回收座、两条腿:会话删除协调器与托管留存 sweep):按空间的 `<前缀>/<化身>/space/` 分区(快照 + `latest`)和该会话停驻车道里名字带被结束住客归属记号的 `<前缀>/<会话 id>/*.tar.gz` 分别 LIST、逐个预签 DELETE;LIST 失败、DELETE 失败(HTTP 非 2xx / 非 404、网络)LIST 超过 1000 个对象被截断,或回收座一次调用的绝对截止(= 快照时限;卷回收也在内)到点〔切断在途请求、停掉余下的;这次调用里还没轮到的空间零请求、各记一次;没删的归生命周期规则〕,各记一次(detail `lane=space|park stage=list|delete|budget`;会话删除口把回收座脱离应答路径,座若抛了——契约禁止——记 `stage=seat_threw`)⇒ 这些对象留在桶里,会话照删(不挡删除)。放行的最坏后果 = 一份已无人能读的工作区快照留在桶里(会话已删,经 API 不可达;内容是用户工作区,所以不是「只占盘」—— 留到桶的生命周期规则把它过期掉为止);不碰任何别的空间、不是门不是凭据;反方向(清不掉对象就拒删会话)会让一个对象存储抖动挡住用户的删除权。故 F 类,但必须留痕:静默吞掉之后「这个会话删了、它的工作区内容还在不在桶里」在遥测里没有任何痕迹。同拍一行 `workspace_space_reclaim_failed`(`space` 前缀 / `sessionId` / `lane` / `stage` / `count` / `error`;一次调用里同类〔分区 × 阶段〕的失败合成一行,`count` = 撞上它的空间数,其余键点名调用里排第一的那个,计数仍逐空间;回收座同一时刻最多 4 个空间在收,sweep 与会话删除共用这一只门)。计数非零 = 有对象没回收掉,运维按行里的空间前缀 / 会话 id 去桶里手清,并核对象存储的可达性与 DELETE 权限。回收与同一空间的尚在途的 run 末提交不是互斥的:会话删除时没有活 run(409 挡),但上一条 run 的提交若恰在删除之后才落对象,这批对象不在本次回收射程内(同样归桶的生命周期规则)。停驻分区按会话 id 分区,所以只删名字带被结束住客归属记号的对象(不读任何钟)—— 会话 id 删后被别人重新登记,新住客停驻出的快照带它自己的记号、不碰;不带记号的旧形与 `none` 留给桶的生命周期规则。";
|
|
501
505
|
};
|
|
506
|
+
readonly "server.sandbox-secret.seat-unverified": {
|
|
507
|
+
readonly cls: "F";
|
|
508
|
+
readonly note: "k8s 车道沙箱秘密座的起服核(`boot/execution-env.ts` `ensureSandboxSecretSeat`,第 5 段 await;只在 `K8S_SANDBOX_ENV` 点到了本进程环境里有的键时问):对沙箱命名空间 secrets 的 env 座那一行动词(create —— 适配器为 env Secret 真发的调用)各发一次 SelfSubjectAccessReview,**问不到**(请求失败 / 审查本身被拒 / 答复没有布尔 `status.allowed`)而没有一个动词答「不许」⇒ 照常起服(答了「不许」⇒ 拒启,不走本 tag)。放行的最坏后果 = RBAC 真缺时第一个要建 Secret 的 run 在连接时被拒(`auth_failed`)、它的 pod 被删 —— 名单值仍然只经该 pod 自己的 Secret,不回落成 pod spec 里的明文;不是门不是凭据的放宽,只是把「缺 RBAC」从起服挪到了第一次连接。detail = `namespace=<ns>` + 每个没问到的动词与原因(不带值)。同拍一行 `sandbox_secret_seat_unverified`。计数非零 = 这台部署起服时没能确认 Secret 动词,按 detail 核 API 可达性与该服务账号能不能建 SelfSubjectAccessReview。";
|
|
509
|
+
};
|
|
510
|
+
readonly "server.sandbox-pod-reaper.list-failed": {
|
|
511
|
+
readonly cls: "F";
|
|
512
|
+
readonly note: "k8s 车道沙箱 Pod 回收器(`plugins/k8s-pod-reaper.ts` `reapOnce`,维护 tick 每副本每 5 分钟一轮)按身份标签列沙箱命名空间的 Pod **失败**(API 不可达 / 403 / 非 2xx)⇒ 这一轮一只都不删、不抛,下一轮一个周期后照常再列。最坏后果 = 已结束的沙箱 Pod 与已终 run 的 Pod(连同它们以 `ownerReferences` 挂着的 Secret —— 部署名单值 / 成员凭据租约)在 etcd 里多留至少一个周期:是**静态数据**多留,不是凭据被用 —— 成员凭据的使用界是代理的租约(到点 destroy,不随回收器);run 收尾的正常删除路不经本腿。不是门 / 凭据的放宽 ⇒ F。计数逐轮一次 + 探针行(`namespace=` + 原因)+ 同拍一行 warn `sandbox_pod_reap_list_failed`;修前只一行 info 轮次行(`listed:false`),不计数、不响。计数持续非零 = 回收器连续列不到 Pod,按原因核 API 可达性与 Role 的 pods `list`。";
|
|
513
|
+
};
|
|
514
|
+
readonly "server.sandbox-pod.delete-failed": {
|
|
515
|
+
readonly cls: "F";
|
|
516
|
+
readonly note: "k8s 车道**删一只沙箱 pod 却没删成**,两个座一只上报口(`plugins/k8s-pod-delete-failure.ts` `reportPodDeleteFailed`;detail = `namespace=<ns> pod=<名> why=<原因词> cause=<http_<状态>|request_failed>`):①连接清理座(`plugins/remote-env-k8s.ts` `discardRefusedPod`,`why` = `env_secret_unsealed|lease_secret_unsealed|broker_image_pull_failed`):env Secret / 租约 Secret 建不成、或代理镜像拉不下 ⇒ 连接被拒、该 pod 要删,而这一删本身失败(请求抛 / API 回 403、5xx 等非 2xx 非 404)⇒ 拒答不变(仍是原来那一条),pod 与挂在它名下的 Secret(部署名单值 / 租约占位)留在命名空间里,由回收器兜(`plugins/k8s-pod-reaper.ts`:带 run 标签的按 run 终态删,不带的等容器全部结束后删);②回收器座(`plugins/k8s-pod-reaper.ts` `reapOnce` 的删一步,`why` = `reaper_containers_ended|reaper_run_ended_past_hold`):兜底本身删失败 ⇒ 这一只留到下一轮(一个周期后)再判再删,一只失败不挡同轮其余。最坏后果 = **静态数据**多留至少一个回收周期(与 `server.sandbox-pod-reaper.list-failed` 同一件事的另一半):没有值进 pod spec、没有连接被放过、成员凭据的使用界是代理的租约 ⇒ 不是门 / 凭据的放宽 ⇒ F。计数逐次 + 探针行 + 同拍一行 error `sandbox_pod_delete_failed`(pod / 命名空间 / 原因词 / 原因码,不带值、不带 API 文本;运维行座缺席或只有 warn 的座上行不发、计数照记);修前连接清理三处 `.catch(() => {})` 吞,零日志零计数,回收器的删失败只落一行 warn(不计数)。计数持续非零 = 删 pod 的 Role 动词(pods `delete`)或 API 可达性有问题,按 `cause` 核;`why` 以 `reaper_` 起头的计数持续非零 = 兜底本身删不动,残留会随轮次累积。";
|
|
517
|
+
};
|
|
502
518
|
readonly "server.sandbox-egress.policy-gap": {
|
|
503
519
|
readonly cls: "P-DEBT";
|
|
504
520
|
readonly note: "k8s 车道沙箱出网的起服自检(`plugins/remote-env-k8s.ts` `checkSandboxEgressPolicy` 读节点表与沙箱 ns 的 NetworkPolicy,判法 `sandbox-egress-policy.ts` `sandboxEgressGaps`;起服一次、不挡起服)读出一个缺口 —— 某节点的 InternalIP / ExternalIP 落在一条放行 ipBlock 内(`kind=node_address_open`)、没有策略以 Egress 选中沙箱 pod(`kind=policy_absent`)、pod 保留 IPv6 而策略层担保不了 v6(`kind=ipv6_enabled`)、节点表或策略表读不到(`kind=unreadable what=nodes|networkpolicies`)⇒ 车道**照常起**,每个缺口一行 `sandbox_egress_policy_gap`(带后果句与去哪改)。归 P 类:出网策略是保护面,缺口意味着沙箱里的代码可能够到节点上的服务;归 DEBT 的理由:修法都在集群配置里(节点地址点名、kubelet 放行 v6 sysctl、CNI 的 v6 执行、RBAC),本服务改不了,而拒起车道会让缺省单节点装法(恒有 `ipv6_enabled`)升级即停摆沙箱执行 —— 车道自己的隔离(VM 边界、零 SA token)仍在。放行的最坏后果 = 读出缺口的那一面照旧可达,直到运维按行里的后果句改配置。计数非零 = 这台部署的沙箱出网面有读得出的缺口。读不出的面(宿主 DNAT 发布端口、「pod 所在节点恒放行」的实现差异、CNI 根本不执行策略)不在本 tag 的射程里。";
|
|
@@ -174,7 +174,7 @@ export const FAIL_OPEN_TAGS = {
|
|
|
174
174
|
},
|
|
175
175
|
"server.approvals.durable-row-checkpoint-id-missing": {
|
|
176
176
|
cls: "F",
|
|
177
|
-
note: "7.133.0(`checkpoint-identity.ts` 的 `durableRowIdentity`;两只店的 `listPending` + `/v1/assistant/inbox` handler):三处 durable 读面(运维队列行 `GET /v1/approvals` 与 `/v1/approvals/stream` 的 `pending` 帧;停驻收件 `GET /v1/assistant/inbox` 的行)读到一行停驻门**没有可用的 `checkpointId`** ⇒ 这一行**照列、`checkpointId` 键缺席**(消费方按「这一行没有可 join 的身份」处理)。detail = `face=<approvals-queue|assistant-inbox> why=<absent|untrusted>`:`absent` = 行上没有这一格(core 5.42.0 之前停驻的老行 —— core 明写不回填);`untrusted` = 在场却没过信任边界(非串 / 空串 / 超长 / 含 resume token —— 数据污染;没过边界的值不上 wire)。放行(列、键缺席)的最坏后果 = 消费方对这一行做不了跨面 join(三面对账少一行)—— 行本身、决断口(`/v1/approvals/:sessionId/decide`,按会话)、到期收割都照常。不放行有两种形:整只拒的代价是一行老 / 坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧);把这一行藏起来的代价更糟 —— 人看不到要批的东西(审批面上的 fail-open,方向反了)。故 F 类;必须留痕(两种成因从此可分)。计数非零 = 有老 / 坏行在飞(列着、没身份);`/stream` 每 3s 一拍重读,同一行每拍计一次(量值 = 行 × 拍数,在场才是信号)。",
|
|
177
|
+
note: "7.133.0(`checkpoint-identity.ts` 的 `durableRowIdentity`;两只店的 `listPending` + `/v1/assistant/inbox` handler):三处 durable 读面(运维队列行 `GET /v1/approvals` 与 `/v1/approvals/stream` 的 `pending` 帧;停驻收件 `GET /v1/assistant/inbox` 的行)读到一行停驻门**没有可用的 `checkpointId`** ⇒ 这一行**照列、`checkpointId` 键缺席**(消费方按「这一行没有可 join 的身份」处理)。detail = `face=<approvals-queue|assistant-inbox> why=<absent|untrusted>`:`absent` = 行上没有这一格(core 5.42.0 之前停驻的老行 —— core 明写不回填);`untrusted` = 在场却没过信任边界(非串 / 空串 / 超长 / 含 resume token —— 数据污染;没过边界的值不上 wire)。放行(列、键缺席)的最坏后果 = 消费方对这一行做不了跨面 join(三面对账少一行)—— 行本身、决断口(`/v1/approvals/:sessionId/decide`,按会话)、到期收割都照常。不放行有两种形:整只拒的代价是一行老 / 坏行打掉整个租户的队列(列表 500、SSE 心跳照常而队列永远停在旧帧);把这一行藏起来的代价更糟 —— 人看不到要批的东西(审批面上的 fail-open,方向反了)。故 F 类;必须留痕(两种成因从此可分)。计数非零 = 有老 / 坏行在飞(列着、没身份);`/stream` 每 3s 一拍重读,同一行每拍计一次(量值 = 行 × 拍数,在场才是信号)。 7.137.0 起第四面:park 账本行(`GET /v1/runs/:id/events` 的 `suspended` / `needs_review`;唯一构造器 `trace/project.ts` 的 `parkEventData`,写时判一次,detail `face=run-events-park`)—— 暂停因由上的门身份没过信任边界 ⇒ 行照写、`checkpointId` 键缺席(决断方回显不了这道门,退回不带键的决断或从 run 结果取原值;行本身、门、待批调用身份照常)。 第五面:回决门族的 200 体(`/decide` / `/resume` / `/plan_review` 执行之前从选中的那一行捕获一次,`http/resume-legs.ts` 三处;detail `face=decision-receipt`)—— 选中那一行的门身份没过信任边界 ⇒ 结清证据照铸、体上 `checkpointId` 键缺席(决断方只是对不上身份;位、决定、续跑都照常)。每次走到捕获点的决断计一次(计的是选中那一行的事实,与这次决断随后走哪条车道无关)。",
|
|
178
178
|
},
|
|
179
179
|
"server.approvals.queue-row-gate-kind-missing": {
|
|
180
180
|
cls: "F",
|
|
@@ -260,6 +260,10 @@ export const FAIL_OPEN_TAGS = {
|
|
|
260
260
|
cls: "F",
|
|
261
261
|
note: "S-690(`instruction-source-notice.ts announceInstructionSource`,项目指令换源通告的唯一铸点;detail 的 `op` 点名哪一步):基线**读**失败或超期(会话店抖动 / 列形坏 / 2s 期限到,detail 带 `timeout=`)⇒ 本 run 不比也不写;基线**写**失败或超期 ⇒ 本 run 的换源帧照发(它对本 run 为真),下一 run 可能再说一遍同一次换源(超期后才落地的写由 CAS 挡住,盖不掉更新的基线);通告**出口**抛 ⇒ 本 run 缺这一帧。放行的最坏后果 = 一次换源没被说出来或被多说一次 —— 通告是**披露**面,不参与任何门 / 裁决,模型读到的指令本身不受影响。不放行的代价严重不对称:铸点跑在 core 的 `loadProjectMemory` 席内,抛回去 core 会把这次 prepare 的项目记忆整块丢掉(不注入),为一条通告赔上指令本身。计数让「某台部署的会话店一直读不出基线」与「这台部署从来没换过源」在遥测上分得开。",
|
|
262
262
|
},
|
|
263
|
+
"server.session-workspace.record-degraded": {
|
|
264
|
+
cls: "F",
|
|
265
|
+
note: "会话行的位置与项目那一格(`session_meta.workspace` / local `session-workspaces.json`;唯一写者 `session-workspace.ts` 的腿记录座,唯一列属主 `plugins/session-workspace-cell.ts`;detail 的 `op` 点名哪一步):`op=write` 一次写失败(库抖 / 盘满 / 锁等待超时)⇒ 行停在上一帧,下一帧照写;`op=read` 一格读不出(被带外改坏)⇒ 读作没有记录,下一帧整格重写;`op=frame` 一帧投不成存储形(引擎不会铸出这种帧)⇒ 这一帧不记。这一格是宿主对**引擎判过的答案**的记录,不是判据 —— 引擎每条腿都重判项目(有记号就判记号,声明不等响亮拒)。放行的最坏后果 = 这只会话的下一条不带 `projectId` 的提交续声明的是旧的项目或不声明(没有记号的检出里这只会话少一次续声明);不放行的代价是把一条在跑的腿、或这只会话往后的每一次提交,为一份记录摔掉。计数非零 = 这台部署的会话店写不动 / 有人改过库。",
|
|
266
|
+
},
|
|
263
267
|
"server.engine-notice.wire-sink-threw": {
|
|
264
268
|
cls: "F",
|
|
265
269
|
note: "#310:`engine_notice` 分流器把一条白名单通告投给某条 run 腿的登记口时,那只口抛了(live 口写向已断/已撕裂的 SSE socket,或 durable 口的账本写同步抛)。放行的最坏后果 = **这一条通告的这一个终点**缺席:①日志终点在分流之前已经逐字打过(事实一条不丢);②两个终点注册成两只独立 sink ⇒ live 抛不牵连 durable(断连后仍看得见的那半保住);③同会话其余口照投。故 F 类。不放行的代价是把异常回抛给 core 的 `deliverEngineNotice` —— 它会吞掉,于是同一次失败**既没有留痕也没有第二只口**,正是本 tag 要根除的形。留痕是承重的:静默吞掉之后「wire 腿为什么总有几条通告不到」在遥测里与「core 本来就没发」同形。",
|
|
@@ -459,6 +463,18 @@ export const FAIL_OPEN_TAGS = {
|
|
|
459
463
|
cls: "F",
|
|
460
464
|
note: "k8s 车道工作区空间结束时对**快照对象**的回收(`plugins/remote-env-k8s.ts` `createSpaceReclaimer` 的对象部分;与上一条同一只回收座、两条腿:会话删除协调器与托管留存 sweep):按空间的 `<前缀>/<化身>/space/` 分区(快照 + `latest`)和该会话停驻车道里名字带被结束住客归属记号的 `<前缀>/<会话 id>/*.tar.gz` 分别 LIST、逐个预签 DELETE;LIST 失败、DELETE 失败(HTTP 非 2xx / 非 404、网络)LIST 超过 1000 个对象被截断,或回收座一次调用的绝对截止(= 快照时限;卷回收也在内)到点〔切断在途请求、停掉余下的;这次调用里还没轮到的空间零请求、各记一次;没删的归生命周期规则〕,各记一次(detail `lane=space|park stage=list|delete|budget`;会话删除口把回收座脱离应答路径,座若抛了——契约禁止——记 `stage=seat_threw`)⇒ 这些对象留在桶里,会话照删(不挡删除)。放行的最坏后果 = 一份已无人能读的工作区快照留在桶里(会话已删,经 API 不可达;内容是用户工作区,所以不是「只占盘」—— 留到桶的生命周期规则把它过期掉为止);不碰任何别的空间、不是门不是凭据;反方向(清不掉对象就拒删会话)会让一个对象存储抖动挡住用户的删除权。故 F 类,但必须留痕:静默吞掉之后「这个会话删了、它的工作区内容还在不在桶里」在遥测里没有任何痕迹。同拍一行 `workspace_space_reclaim_failed`(`space` 前缀 / `sessionId` / `lane` / `stage` / `count` / `error`;一次调用里同类〔分区 × 阶段〕的失败合成一行,`count` = 撞上它的空间数,其余键点名调用里排第一的那个,计数仍逐空间;回收座同一时刻最多 4 个空间在收,sweep 与会话删除共用这一只门)。计数非零 = 有对象没回收掉,运维按行里的空间前缀 / 会话 id 去桶里手清,并核对象存储的可达性与 DELETE 权限。回收与同一空间的尚在途的 run 末提交不是互斥的:会话删除时没有活 run(409 挡),但上一条 run 的提交若恰在删除之后才落对象,这批对象不在本次回收射程内(同样归桶的生命周期规则)。停驻分区按会话 id 分区,所以只删名字带被结束住客归属记号的对象(不读任何钟)—— 会话 id 删后被别人重新登记,新住客停驻出的快照带它自己的记号、不碰;不带记号的旧形与 `none` 留给桶的生命周期规则。",
|
|
461
465
|
},
|
|
466
|
+
"server.sandbox-secret.seat-unverified": {
|
|
467
|
+
cls: "F",
|
|
468
|
+
note: "k8s 车道沙箱秘密座的起服核(`boot/execution-env.ts` `ensureSandboxSecretSeat`,第 5 段 await;只在 `K8S_SANDBOX_ENV` 点到了本进程环境里有的键时问):对沙箱命名空间 secrets 的 env 座那一行动词(create —— 适配器为 env Secret 真发的调用)各发一次 SelfSubjectAccessReview,**问不到**(请求失败 / 审查本身被拒 / 答复没有布尔 `status.allowed`)而没有一个动词答「不许」⇒ 照常起服(答了「不许」⇒ 拒启,不走本 tag)。放行的最坏后果 = RBAC 真缺时第一个要建 Secret 的 run 在连接时被拒(`auth_failed`)、它的 pod 被删 —— 名单值仍然只经该 pod 自己的 Secret,不回落成 pod spec 里的明文;不是门不是凭据的放宽,只是把「缺 RBAC」从起服挪到了第一次连接。detail = `namespace=<ns>` + 每个没问到的动词与原因(不带值)。同拍一行 `sandbox_secret_seat_unverified`。计数非零 = 这台部署起服时没能确认 Secret 动词,按 detail 核 API 可达性与该服务账号能不能建 SelfSubjectAccessReview。",
|
|
469
|
+
},
|
|
470
|
+
"server.sandbox-pod-reaper.list-failed": {
|
|
471
|
+
cls: "F",
|
|
472
|
+
note: "k8s 车道沙箱 Pod 回收器(`plugins/k8s-pod-reaper.ts` `reapOnce`,维护 tick 每副本每 5 分钟一轮)按身份标签列沙箱命名空间的 Pod **失败**(API 不可达 / 403 / 非 2xx)⇒ 这一轮一只都不删、不抛,下一轮一个周期后照常再列。最坏后果 = 已结束的沙箱 Pod 与已终 run 的 Pod(连同它们以 `ownerReferences` 挂着的 Secret —— 部署名单值 / 成员凭据租约)在 etcd 里多留至少一个周期:是**静态数据**多留,不是凭据被用 —— 成员凭据的使用界是代理的租约(到点 destroy,不随回收器);run 收尾的正常删除路不经本腿。不是门 / 凭据的放宽 ⇒ F。计数逐轮一次 + 探针行(`namespace=` + 原因)+ 同拍一行 warn `sandbox_pod_reap_list_failed`;修前只一行 info 轮次行(`listed:false`),不计数、不响。计数持续非零 = 回收器连续列不到 Pod,按原因核 API 可达性与 Role 的 pods `list`。",
|
|
473
|
+
},
|
|
474
|
+
"server.sandbox-pod.delete-failed": {
|
|
475
|
+
cls: "F",
|
|
476
|
+
note: "k8s 车道**删一只沙箱 pod 却没删成**,两个座一只上报口(`plugins/k8s-pod-delete-failure.ts` `reportPodDeleteFailed`;detail = `namespace=<ns> pod=<名> why=<原因词> cause=<http_<状态>|request_failed>`):①连接清理座(`plugins/remote-env-k8s.ts` `discardRefusedPod`,`why` = `env_secret_unsealed|lease_secret_unsealed|broker_image_pull_failed`):env Secret / 租约 Secret 建不成、或代理镜像拉不下 ⇒ 连接被拒、该 pod 要删,而这一删本身失败(请求抛 / API 回 403、5xx 等非 2xx 非 404)⇒ 拒答不变(仍是原来那一条),pod 与挂在它名下的 Secret(部署名单值 / 租约占位)留在命名空间里,由回收器兜(`plugins/k8s-pod-reaper.ts`:带 run 标签的按 run 终态删,不带的等容器全部结束后删);②回收器座(`plugins/k8s-pod-reaper.ts` `reapOnce` 的删一步,`why` = `reaper_containers_ended|reaper_run_ended_past_hold`):兜底本身删失败 ⇒ 这一只留到下一轮(一个周期后)再判再删,一只失败不挡同轮其余。最坏后果 = **静态数据**多留至少一个回收周期(与 `server.sandbox-pod-reaper.list-failed` 同一件事的另一半):没有值进 pod spec、没有连接被放过、成员凭据的使用界是代理的租约 ⇒ 不是门 / 凭据的放宽 ⇒ F。计数逐次 + 探针行 + 同拍一行 error `sandbox_pod_delete_failed`(pod / 命名空间 / 原因词 / 原因码,不带值、不带 API 文本;运维行座缺席或只有 warn 的座上行不发、计数照记);修前连接清理三处 `.catch(() => {})` 吞,零日志零计数,回收器的删失败只落一行 warn(不计数)。计数持续非零 = 删 pod 的 Role 动词(pods `delete`)或 API 可达性有问题,按 `cause` 核;`why` 以 `reaper_` 起头的计数持续非零 = 兜底本身删不动,残留会随轮次累积。",
|
|
477
|
+
},
|
|
462
478
|
"server.sandbox-egress.policy-gap": {
|
|
463
479
|
cls: "P-DEBT",
|
|
464
480
|
note: "k8s 车道沙箱出网的起服自检(`plugins/remote-env-k8s.ts` `checkSandboxEgressPolicy` 读节点表与沙箱 ns 的 NetworkPolicy,判法 `sandbox-egress-policy.ts` `sandboxEgressGaps`;起服一次、不挡起服)读出一个缺口 —— 某节点的 InternalIP / ExternalIP 落在一条放行 ipBlock 内(`kind=node_address_open`)、没有策略以 Egress 选中沙箱 pod(`kind=policy_absent`)、pod 保留 IPv6 而策略层担保不了 v6(`kind=ipv6_enabled`)、节点表或策略表读不到(`kind=unreadable what=nodes|networkpolicies`)⇒ 车道**照常起**,每个缺口一行 `sandbox_egress_policy_gap`(带后果句与去哪改)。归 P 类:出网策略是保护面,缺口意味着沙箱里的代码可能够到节点上的服务;归 DEBT 的理由:修法都在集群配置里(节点地址点名、kubelet 放行 v6 sysctl、CNI 的 v6 执行、RBAC),本服务改不了,而拒起车道会让缺省单节点装法(恒有 `ipv6_enabled`)升级即停摆沙箱执行 —— 车道自己的隔离(VM 边界、零 SA token)仍在。放行的最坏后果 = 读出缺口的那一面照旧可达,直到运维按行里的后果句改配置。计数非零 = 这台部署的沙箱出网面有读得出的缺口。读不出的面(宿主 DNAT 发布端口、「pod 所在节点恒放行」的实现差异、CNI 根本不执行策略)不在本 tag 的射程里。",
|
|
@@ -262,7 +262,6 @@ export function createMetrics() {
|
|
|
262
262
|
m.counter("resume_anchor_capture_failed", "E18 resume-at per-turn anchor captures that failed (best-effort, run unaffected)");
|
|
263
263
|
m.counter("brain_retry_total", "Brain-layer status events (S4), by phase (rate_limited/retrying/reconnecting/circuit_open/waiting_first_token/recovered/gave_up)");
|
|
264
264
|
m.gauge("store_backend_degraded", "1 when the auto DB probe failed at boot and this replica degraded to in-memory (S5)");
|
|
265
|
-
m.counter("images_omitted_total", "Tasks whose images will be degraded to text placeholders (no-vision model), by model (S6)");
|
|
266
265
|
m.counter("runs_reaped_total", "Run rows flipped by the background reapers (S7), by kind (stale/suspended/expired_checkpoint)");
|
|
267
266
|
m.counter("checkpoints_reaped_total", "Durable checkpoints expired by the backstop reaper (S7)");
|
|
268
267
|
m.counter("user_input_converged_total", "User-input acceptances (S-928 ledger) converged to crashed by the maintenance tick (the boot pass reports its count on the user_input_ledger_crash_converged warn line instead): steers accepted whose writer process ended before the run settled");
|
|
@@ -303,6 +302,7 @@ export function createMetrics() {
|
|
|
303
302
|
m.counter("remote_env_exec_idle_timeout_total", "Remote-env exec idle timeouts, by provider");
|
|
304
303
|
m.counter("remote_env_file_timeout_total", "Remote-env file-op timeouts, by provider");
|
|
305
304
|
m.counter("remote_env_rpc_timeout_total", "Remote-env RPC timeouts, by provider");
|
|
305
|
+
m.counter("sandbox_pods_reaped_total", "Sandbox pods deleted by the k8s lane's pod reaper, by reason (containers_ended: every container finished; run_ended_past_hold: the pod's run ended longer ago than the hold)");
|
|
306
306
|
m.counter("task_outcomes_total", "Task outcome-ledger rows recorded, by status and oracle green flag");
|
|
307
307
|
m.counter("workflow_runs_total", "Self-orchestration workflow runs, by status");
|
|
308
308
|
m.histogram("auth_bridge_verify_seconds", "Registry SSO JWT verify latency (hot path sub-ms; cold path includes a JWKS fetch)", [0.001, 0.005, 0.02, 0.1, 0.5, 2, 10]);
|
|
@@ -62,7 +62,7 @@ export declare const SECRET_ENV_SCRUB_SITES: {
|
|
|
62
62
|
readonly remedy: null;
|
|
63
63
|
};
|
|
64
64
|
readonly "server.hooks.spawn-env": {
|
|
65
|
-
readonly note: "settings hooks 的命令腿(请求带来的命令跑在宿主上)的 env —— 严格名单(`PATH` / `HOME` / 终端 / locale 等十二名)
|
|
65
|
+
readonly note: "settings hooks 的命令腿(请求带来的命令跑在宿主上)的 env —— 严格名单(`PATH` / `HOME` / 终端 / locale 等十二名)经引擎的 `hostChildEnv` 组合:名单外一律不交,本服务自有凭据任何情况都不交;请求的有效环境层(`settings.env`)作授予叠在上面;请求给工具 shell 的继承词对它不作用";
|
|
66
66
|
readonly remedy: null;
|
|
67
67
|
};
|
|
68
68
|
readonly "server.project-memory.git-subprocess": {
|
|
@@ -14,7 +14,7 @@ export const SECRET_ENV_SCRUB_SITES = {
|
|
|
14
14
|
remedy: null,
|
|
15
15
|
},
|
|
16
16
|
"server.hooks.spawn-env": {
|
|
17
|
-
note: "settings hooks 的命令腿(请求带来的命令跑在宿主上)的 env —— 严格名单(`PATH` / `HOME` / 终端 / locale 等十二名)
|
|
17
|
+
note: "settings hooks 的命令腿(请求带来的命令跑在宿主上)的 env —— 严格名单(`PATH` / `HOME` / 终端 / locale 等十二名)经引擎的 `hostChildEnv` 组合:名单外一律不交,本服务自有凭据任何情况都不交;请求的有效环境层(`settings.env`)作授予叠在上面;请求给工具 shell 的继承词对它不作用",
|
|
18
18
|
remedy: null,
|
|
19
19
|
},
|
|
20
20
|
"server.project-memory.git-subprocess": {
|
package/dist/operator-ask.d.ts
CHANGED
|
@@ -82,8 +82,8 @@ export declare function requestAlwaysHumanAsk(rule: string, message: string): Op
|
|
|
82
82
|
* 只加一位、从不放宽)。同步叶保持同步返回;叶抛照抛(fail-closed 的属主仍是叶)。
|
|
83
83
|
*
|
|
84
84
|
* **只收叶**:治理层(`runtime-governance.ts` `applyRuntimeGovernance`)对每一片叶各盖一次,再交 core `combinePolicies` 折**一次**
|
|
85
|
-
* (折叠是最外层,其输出原样交回 —— core 把落选 ask 的类(含本位带出的 `operator_forced`)
|
|
86
|
-
* 把一只折叠交给本函数 =
|
|
85
|
+
* (折叠是最外层,其输出原样交回 —— core 把落选 ask 的类(含本位带出的 `operator_forced`)记进它铸的认证记录 `attestation.foldedClasses`)。
|
|
86
|
+
* 把一只折叠交给本函数 = 在折叠的输出上再盖一次出身(只改幸存者自己的类)—— [ref] 收成「逐叶盖、折一次」,治理层只有一个折叠点。
|
|
87
87
|
*/
|
|
88
88
|
export declare function createDeploymentAuthoredPolicy(leaf: ToolPolicy): ToolPolicy;
|
|
89
89
|
//# sourceMappingURL=operator-ask.d.ts.map
|
|
@@ -16,7 +16,7 @@ async function shareAnOrg(directory, a, b) {
|
|
|
16
16
|
return false;
|
|
17
17
|
return Object.keys(la.scopes).some((org) => Object.hasOwn(lb.scopes, org));
|
|
18
18
|
}
|
|
19
|
-
const principalShaped = (s) =>
|
|
19
|
+
const principalShaped = (s) => principalShapeProblem(s) === undefined;
|
|
20
20
|
const fitsInboxKey = (recipient) => mailboxKeyProblem("scope", recipient) === undefined;
|
|
21
21
|
export function createOrgDeliveryGate(deps) {
|
|
22
22
|
const nowMs = deps.nowMs ?? Date.now;
|
|
@@ -19,8 +19,8 @@ import type { MemoryScopeAdmission } from "@sema-agent/core";
|
|
|
19
19
|
/**
|
|
20
20
|
* 单机腿:装载 `MEMORY_ORG_DIRECTORY_JSON`(`Record<principal, Record<orgScope, {write?}>>`)。启动期调用,
|
|
21
21
|
* **fail-loud**——任何非法直接 throw 且消息点名坏在哪个键(响亮拒是正确方向:一张半坏的授权表比拒绝
|
|
22
|
-
* 启动更危险)。principal 键复用 {@link assertPrincipalShape}(
|
|
23
|
-
* principal
|
|
22
|
+
* 启动更危险)。principal 键复用 {@link assertPrincipalShape}(拒不是名字的串 / 保留哨兵 / 超长租户名,与所有其它
|
|
23
|
+
* principal 入口同一道闸;拒句按键在 JSON 文本里的出现序点名,不回显不是名字的键 —— 对象的枚举序会把整数形的键排到最前,不能拿它编号);scope 键必须是 `org:` 前缀、值必须是仅含可选 `write: boolean` 的 plain object。
|
|
24
24
|
*/
|
|
25
25
|
export declare function parseOrgDirectoryStatic(json: string): Map<string, Record<string, {
|
|
26
26
|
write?: boolean;
|
|
@@ -2,6 +2,37 @@ import { PrincipalOrgMemoryWire } from "@sema-agent/settings-schema";
|
|
|
2
2
|
import { assertPrincipalShape } from "./security.js";
|
|
3
3
|
const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
4
4
|
const ORG_SCOPE_RE = /^org:\S+$/;
|
|
5
|
+
function topLevelKeysInTextOrder(json) {
|
|
6
|
+
const keys = [];
|
|
7
|
+
let depth = 0;
|
|
8
|
+
let expectKey = false;
|
|
9
|
+
for (let i = 0; i < json.length; i++) {
|
|
10
|
+
const c = json[i];
|
|
11
|
+
if (c === '"') {
|
|
12
|
+
let j = i + 1;
|
|
13
|
+
while (json[j] !== '"')
|
|
14
|
+
j += json[j] === "\\" ? 2 : 1;
|
|
15
|
+
if (depth === 1 && expectKey) {
|
|
16
|
+
const key = JSON.parse(json.slice(i, j + 1));
|
|
17
|
+
if (typeof key !== "string")
|
|
18
|
+
throw new Error("MEMORY_ORG_DIRECTORY_JSON: a top-level key did not decode as a string (scanner out of step with the JSON text)");
|
|
19
|
+
keys.push(key);
|
|
20
|
+
expectKey = false;
|
|
21
|
+
}
|
|
22
|
+
i = j;
|
|
23
|
+
}
|
|
24
|
+
else if (c === "{" || c === "[") {
|
|
25
|
+
depth++;
|
|
26
|
+
if (depth === 1)
|
|
27
|
+
expectKey = c === "{";
|
|
28
|
+
}
|
|
29
|
+
else if (c === "}" || c === "]")
|
|
30
|
+
depth--;
|
|
31
|
+
else if (c === "," && depth === 1)
|
|
32
|
+
expectKey = true;
|
|
33
|
+
}
|
|
34
|
+
return keys;
|
|
35
|
+
}
|
|
5
36
|
export function parseOrgDirectoryStatic(json) {
|
|
6
37
|
let parsed;
|
|
7
38
|
try {
|
|
@@ -14,8 +45,14 @@ export function parseOrgDirectoryStatic(json) {
|
|
|
14
45
|
throw new Error("MEMORY_ORG_DIRECTORY_JSON must be a JSON object: Record<principal, Record<orgScope, {write?: boolean}>>");
|
|
15
46
|
}
|
|
16
47
|
const table = new Map();
|
|
17
|
-
for (const [
|
|
18
|
-
|
|
48
|
+
for (const [n, principal] of topLevelKeysInTextOrder(json).entries()) {
|
|
49
|
+
try {
|
|
50
|
+
assertPrincipalShape(principal);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
throw new Error(`MEMORY_ORG_DIRECTORY_JSON principal key #${n + 1} (in text order): ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
54
|
+
}
|
|
55
|
+
const scopesRaw = parsed[principal];
|
|
19
56
|
if (!isPlainObject(scopesRaw)) {
|
|
20
57
|
throw new Error(`MEMORY_ORG_DIRECTORY_JSON[${JSON.stringify(principal)}] must be an object of org scopes`);
|
|
21
58
|
}
|