@sema-agent/server 7.105.0 → 7.107.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 +105 -0
- package/README.md +2 -2
- package/USAGE.md +135 -43
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +2 -0
- package/deploy/sema-up/cluster-up.sh +15 -2
- package/deploy/sema-up/kube-up.sh +8 -3
- package/deploy/sema-up/lib/flagshape.sh +29 -0
- package/deploy/sema-up/lib/parse-machines.py +4 -1
- package/deploy/sema-up/sema-up.sh +11 -9
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +3 -1
- package/dist/approval-card.d.ts +1 -1
- package/dist/approval.d.ts +6 -1
- package/dist/approval.js +4 -4
- package/dist/auth-bridge.d.ts +14 -0
- package/dist/auth-bridge.js +7 -0
- package/dist/auto-mode-face.d.ts +49 -40
- package/dist/auto-mode-face.js +6 -68
- package/dist/bench/s1/live-deps.d.ts +9 -2
- package/dist/bench/s1/live-deps.js +13 -8
- package/dist/boot/budget-tracing.js +3 -2
- package/dist/boot/config-center.d.ts +4 -0
- package/dist/boot/config-center.js +95 -37
- package/dist/boot/coordinators.d.ts +1 -0
- package/dist/boot/coordinators.js +3 -1
- package/dist/boot/device-lane.d.ts +2 -1
- package/dist/boot/execution-env.d.ts +11 -0
- package/dist/boot/execution-env.js +30 -6
- package/dist/boot/execution-lane.js +2 -3
- package/dist/boot/leader.d.ts +2 -1
- package/dist/boot/leader.js +2 -0
- package/dist/boot/parked-revive-gate.d.ts +10 -7
- package/dist/boot/parked-revive-gate.js +4 -11
- package/dist/boot/resolve-spec.d.ts +1 -4
- package/dist/boot/resolve-spec.js +44 -21
- package/dist/boot/runner-deps.d.ts +5 -8
- package/dist/boot/runner-deps.js +3 -9
- package/dist/boot/side-query-lane.d.ts +2 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +2 -1
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +3 -2
- package/dist/boot/stage-06-runners.js +2 -5
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +1 -2
- package/dist/boot/stage-08-reapers.d.ts +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -2
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -2
- package/dist/boot/stage-10-http-server.js +11 -7
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +6 -4
- package/dist/brain.d.ts +24 -2
- package/dist/brain.js +29 -10
- package/dist/budget.js +3 -0
- package/dist/capabilities/center-wiring.d.ts +64 -0
- package/dist/capabilities/center-wiring.js +24 -0
- package/dist/capabilities/composite-members.d.ts +89 -0
- package/dist/capabilities/composite-members.js +20 -0
- package/dist/capabilities/execution-lane.d.ts +3 -0
- package/dist/capabilities/execution-lane.js +5 -2
- package/dist/config-catalog.d.ts +35 -5
- package/dist/config-catalog.js +92 -26
- package/dist/config-center/apply-effective.d.ts +1 -1
- package/dist/config-center/apply-effective.js +7 -8
- package/dist/config-center/apply-ledger.d.ts +17 -0
- package/dist/config-center/apply-ledger.js +5 -0
- package/dist/config-center/center-request.d.ts +17 -0
- package/dist/config-center/center-request.js +4 -0
- package/dist/config-center/pull-state.d.ts +29 -0
- package/dist/config-center/pull-state.js +2 -0
- package/dist/config-types.d.ts +41 -14
- package/dist/config-types.js +1 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.js +69 -16
- package/dist/cross-session-settings.d.ts +1 -1
- package/dist/deployment-governance.d.ts +12 -1
- package/dist/deployment-governance.js +2 -0
- package/dist/execution-lane-caps.d.ts +30 -2
- package/dist/execution-lane-caps.js +12 -0
- package/dist/fleet-client.d.ts +18 -13
- package/dist/fleet-client.js +32 -22
- package/dist/fleet-lease.d.ts +72 -47
- package/dist/fleet-lease.js +66 -14
- package/dist/governance-http-status.d.ts +0 -1
- package/dist/governance-http-status.js +0 -1
- package/dist/hosted-posture.d.ts +6 -17
- package/dist/hosted-posture.js +11 -6
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +13 -1
- package/dist/http/dispatch.js +1 -1
- package/dist/http/durable-run-leg.js +2 -0
- package/dist/http/request-guards.d.ts +25 -0
- package/dist/http/request-guards.js +25 -5
- package/dist/http/resume-legs.js +19 -11
- package/dist/http/route-ctx.d.ts +9 -0
- package/dist/http/routes/approvals-assistant.js +0 -1
- package/dist/http/routes/capabilities.js +11 -12
- package/dist/http/routes/config-catalog.js +2 -1
- package/dist/http/routes/diagnostics.js +2 -0
- package/dist/http/routes/tasks.js +4 -1
- package/dist/http/server.d.ts +20 -4
- package/dist/http/session-inherit-env.d.ts +37 -0
- package/dist/http/session-inherit-env.js +6 -0
- package/dist/http/wire-types.d.ts +19 -28
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/key-resolver.d.ts +74 -19
- package/dist/key-resolver.js +65 -7
- package/dist/leader/leader.d.ts +6 -0
- package/dist/leader/leader.js +2 -1
- package/dist/leader/repair-wire.js +2 -1
- package/dist/leader/wire.d.ts +9 -1
- package/dist/leader/wire.js +10 -6
- package/dist/observability/fail-open.d.ts +5 -1
- package/dist/observability/fail-open.js +5 -1
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/permission-rule-events.d.ts +1 -1
- package/dist/observability/permission-rule-events.js +1 -1
- package/dist/observability/run-terminal.d.ts +40 -1
- package/dist/observability/run-terminal.js +2 -5
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/observability/tool-trace.d.ts +2 -0
- package/dist/operator-ask.d.ts +29 -1
- package/dist/operator-ask.js +6 -0
- package/dist/parked-decide.d.ts +14 -1
- package/dist/parked-decide.js +8 -1
- package/dist/plugins/session-policy-store-sql.d.ts +38 -7
- package/dist/plugins/session-policy-store-sql.js +64 -22
- package/dist/plugins/sql-driver.d.ts +1 -1
- package/dist/plugins/store-backend.d.ts +12 -3
- package/dist/plugins/store-backend.js +16 -5
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/read-face-posture.d.ts +4 -4
- package/dist/request-key-closure.js +2 -2
- package/dist/request-value-closure.d.ts +17 -5
- package/dist/request-value-closure.js +12 -0
- package/dist/router/route-orchestration.d.ts +11 -0
- package/dist/router/route-orchestration.js +7 -6
- package/dist/run-local.js +4 -2
- package/dist/runs.d.ts +2 -1
- package/dist/runs.js +4 -4
- package/dist/runtime-caps-resolver.d.ts +4 -10
- package/dist/runtime-governance.d.ts +8 -11
- package/dist/runtime-governance.js +10 -41
- package/dist/sealed-key.d.ts +0 -40
- package/dist/sealed-key.js +0 -20
- package/dist/server-secret-env.d.ts +11 -12
- package/dist/session-policy-wire.d.ts +5 -3
- package/dist/session-titler.d.ts +11 -0
- package/dist/session-titler.js +6 -2
- package/dist/sql-engine-posture.d.ts +2 -2
- package/dist/store-posture.d.ts +53 -0
- package/dist/store-posture.js +32 -0
- package/dist/task-settings.d.ts +64 -62
- package/dist/task-settings.js +57 -27
- package/dist/tool-approval.d.ts +51 -22
- package/dist/tool-approval.js +44 -8
- package/dist/tool-declaration-http-status.d.ts +12 -0
- package/dist/tool-declaration-http-status.js +12 -0
- package/dist/trace/core-keyset-guard.d.ts +7 -7
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +5 -0
- package/dist/trace/project.d.ts +7 -5
- package/dist/trace/project.js +51 -3
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/unattended-permission-mode.d.ts +110 -0
- package/dist/unattended-permission-mode.js +65 -0
- package/package.json +3 -3
- package/dist/boot/session-shell-gate-registry.d.ts +0 -39
- package/dist/boot/session-shell-gate-registry.js +0 -21
- package/dist/roster-bound-http-status.d.ts +0 -6
- package/dist/roster-bound-http-status.js +0 -6
package/dist/boot/stores.js
CHANGED
|
@@ -37,6 +37,7 @@ import { resolveStreamApprovalGate } from "../tool-approval.js";
|
|
|
37
37
|
import { buildMemoryBoundaryLaneFacts, buildMemoryWriteBoundaryAudit, effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
|
|
38
38
|
import { buildMemoryPosture } from "../memory-posture.js";
|
|
39
39
|
import { establishSqlEnginePosture } from "../sql-engine-posture.js";
|
|
40
|
+
import { buildStorePosture } from "../store-posture.js";
|
|
40
41
|
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
41
42
|
const DARK_REASON_PROSE = {
|
|
42
43
|
engine_off: () => "MEMORY_ENGINE=off",
|
|
@@ -46,16 +47,17 @@ const DARK_REASON_PROSE = {
|
|
|
46
47
|
export async function openStores(ctx) {
|
|
47
48
|
const { config, logger, metrics, localRoot } = ctx;
|
|
48
49
|
let backend;
|
|
49
|
-
let
|
|
50
|
+
let storeDegradedReason;
|
|
50
51
|
const wantDb = config.sessionBackend === "tidb" ||
|
|
51
52
|
config.dbBackend === "local" ||
|
|
52
53
|
(config.sessionBackend === "auto" && !!(config.tidb || config.pg));
|
|
53
54
|
if (wantDb) {
|
|
54
55
|
const opened = await openStoreBackendWithFallback(config, logger);
|
|
55
56
|
backend = opened.backend;
|
|
56
|
-
|
|
57
|
+
storeDegradedReason = opened.degradedReason;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
+
const storePosture = buildStorePosture({ declared: config.dbBackend, assembled: backend?.kind, degradedReason: storeDegradedReason });
|
|
60
|
+
metrics.setGauge("store_backend_degraded", storePosture.degradedReason !== undefined ? 1 : 0);
|
|
59
61
|
{
|
|
60
62
|
const mysqlPool = backend?.mysqlPool?.();
|
|
61
63
|
const pgPool = backend?.pgPool?.();
|
|
@@ -442,7 +444,7 @@ export async function openStores(ctx) {
|
|
|
442
444
|
.startRefresh()
|
|
443
445
|
: undefined;
|
|
444
446
|
return {
|
|
445
|
-
backend,
|
|
447
|
+
backend, storePosture, memoryEngine, memorySyncCursors, rosterStore, backgroundAgentStore, mailboxRecipientLifecycle,
|
|
446
448
|
taskAttachmentStore, mailboxStore, memoryExportBackend, memorySyncRunner, sessionStore, breakerState,
|
|
447
449
|
usageWindowStore, memoryPosture, taskListLane, sqlEngineFacts,
|
|
448
450
|
};
|
package/dist/brain.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Brain, type BreakerState, type Model } from "@sema-agent/core";
|
|
2
2
|
import type { ServiceConfig } from "./config-types.js";
|
|
3
|
+
import { type SealedCustodyPoison } from "./key-resolver.js";
|
|
3
4
|
import { type RestartSliceCtx } from "./config-center/restart-signal.js";
|
|
4
5
|
/**
|
|
5
6
|
* 配了快切层(failover ≥2 路 / 断路器)时,**每路**的重试上限。
|
|
@@ -49,6 +50,25 @@ export type DegradeRoutePlane = Pick<ServiceConfig, "degrade" | "models" | "gate
|
|
|
49
50
|
* 车道没开(非 reactive)或表里没有叫 `degrade.to` 的条目 ⇒ `undefined`(createBrain 不装降级壳)。
|
|
50
51
|
*/
|
|
51
52
|
export declare function degradeTargetOf(config: Pick<ServiceConfig, "degrade" | "models">): Model | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* S-795(R1):降级壳里目标自有凭据的**身份**(不是值)—— 与目标那只 Model 同一代,在 createBrain 组壳那一刻冻结。
|
|
55
|
+
* · `apiKeyEnv` —— 那一代给目标配的 env 变量**名**;壳每跳按这个名字现读值(同名轮换仍热;变量被删 ⇒ S-896 起 `env_missing` 毒丸,跳响亮拒 —— 7.105.0 及以前是「与自有凭据缺席同一臂」、落网关 key 档)。
|
|
56
|
+
* · `sealed` —— 那一代托管密钥的解封产物(明文,或解不开时的毒丸;与 `config.modelApiKeys` 的值同型)。托管密钥的身份是它的密文;
|
|
57
|
+
* 本进程的托管店在 boot 读一次、此后不变(`ensureSealedKeyStore`),同一密文恒解出同一产物 —— 所以持有那一代的产物就是持有
|
|
58
|
+
* 那一代的身份(壳里没有密文与托管店,也不需要)。重贴 = 新 key = 新身份,要重启才进壳 —— `degrade-route` 指纹带它的身份摘要,
|
|
59
|
+
* 所以重贴会签。🔴 明文是活秘密:只活在壳的闭包里,指纹只取摘要({@link degradeRouteFingerprint}),绝不进日志 / 序列化面。
|
|
60
|
+
* 目标没有自有凭据 ⇒ `{}`。两张表至多一个条目有效(registry-core 互斥:带 sealedApiKey 的条目不落 modelApiKeyEnv)。
|
|
61
|
+
*/
|
|
62
|
+
export interface DegradeCredentialIdentity {
|
|
63
|
+
readonly apiKeyEnv?: string;
|
|
64
|
+
readonly sealed?: string | SealedCustodyPoison;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* S-795:读出 `target`(降级壳焊的那只目标,{@link degradeTargetOf})此刻的凭据身份 —— **唯一**读法:createBrain 组壳时冻结它,
|
|
68
|
+
* `degrade-route` 指纹的两侧读数与启动摘要同读它。查表的键与序与修前 `fbOwnApiKey` 同:目标真名、再 `degrade.to`(后者可能是
|
|
69
|
+
* `default` 别名,两张 key 表按真名索引、env 车道的目录则反过来);每个名字上托管密钥压过 env 引用(key-resolver 的序)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function degradeCredentialIdentityOf(config: Pick<ServiceConfig, "degrade" | "modelApiKeyEnv" | "modelApiKeys">, target: Pick<Model, "name">): DegradeCredentialIdentity;
|
|
52
72
|
/**
|
|
53
73
|
* S-794:降级壳的**路由指纹**(纯数据)—— `degrade-route` 重启片 `baked` / `current` 两侧读数的唯一读法。
|
|
54
74
|
*
|
|
@@ -57,8 +77,10 @@ export declare function degradeTargetOf(config: Pick<ServiceConfig, "degrade" |
|
|
|
57
77
|
* · 那只 Model 经 `catalogEntryFingerprint`(与 swap 门同一张热字段减法:单价**数值**热、在场性不热;其余字段一律算 —— deny-list,
|
|
58
78
|
* 漂移的失败形是多签一次,绝不漏签);
|
|
59
79
|
* · 有效端点根(S-623 同一只解析器 `openaiRouteBaseUrl(baseUrl, gatewayBaseUrl)`);
|
|
60
|
-
* ·
|
|
61
|
-
*
|
|
80
|
+
* · 它配的凭据**身份**({@link degradeCredentialIdentityOf},壳冻结的同一只):`apiKeyEnv`(变量名,不是值;值热、同名轮换不签)与
|
|
81
|
+
* 托管密钥的**身份摘要**(S-795 R1 起壳冻结那一代的 key ⇒ 重贴 = 新身份,必须签;车QU codex r1 [high] F2:修前只有在场位,同端点
|
|
82
|
+
* 重贴不签、旧 key 一直发到人工重启)。摘要 = 明文 sha256 前 16 位十六进制(与 center-credential.ts「token 自身摘要身份」同一种
|
|
83
|
+
* 做法;同一明文重新封一次 = 同一把 key ⇒ 不签);毒丸 = 它的 `publicKeyId` + 成因(不含检测时刻 —— 每次 apply 都会重铸)。
|
|
62
84
|
* 没有焊壳(车道没开 / 没有目标)⇒ `null`。在场 ↔ 缺席的翻转因此自然是一次变化。
|
|
63
85
|
*/
|
|
64
86
|
export declare function degradeRouteFingerprint(config: DegradeRoutePlane): unknown;
|
package/dist/brain.js
CHANGED
|
@@ -2,6 +2,8 @@ import { adjudicateModelRoute, createAnthropicBrain, createCircuitBreakerBrain,
|
|
|
2
2
|
import { routeKeyOf } from "@sema-agent/core";
|
|
3
3
|
import { buildDefaultResilience } from "./config-types.js";
|
|
4
4
|
import { resolveModelApiKey } from "./key-resolver.js";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { isModelKeyPoison, modelKeyPoisonIdentity } from "./key-resolver.js";
|
|
5
7
|
import { dispatchBrainLane } from "./model-provider.js";
|
|
6
8
|
import { openaiRouteBaseUrl } from "./model-route-endpoint.js";
|
|
7
9
|
import { catalogEntryFingerprint } from "./config-center/restart-signal.js";
|
|
@@ -96,8 +98,10 @@ export function createBrain(config, deps = {}) {
|
|
|
96
98
|
const degradeTo = config.degrade.to;
|
|
97
99
|
const fallbackModel = degradeTargetOf(config);
|
|
98
100
|
if (fallbackModel) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
+
const credential = degradeCredentialIdentityOf(config, fallbackModel);
|
|
102
|
+
const ownEnvRef = credential.apiKeyEnv !== undefined ? { [fallbackModel.name]: credential.apiKeyEnv } : {};
|
|
103
|
+
const ownSealed = credential.sealed !== undefined ? { [fallbackModel.name]: credential.sealed } : {};
|
|
104
|
+
const fbOwnApiKey = () => resolveModelApiKey(fallbackModel.name, ownEnvRef, process.env, ownSealed);
|
|
101
105
|
const anthropicLaneHop = dispatchBrainLane(fallbackModel.provider, anthropicBrain !== undefined) === "anthropic";
|
|
102
106
|
const fallback = anthropicLaneHop && anthropicBrain
|
|
103
107
|
?
|
|
@@ -139,18 +143,36 @@ export function createBrain(config, deps = {}) {
|
|
|
139
143
|
export function degradeTargetOf(config) {
|
|
140
144
|
return config.degrade?.reactive ? config.models?.[config.degrade.to] : undefined;
|
|
141
145
|
}
|
|
146
|
+
export function degradeCredentialIdentityOf(config, target) {
|
|
147
|
+
for (const name of config.degrade === undefined ? [target.name] : [target.name, config.degrade.to]) {
|
|
148
|
+
const sealed = config.modelApiKeys?.[name];
|
|
149
|
+
if (sealed !== undefined)
|
|
150
|
+
return { sealed };
|
|
151
|
+
const apiKeyEnv = config.modelApiKeyEnv?.[name];
|
|
152
|
+
if (apiKeyEnv !== undefined)
|
|
153
|
+
return { apiKeyEnv };
|
|
154
|
+
}
|
|
155
|
+
return {};
|
|
156
|
+
}
|
|
142
157
|
export function degradeRouteFingerprint(config) {
|
|
143
158
|
const target = degradeTargetOf(config);
|
|
144
159
|
if (target === undefined || config.degrade === undefined)
|
|
145
160
|
return null;
|
|
146
|
-
const
|
|
161
|
+
const credential = degradeCredentialIdentityOf(config, target);
|
|
147
162
|
return {
|
|
148
163
|
model: catalogEntryFingerprint(target),
|
|
149
164
|
endpoint: openaiRouteBaseUrl(target.baseUrl, config.gatewayBaseUrl) ?? null,
|
|
150
|
-
apiKeyEnv:
|
|
151
|
-
sealedKey:
|
|
165
|
+
apiKeyEnv: credential.apiKeyEnv ?? null,
|
|
166
|
+
sealedKey: sealedIdentityFingerprint(credential.sealed),
|
|
152
167
|
};
|
|
153
168
|
}
|
|
169
|
+
function sealedIdentityFingerprint(sealed) {
|
|
170
|
+
if (sealed === undefined)
|
|
171
|
+
return null;
|
|
172
|
+
if (isModelKeyPoison(sealed))
|
|
173
|
+
return { poisoned: modelKeyPoisonIdentity(sealed), reason: sealed.reason };
|
|
174
|
+
return { digest: createHash("sha256").update(sealed, "utf8").digest("hex").slice(0, 16) };
|
|
175
|
+
}
|
|
154
176
|
export function createDegradeRouteWatch(config) {
|
|
155
177
|
const baked = degradeRouteFingerprint(config);
|
|
156
178
|
return { read: () => ({ baked, current: degradeRouteFingerprint(config) }) };
|
|
@@ -203,11 +225,8 @@ export function brainSummary(config) {
|
|
|
203
225
|
if (dispatchBrainLane(target.provider, config.anthropic !== undefined) === "anthropic") {
|
|
204
226
|
return { reactiveDegradeRoutePairing: "anthropic-lane", reactiveDegradeRouteRefusal: null };
|
|
205
227
|
}
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
config.modelApiKeys?.[target.name] !== undefined ||
|
|
209
|
-
config.modelApiKeys?.[config.degrade.to] !== undefined ||
|
|
210
|
-
hasAuthCarrier(target.headers);
|
|
228
|
+
const credential = degradeCredentialIdentityOf(config, target);
|
|
229
|
+
const declaresOwnCredential = credential.apiKeyEnv !== undefined || credential.sealed !== undefined || hasAuthCarrier(target.headers);
|
|
211
230
|
if (declaresOwnCredential) {
|
|
212
231
|
return { reactiveDegradeRoutePairing: "per-model-declared", reactiveDegradeRouteRefusal: null };
|
|
213
232
|
}
|
package/dist/budget.js
CHANGED
|
@@ -100,6 +100,9 @@ export function createTracer(metrics, costQuota, modelUsage, fleetUsage, fleetLe
|
|
|
100
100
|
else if (e.kind === "tool.call") {
|
|
101
101
|
metrics.inc("tool_calls_total", { name: toolName(e.name), ok: String(e.ok) });
|
|
102
102
|
}
|
|
103
|
+
else if (e.kind === "brain.echo_dropped") {
|
|
104
|
+
metrics.inc("brain_echo_dropped_total", { field: e.field });
|
|
105
|
+
}
|
|
103
106
|
else if (e.kind === "task.degraded") {
|
|
104
107
|
metrics.inc("degraded_total", { reason: e.reason });
|
|
105
108
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-866 ②(设计稿 v1.1 §2②)—— caps `centerWiring`:「这台引擎**此刻**是不是真的接着中心,调用者的额度是不是真的在执行」。
|
|
3
|
+
*
|
|
4
|
+
* 7.105.0 及以前这几件事只有日志和 gauge 知道:拉取、租约、用量三条腿各自沉默 —— 租约鉴权失败 / 中心不可达一律放行,调用方
|
|
5
|
+
* 与运维面板都读不出「额度现在没人在判」。本键把它们收成一个读面(调用方面;运维面仍是 `/health` 与 `GET /v1/diagnostics/wiring`)。
|
|
6
|
+
*
|
|
7
|
+
* ## 形与 present-iff
|
|
8
|
+
* 整个键只在接了中心(`config.configCenter` 在场)时出现;`lease:"absent"`(中心三件不齐 ⇒ 没装租约管理器)时 `leaseHealth` /
|
|
9
|
+
* `failMode` / `caller` 三键缺席。「键缺席」于是两义:老 worker / 没接中心 —— 同一体的 `version` 能分。
|
|
10
|
+
* · `effectivePull` = 最近一次实拉成功(`lastPull === "ok"`;LKG 起服 / 从未成功 / 最近一拍失败 = false);
|
|
11
|
+
* · `effectiveRevision` = 与 `/health.configAppliedVersion` 同一只 ledger 视图(`config-center/pull-state.ts`);
|
|
12
|
+
* · `lease` / `leaseHealth` / `failMode` / `caller` = 租约管理器的 `snapshot()` 与生效姿态(与执行的那一只同源);
|
|
13
|
+
* · `usageReport` = 用量环装没装(装配事实:累加器与环同一只谓词 `centerLaneConfigured`);
|
|
14
|
+
* · `issuer` = 鉴权桥 issuer 显式 / 回退(`authBridgeIssuerOf`;接了中心 ⇒ 桥恒装 ⇒ 没有 `none` 这一词)。
|
|
15
|
+
* caps 路由自己**不 admit**(不打中心):读的是最近一次谈判留下的状态。
|
|
16
|
+
*/
|
|
17
|
+
import type { CenterPullView } from "../config-center/pull-state.js";
|
|
18
|
+
import type { CallerLease, FleetLeaseManager, LeaseFailMode, LeaseHealth, LeaseSnapshot } from "../fleet-lease.js";
|
|
19
|
+
import type { ServiceConfig } from "../config.js";
|
|
20
|
+
/** `issuer` 的词表(两词:接了中心 ⇒ 桥恒装,`none` 结构上到不了,闭集里不留死词)。 */
|
|
21
|
+
export declare const CENTER_ISSUER_WORDS: readonly ["explicit", "fallback"];
|
|
22
|
+
export type CenterIssuer = (typeof CENTER_ISSUER_WORDS)[number];
|
|
23
|
+
/** caps `centerWiring` 的形(纯数据)。 */
|
|
24
|
+
export interface CenterWiring {
|
|
25
|
+
readonly effectivePull: boolean;
|
|
26
|
+
readonly effectiveRevision: {
|
|
27
|
+
readonly version: number;
|
|
28
|
+
readonly updatedAt: string;
|
|
29
|
+
} | null;
|
|
30
|
+
readonly lease: "configured" | "absent";
|
|
31
|
+
readonly leaseHealth?: LeaseHealth;
|
|
32
|
+
readonly failMode?: LeaseFailMode;
|
|
33
|
+
readonly usageReport: boolean;
|
|
34
|
+
readonly issuer: CenterIssuer;
|
|
35
|
+
readonly caller?: {
|
|
36
|
+
readonly lease: CallerLease;
|
|
37
|
+
readonly retryAfterSec?: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** 投影的全部输入(纯数据;一次读取的快照)。 */
|
|
41
|
+
export interface CenterWiringFacts {
|
|
42
|
+
readonly pull: CenterPullView;
|
|
43
|
+
/** 缺席 = 没装租约管理器(`lease:"absent"`)。 */
|
|
44
|
+
readonly lease: {
|
|
45
|
+
readonly failMode: LeaseFailMode;
|
|
46
|
+
readonly snapshot: LeaseSnapshot;
|
|
47
|
+
} | undefined;
|
|
48
|
+
readonly usageReport: boolean;
|
|
49
|
+
readonly issuer: CenterIssuer;
|
|
50
|
+
}
|
|
51
|
+
/** 输入 → caps 投影(纯函数,`build*` = 纯数据)。 */
|
|
52
|
+
export declare function buildCenterWiring(f: CenterWiringFacts): CenterWiring;
|
|
53
|
+
/**
|
|
54
|
+
* 读面工厂(`create*`:返回的是闭包)。stage-10 装配一次,caps 路由按请求调(入参 = 该请求的已验 principal,与租约门同键)。
|
|
55
|
+
* 没接中心 ⇒ `undefined`(键整个缺席)。`now` 注入只给测试(与租约管理器同钟才判得出过期);生产缺省 `Date.now`。
|
|
56
|
+
*/
|
|
57
|
+
export declare function createCenterWiringReader(a: {
|
|
58
|
+
readonly config: Pick<ServiceConfig, "configCenter" | "authBridgeIssuer">;
|
|
59
|
+
readonly pullState: () => CenterPullView;
|
|
60
|
+
readonly fleetLease: Pick<FleetLeaseManager, "snapshot" | "failMode"> | undefined;
|
|
61
|
+
readonly usageReport: boolean;
|
|
62
|
+
readonly now?: () => number;
|
|
63
|
+
}): ((principal: string | undefined) => CenterWiring) | undefined;
|
|
64
|
+
//# sourceMappingURL=center-wiring.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { authBridgeIssuerOf } from "../auth-bridge.js";
|
|
2
|
+
export const CENTER_ISSUER_WORDS = ["explicit", "fallback"];
|
|
3
|
+
export function buildCenterWiring(f) {
|
|
4
|
+
const base = { effectivePull: f.pull.lastPull === "ok", effectiveRevision: f.pull.effectiveRevision, usageReport: f.usageReport, issuer: f.issuer };
|
|
5
|
+
if (f.lease === undefined)
|
|
6
|
+
return { ...base, lease: "absent" };
|
|
7
|
+
return { ...base, lease: "configured", leaseHealth: f.lease.snapshot.leaseHealth, failMode: f.lease.failMode, caller: f.lease.snapshot.caller };
|
|
8
|
+
}
|
|
9
|
+
export function createCenterWiringReader(a) {
|
|
10
|
+
if (a.config.configCenter === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
const issuer = authBridgeIssuerOf(a.config);
|
|
13
|
+
if (issuer === undefined)
|
|
14
|
+
throw new Error("center wiring: a configured center always yields an auth-bridge issuer (explicit or fallback)");
|
|
15
|
+
const now = a.now ?? Date.now;
|
|
16
|
+
const lease = a.fleetLease;
|
|
17
|
+
return (principal) => buildCenterWiring({
|
|
18
|
+
pull: a.pullState(),
|
|
19
|
+
lease: lease === undefined ? undefined : { failMode: lease.failMode, snapshot: lease.snapshot(principal, now()) },
|
|
20
|
+
usageReport: a.usageReport,
|
|
21
|
+
issuer: issuer.source,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=center-wiring.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-129 ③ 残余(车QX)—— `GET /v1/capabilities` **复合能力位的成员闭集**(单点)。
|
|
3
|
+
*
|
|
4
|
+
* ## 病
|
|
5
|
+
* 能力位的**顶层键**早有闭集(契约附录 B.1,`test/capabilities-doc-appendix.test.ts` 双向对拍),wire 变更清单
|
|
6
|
+
* (`scripts/wire-changes-server.mjs`)也 diff 它;可**值是对象**的那些位,其成员(`executionLane.isolated`、`store.sql`、
|
|
7
|
+
* `centerWiring.caller` …)不在任何闭集里 —— 7.106.0 新加的 `executionLane.isolated` 在清单里不可见,发车帖与 CAPABILITY 登记只能
|
|
8
|
+
* 人工抄。本表把「成员」立成与顶层键同级的闭集,契约附录 B.1a(`taskSettings` 在 B.2、`permissionModeAuto` 在 B.2b —— 同一闭集的
|
|
9
|
+
* 分段)是它的文档面,清单生成器 diff 那几段。
|
|
10
|
+
*
|
|
11
|
+
* ## 一条规则:什么算「复合能力位」
|
|
12
|
+
* caps 应答字面量里,**值的类型含具名成员对象臂**的顶层键。判据只看类型,不看名字:
|
|
13
|
+
* · `false` / `null` / `undefined` 臂剥掉再看(`fleet: {…} | false`、`writeProtection: {…} | null`、present-iff 的
|
|
14
|
+
* `centerWiring?: {…}` 都算复合位,成员 = 对象臂的键);
|
|
15
|
+
* · 判别联合逐臂取键的**并集**(`permissionModeAuto` 展开的 `AutoModeVerdict`:`reason` 只在 `armed:false` 臂上,照样是成员 ——
|
|
16
|
+
* `keyof (A | B)` 只给公共键,会漏掉它);
|
|
17
|
+
* · **不算**:标量 / 字面词(`readFace`、`fileHistoryCapture`)· 数组(`workflowModels`:成员是数据,不是键)· **自由映射**
|
|
18
|
+
* (`Record<string, …>`:键集不是闭集,「成员」无从登记 —— 它的键在 wire 上是数据,消费方按值读,不按键名分派;今天 caps
|
|
19
|
+
* 字面量里没有这种位,规则先写明,免得哪天有人为它开特例)。
|
|
20
|
+
* · 只登记**一层**:成员本身若又是对象(`store.sql`、`centerWiring.effectiveRevision` / `caller`),它的内部形写在附录 B.1a 的
|
|
21
|
+
* 「值形」列,不进本表(二层成员不登记 = 已披露的欠账:它们的增删今天仍只在「值形」列的人读文字里)。
|
|
22
|
+
*
|
|
23
|
+
* ## 两个半场(都必须双向)
|
|
24
|
+
* · **编译期**:{@link gateCompositeMembers} 包在 caps 路由的应答字面量外,按字面量**自己的推断型**对本表做双向差 ——
|
|
25
|
+
* 字面量上长出一个未登记的复合位 / 成员 ⇒ tsc 红(正向);表里登记了字面量不再铸的位 / 成员(退役、改名、拼错)⇒ tsc 红
|
|
26
|
+
* (反向)。红的时候错误里逐条点名 `<cap>.<member>` 与方向。判据是推断型而不是某个具名接口:内联字面量(`fleet`、
|
|
27
|
+
* `taskSettings` …)、投影函数的返回型(`ExecutionLaneCapability` …)、展开进来的类型(`...autoMode`)一律被看见,新长出来的
|
|
28
|
+
* 复合位也被看见 —— 「值是对象」这条规则由类型自己执行,不靠人记得来登记。
|
|
29
|
+
* · **文档**:`test/capabilities-doc-appendix.test.ts` 把本表与附录 B.1a / B.2 / B.2b 的成员行双向对拍(缺行 / 多行逐条点名)。
|
|
30
|
+
*
|
|
31
|
+
* 为什么编译期门借一只恒等函数而不是 `AssertAllKeysHandled` 类型别名:被判的是 `handleCapabilities` 里一个**表达式**的推断型,
|
|
32
|
+
* 模块级给不出它的名字;而把字面量挪成局部常量会让它离开 `sendJson(…)` 的实参子树 —— `test/config-url-display-safe.test.ts`
|
|
33
|
+
* 的出口扫描器按「出口调用的实参子树」找 URL 字段,挪出去它就对整只 caps 体失明。恒等函数运行期零行为(原样返回入参)。
|
|
34
|
+
*/
|
|
35
|
+
import type { NamedKeysOf } from "../request-key-closure.js";
|
|
36
|
+
/**
|
|
37
|
+
* 复合能力位 → 成员(闭集,一位一行;成员按字面量 / 投影型里的声明序)。改这张表 = 改 wire 契约:同批改附录 B.1a(或 B.2 /
|
|
38
|
+
* B.2b)与 CHANGELOG。present-iff 的位与成员照样登记(在场律写在附录的「在场律」列)。
|
|
39
|
+
*/
|
|
40
|
+
export declare const COMPOSITE_CAPABILITY_MEMBERS: {
|
|
41
|
+
readonly deviceExecutor: readonly ["enabled", "protocolVersion", "maxInflightPerDevice", "wsPath", "management"];
|
|
42
|
+
readonly fleet: readonly ["stream", "sessionScope", "observe", "resume", "bgNotifyFailClosed", "steerPriority", "hookFailureNotice"];
|
|
43
|
+
readonly memoryEngine: readonly ["backend", "vectorMode"];
|
|
44
|
+
readonly store: readonly ["declared", "backend", "durable", "degradedReason", "sql"];
|
|
45
|
+
readonly centerWiring: readonly ["effectivePull", "effectiveRevision", "lease", "leaseHealth", "failMode", "usageReport", "issuer", "caller"];
|
|
46
|
+
readonly webSearch: readonly ["backend"];
|
|
47
|
+
readonly background: readonly ["listFace", "exitFaces"];
|
|
48
|
+
readonly taskSettings: readonly ["permissions", "permissionMode", "model", "outputStyle", "env", "hooks"];
|
|
49
|
+
readonly permissionModeAuto: readonly ["accepted", "classifierSeat", "entitlementSource", "armed", "reason", "model"];
|
|
50
|
+
readonly writeProtection: readonly ["armed", "rows", "replaced"];
|
|
51
|
+
readonly executionLane: readonly ["provider", "toolsOnThisHost", "isolated"];
|
|
52
|
+
readonly retention: readonly ["mode", "maxAgeDays"];
|
|
53
|
+
readonly workflowsGate: readonly ["engineCan", "denial"];
|
|
54
|
+
readonly sealedKey: readonly ["alg", "publicKeyId", "publicKey"];
|
|
55
|
+
};
|
|
56
|
+
type CompositeTable = typeof COMPOSITE_CAPABILITY_MEMBERS;
|
|
57
|
+
/** 值的**具名成员对象臂**(标量 / 字面词 / `false` / `null` / `undefined` / 数组 / 函数臂剥掉)。 */
|
|
58
|
+
type ObjectArmsOf<V> = V extends readonly unknown[] ? never : V extends (...args: never[]) => unknown ? never : V extends object ? V : never;
|
|
59
|
+
/** 联合逐臂取键的并集(`keyof (A | B)` 只给公共键,判别联合的臂专有键会漏)。 */
|
|
60
|
+
type KeysOfUnion<T> = T extends unknown ? keyof T : never;
|
|
61
|
+
/** 一个能力位值的成员键;自由映射(键集含 `string`)⇒ `never`(不算复合位,见头注)。 */
|
|
62
|
+
type MemberKeysOf<V> = string extends KeysOfUnion<ObjectArmsOf<V>> ? never : KeysOfUnion<ObjectArmsOf<V>>;
|
|
63
|
+
/** 应答体里的复合位(索引签名剥掉 —— `...deps.capabilities` 展开进来的 `Record<string, unknown>` 不是具名键)。 */
|
|
64
|
+
type CompositeKeysOf<Body> = {
|
|
65
|
+
[K in keyof NamedKeysOf<Body>]-?: [MemberKeysOf<Body[K & keyof Body]>] extends [never] ? never : K;
|
|
66
|
+
}[keyof NamedKeysOf<Body>];
|
|
67
|
+
/** 正向:字面量铸了、表没登记 —— 整只复合位(`<cap>`)或已登记位上的成员(`<cap>.<member>`)。 */
|
|
68
|
+
type CompositeMembersUnregistered<Body> = Exclude<CompositeKeysOf<Body>, keyof CompositeTable> | {
|
|
69
|
+
[C in CompositeKeysOf<Body> & keyof CompositeTable]: `${C & string}.${Exclude<MemberKeysOf<Body[C & keyof Body]>, CompositeTable[C][number]> & string}`;
|
|
70
|
+
}[CompositeKeysOf<Body> & keyof CompositeTable];
|
|
71
|
+
/** 反向:表登记了、字面量不再铸 —— 退役 / 改名 / 拼错的残条目。 */
|
|
72
|
+
type CompositeMembersPhantom<Body> = Exclude<keyof CompositeTable, CompositeKeysOf<Body>> | {
|
|
73
|
+
[C in keyof CompositeTable & CompositeKeysOf<Body>]: `${C & string}.${Exclude<CompositeTable[C][number], MemberKeysOf<Body[C & keyof Body]>> & string}`;
|
|
74
|
+
}[keyof CompositeTable & CompositeKeysOf<Body>];
|
|
75
|
+
/** 表与应答体的**双向**漂移(正向 ∪ 反向;`never` = 一致)。导出给测试做类型负控。 */
|
|
76
|
+
export type CompositeMembersDrift<Body> = CompositeMembersUnregistered<Body> | CompositeMembersPhantom<Body>;
|
|
77
|
+
/** 漂移非空 ⇒ 一个多出来的必填键,错误信息里逐条点名 `<cap>.<member>` 与方向。 */
|
|
78
|
+
type CompositeMembersGate<Body> = [CompositeMembersDrift<Body>] extends [never] ? object : {
|
|
79
|
+
readonly "S-129 composite capability member drift (src/capabilities/composite-members.ts)": {
|
|
80
|
+
readonly [K in CompositeMembersDrift<Body>]: K extends CompositeMembersUnregistered<Body> ? "字面量铸了、表没登记" : "表登记了、字面量没铸";
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* caps 应答字面量的**编译期**成员闭集门(见头注「两个半场」)。运行期是恒等函数:原样返回入参,零行为。
|
|
85
|
+
* 用法:`sendJson(res, 200, gateCompositeMembers({ …应答字面量… }))`。
|
|
86
|
+
*/
|
|
87
|
+
export declare function gateCompositeMembers<Body extends CompositeMembersGate<Body>>(body: Body): Body;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=composite-members.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const COMPOSITE_CAPABILITY_MEMBERS = {
|
|
2
|
+
deviceExecutor: ["enabled", "protocolVersion", "maxInflightPerDevice", "wsPath", "management"],
|
|
3
|
+
fleet: ["stream", "sessionScope", "observe", "resume", "bgNotifyFailClosed", "steerPriority", "hookFailureNotice"],
|
|
4
|
+
memoryEngine: ["backend", "vectorMode"],
|
|
5
|
+
store: ["declared", "backend", "durable", "degradedReason", "sql"],
|
|
6
|
+
centerWiring: ["effectivePull", "effectiveRevision", "lease", "leaseHealth", "failMode", "usageReport", "issuer", "caller"],
|
|
7
|
+
webSearch: ["backend"],
|
|
8
|
+
background: ["listFace", "exitFaces"],
|
|
9
|
+
taskSettings: ["permissions", "permissionMode", "model", "outputStyle", "env", "hooks"],
|
|
10
|
+
permissionModeAuto: ["accepted", "classifierSeat", "entitlementSource", "armed", "reason", "model"],
|
|
11
|
+
writeProtection: ["armed", "rows", "replaced"],
|
|
12
|
+
executionLane: ["provider", "toolsOnThisHost", "isolated"],
|
|
13
|
+
retention: ["mode", "maxAgeDays"],
|
|
14
|
+
workflowsGate: ["engineCan", "denial"],
|
|
15
|
+
sealedKey: ["alg", "publicKeyId", "publicKey"],
|
|
16
|
+
};
|
|
17
|
+
export function gateCompositeMembers(body) {
|
|
18
|
+
return body;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=composite-members.js.map
|
|
@@ -5,6 +5,9 @@ export interface ExecutionLaneCapability {
|
|
|
5
5
|
/** 工具跑的那台机器就是本进程这台吗(= server 盘上的绝对路径对模型的工具有没有意义)。
|
|
6
6
|
* 属主 = `task-cwd.ts` 的 {@link toolsRunOnThisHost},与 `skills[].baseDir` 的铸点同一只函数。 */
|
|
7
7
|
readonly toolsOnThisHost: boolean;
|
|
8
|
+
/** S-281:手在不在 OS 级隔离边界里(容器 / microVM / Kata pod)。**present-iff 本车道有手**(能力表 `coreRemoteExecutionEnv`);
|
|
9
|
+
* 值 = {@link laneIsolated}(能力表 `isolation` 位,与 boot `remote_exec_enabled.isolated` 同一只)。见头注 S-281 段。 */
|
|
10
|
+
readonly isolated?: boolean;
|
|
8
11
|
}
|
|
9
12
|
/**
|
|
10
13
|
* 部署席 → 消费端窄投影。形照 `projectWebSearchCapability` / `projectSqlEngineCapability`:
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { toolsRunOnThisHost } from "../task-cwd.js";
|
|
2
|
-
import { executionLaneOf } from "../execution-lane-caps.js";
|
|
2
|
+
import { executionLaneCaps, executionLaneOf, laneIsolated } from "../execution-lane-caps.js";
|
|
3
3
|
export function projectExecutionLaneCapability(config) {
|
|
4
|
+
const lane = executionLaneOf(config.remoteExec?.provider);
|
|
5
|
+
const handsWired = executionLaneCaps(lane).coreRemoteExecutionEnv === "supported";
|
|
4
6
|
return {
|
|
5
|
-
provider:
|
|
7
|
+
provider: lane,
|
|
6
8
|
toolsOnThisHost: toolsRunOnThisHost(config),
|
|
9
|
+
...(handsWired ? { isolated: laneIsolated(lane) } : {}),
|
|
7
10
|
};
|
|
8
11
|
}
|
|
9
12
|
//# sourceMappingURL=execution-lane.js.map
|
package/dist/config-catalog.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ServiceConfig, ServiceConfigGroups } from "./config-types.js";
|
|
2
|
-
import type { ConfigKnobRecord } from "./config.js";
|
|
2
|
+
import type { ConfigKnobRecord, RetiredEnvWire } from "./config.js";
|
|
3
3
|
import type { RestartSlice } from "./config-center/restart-signal.js";
|
|
4
4
|
export declare const CATALOG_VALUE_TYPES: readonly ["boolean", "number", "string", "enum", "csv", "json", "path", "url", "secret", "opaque"];
|
|
5
5
|
export type CatalogValueType = (typeof CATALOG_VALUE_TYPES)[number];
|
|
@@ -40,7 +40,7 @@ export interface ConfigCatalogSpec {
|
|
|
40
40
|
* 🔴 `enumValues` 一直是**两义**的:它既是行对外宣告的「你可以写哪些词」([ref] 件⑤/⑧ 两条钉逐字锚
|
|
41
41
|
* 这一义:窄了=少宣告一档、宽了=宣告一个 boot 会拒的词),又被回显校验当成「实算值合不合法」的闭集。
|
|
42
42
|
* 两义在**多数**行上碰巧同集,于是差别只活在散文里 —— `MANUAL_MODE_SHELL_GATE` 的
|
|
43
|
-
* `derivedDefaultNote` 写着「真姿态只有 always/classify
|
|
43
|
+
* `derivedDefaultNote` 写着「真姿态只有 always 一个」(S-877 前是 always/classify 两个),`MODEL_DEFAULT_THINKING` 写着
|
|
44
44
|
* 「缺席/off ⇒ 不铸」,而**没有任何一条腿读那两句话**:`off` 照样留在回显闭集里,回显校验对它放行。
|
|
45
45
|
*
|
|
46
46
|
* ⇒ 把那半句散文变成一处**校验腿真读的声明**:`sanitizeEnumValue` 问 `echoWords ?? enumValues`,
|
|
@@ -87,8 +87,6 @@ export interface ConfigCatalogRowCenter {
|
|
|
87
87
|
readonly timing: Exclude<CatalogTiming, "deploy">;
|
|
88
88
|
readonly restartSlice?: RestartSlice;
|
|
89
89
|
readonly restartReason?: string;
|
|
90
|
-
/** settings-schema 现行 DOMAINS 里真有这个域(false = 设计稿 ⚪ 成因 b「该片暂无配置中心写腿」)。 */
|
|
91
|
-
readonly domainExists: boolean;
|
|
92
90
|
/** center 的最近一份 effective **当前在管**本键(没有配置管道 ⇒ 恒 false)。 */
|
|
93
91
|
readonly managedNow: boolean;
|
|
94
92
|
/** center 写**现在真的在生效**(在管 ∧ 未被 env 占位压住;env-wins 族 env 占位 ⇒ false = ⚪ 成因 a)。 */
|
|
@@ -142,10 +140,16 @@ export interface ConfigCatalogInputs {
|
|
|
142
140
|
/** boot 装配的生效事实({@link CatalogBootFacts})。 */
|
|
143
141
|
readonly boot: CatalogBootFacts;
|
|
144
142
|
readonly knobs: readonly ConfigKnobRecord[];
|
|
145
|
-
/** settings-schema 现行 DOMAINS(
|
|
143
|
+
/** settings-schema 现行 DOMAINS(调用方传入,原样上 wire 的 `centerDomains` 列表)。🔴 7.106.0 起本注改真:本模块**不是**零包依赖 ——
|
|
144
|
+
* 它值级 import 了 core 与契约包(词表 / 中心凭证键名 / S-866 ⑤a 的 `DOMAIN_SCHEMAS` 座位门);这一格照旧由调用方传,
|
|
145
|
+
* 只因为它是 wire 上的一段列表、由路由决定取哪一份。 */
|
|
146
146
|
readonly centerDomains: readonly string[];
|
|
147
147
|
/** config-center 当前在管的 ServiceConfig 键集(缺席 = 没有配置管道)。 */
|
|
148
148
|
readonly centerManagedKeys?: ReadonlySet<string> | undefined;
|
|
149
|
+
/** S-885:退役 env 墓碑表的投影 —— 调用方传 `config.ts` 的 `buildRetiredEnvWire()`(同一张 `RETIRED_ENVS`,不手抄)。**必填**:
|
|
150
|
+
* 本模块不能值引 config.ts(`server-secret-env.ts` 值引本模块 ⇒ config → server-secret-env → config-catalog → config 成环,
|
|
151
|
+
* 干净进程直接 import 本模块即 TDZ 崩;codex r1 F2)⇒ 由调用方注入,缺了就是编译错而不是一张静默空表。 */
|
|
152
|
+
readonly retired: readonly RetiredEnvWire[];
|
|
149
153
|
}
|
|
150
154
|
export interface ConfigCatalogWire {
|
|
151
155
|
readonly catalogVersion: 1;
|
|
@@ -160,12 +164,38 @@ export interface ConfigCatalogWire {
|
|
|
160
164
|
readonly centerManaged: number;
|
|
161
165
|
};
|
|
162
166
|
readonly rows: readonly ConfigCatalogRow[];
|
|
167
|
+
/** S-885(7.106.0)—— 退役 env 墓碑表(`config.ts` 的 `RETIRED_ENVS`,在场即拒启)的投影,**恒在场**(可为空数组)。与 `rows` 分开:
|
|
168
|
+
* rows 是「本进程会读的 env」,这里是「本进程会拒的旧名」—— 一个名字不会同时在两处(墓碑名没有读取点)。 */
|
|
169
|
+
readonly retired: readonly RetiredEnvWire[];
|
|
163
170
|
}
|
|
164
171
|
/**
|
|
165
172
|
* 目录表(按名排序 —— 卫生格执法)。语义句以读取点实现为准(不信注释纪律:本表成文时逐键对过
|
|
166
173
|
* config.ts / boot / plugins 的真实读取臂;后续漂移由 D1 对账门逼着回到这里补行)。
|
|
167
174
|
*/
|
|
168
175
|
export declare const CONFIG_CATALOG: readonly ConfigCatalogSpec[];
|
|
176
|
+
/**
|
|
177
|
+
* S-866 ⑤a —— **目录座位加载期门**(类修:一次把「目录声称了契约里没有的中心写位」整类关掉)。
|
|
178
|
+
*
|
|
179
|
+
* 行上的 `center` 座位说的是「中心能发布这个键」。它必须对得上契约包 `@sema-agent/settings-schema` 的 `DOMAIN_SCHEMAS`:
|
|
180
|
+
* ① 域在场;② `path` 在该域的 zod 形里解析得出(`a.b` 逐段进对象;`xs[].c` = 进数组元素)。任一不成立 ⇒ **抛**(模块加载即抛:
|
|
181
|
+
* 进程起不来、每个 import 本模块的测试当场红)—— 不是 warn、不是标一个 `false` 位上 wire(7.105.0 及以前那只 `domainExists`
|
|
182
|
+
* 位就是后一种:它只看域不看路径,而 `models` 是真域,于是 `models.degrade` 这个不存在的成员被报成「中心可写」)。
|
|
183
|
+
*
|
|
184
|
+
* 解析只认 zod 的结构外衣(optional / nullable / default / catch / readonly / effects·管道 / lazy)与对象 / 数组两种容器;认不出的节点 = 解析不出
|
|
185
|
+
* (fail-closed:宁可多拒一个座位,也不放过一个假座位)。
|
|
186
|
+
*
|
|
187
|
+
* 🔴 S-909(7.106.0 合并复审 opus 腿 L-1):**只走 zod 公开面**。契约包今天是 zod 3.25、本仓是 zod 4 —— 读 zod 私有定义字段(类型判别名 /
|
|
188
|
+
* 内层 schema / lazy getter)的旧写法在契约包升 zod 4 那天会让 `models[].…` 整族座位解析不出,模块 import 期整只抛。两大版没有一个能同时
|
|
189
|
+
* 公开读到的「这是什么节点」判别位(v4 的 `.def.type` 在 v3 上不存在),`instanceof` 也跨不了两份 zod 的类身份 ⇒ 按两大版**同名的公开访问器**
|
|
190
|
+
* 认形,规则三条(见 {@link zodObjectShapeOf} / {@link isZodArrayFace} / {@link ZOD_WRAPPER_FACES})。钉:`test/config-catalog-zod-public-face.test.ts`。
|
|
191
|
+
*/
|
|
192
|
+
export declare function assertCenterSeatsResolvable(specs: readonly {
|
|
193
|
+
readonly name: string;
|
|
194
|
+
readonly center?: {
|
|
195
|
+
readonly domain: string;
|
|
196
|
+
readonly path: string;
|
|
197
|
+
} | undefined;
|
|
198
|
+
}[]): void;
|
|
169
199
|
/** `build*` 命名(工厂纪律):产物是纯数据(wire 投影),零方法零捕获行为。 */
|
|
170
200
|
export declare function buildConfigCatalog(inputs: ConfigCatalogInputs): ConfigCatalogWire;
|
|
171
201
|
//# sourceMappingURL=config-catalog.d.ts.map
|