import type { EffectiveConfig } from "./types.js"; export type RestartSlice = "skills" | "mcp" | "a2a" | "scenarios" | "runtime-gates" | "models-tiers" | "degrade-route" | "read-face"; /** What the CALLER must contribute about boot-baked catalog consumers that live OUTSIDE the Runner — the * slices cannot see them, because they are configured from env (`ServiceConfig`), not from the center's * EffectiveConfig. Absent/empty = that lane is off ⇒ its slice is inert (null on both sides). */ export interface RestartSliceCtx { /** `config.degrade.to` when REACTIVE degrade is on (env `MODEL_DEGRADE_TO` + `MODEL_DEGRADE_REACTIVE`); * undefined = the lane is off ⇒ no degrading brain was composed ⇒ nothing is boot-frozen. */ reactiveDegradeTo?: string; /** #A4(codex 交叉复审 finding 2,验真后采纳):本机 env **显式占住**的 readFace 键 * (`applyCenterReadFace` 的返回值,由 boot 存下)。这些键的 center 值在本机**永不 boot-bake**, * 所以它们的变化不该产生 restart 理由 —— 否则 center 改一个本机用不上的键,整片 fleet 会为一次 * 对自己毫无影响的发布滚动重启一遍。缺席 = 没有 env 覆盖 ⇒ 整域都算数(与旧行为一致)。 */ readFaceEnvHeld?: readonly ("face" | "denyPatterns" | "denyBuiltinTiers" | "denyBuiltinExclude")[]; /** [ref](core 5.50 [ref]):撤销台账腿已接线(`RunnerDeps.mcpRevocations` 席在场且 refresh 拍在喂)。 * true ⇒ mcp 片的**纯删除向**(current 的 enabled 集是 boot 集的逐字子集)不再签 restart —— 删除已被 * 台账即时承接(core 每次 dispatch 前探 isRevoked),再签就是为一个已生效的变更滚动重启 fleet。 * 新增/改址/域整体出现或消失仍签(新 mount / 改址只能 restart 才生效)。缺席/false = 旧语义照签 * (fail-closed:没接席的部署里删除向没人承接,restart 是它唯一的生效路径)。 */ mcpRevocationLive?: boolean; } /** Structured restart signal an orchestrator consumes (GET /health → `restart`). Change-detected against the * process's BOOT config, NOT presence — so it stays absent when nothing baked-at-boot changed (presence would * re-fire every refresh → a restart LOOP). `restartRequired` is always true when this object exists. */ export interface RestartSignal { restartRequired: true; /** Which restart-to-apply slices differ from the value baked at boot. */ reasons: RestartSlice[]; /** The config-center version that currently differs from boot (latest seen). */ version: number; /** Epoch ms when this restart first became required (stable across refreshes while `reasons` is unchanged). */ since: number; } /** Canonical, key-sorted JSON (array order preserved) so two semantically-equal effective slices fingerprint * identically regardless of object key order from the center serializer. * * ⚠️ [ref](2026-08-31)如实登记:这**不是** `src/canonical-json.ts#canonicalJson`(core 逐字港,全仓单源)—— * 两者在 JSON 形输入上逐字节相同(golden 交叉读数已证),但本函数把 `undefined` 值键**保留为 `"k":null`**, * 共享件按 `JSON.stringify` 语义**省略**。restart 指纹的输入是进程内构造的切片对象(zod 解析产物 + rest 展开/ * 挑字段),`{k: undefined}` 形原则上可达,而它与 `{}` 是否同指纹 = 本轴上的**行为**(多签/少签一次 fleet 滚动 * 重启),不是序列化器的私事 ⇒ 语义不恒等不合并;字节钉 test/canonical-json-golden.test.ts,K→O 统一另立件 * 走三问。导出只为 mcp-revocation 同源改调(两处此前各持一份逐字相同的复刻)与 golden 直钉,不是公共 API。 */ export declare function stableStringify(v: unknown): string; /** Restart-to-apply slices that DIFFER between this process's BOOT config and a freshly-pulled one. Empty = * nothing baked-at-boot changed (only hot-apply slices moved, or nothing) → no restart needed. An orchestrator * can auto rolling-restart on a non-empty result WITHOUT a restart loop, because the comparison is always * against boot (a refresh that re-fires the same diff is idempotent, not a fresh trigger). */ export declare function restartReasons(boot: EffectiveConfig | undefined, current: EffectiveConfig, ctx?: RestartSliceCtx): RestartSlice[]; /** codex R10 (models-tiers 窗收口): TRUE when the MODEL PLANE (enabled models + active tier table + resolved * default) of `next` differs from the last-APPLIED plane `prev`. Under a tier-frozen Runner (tiers non-empty at * construction → private expanded copy) main.ts DEFERS the whole plane mutation until restart when this is true — * admission (/v1/models, the catalog gates) and the Runner then stay on ONE generation through the restart * window, so a same-key retarget can never silently route/bill the stale Model object. `prev === undefined` * (env-boot plane, no EffectiveConfig to compare) is conservatively "changed" — one deferred adoption + restart * converges. Deliberately NOT gated on tier activity of either side (unlike the restart slice): a frozen Runner * goes stale on ANY plane change, including a tiers-off flip. */ /** codex R12: TRUE when this candidate resolves an ACTIVE tier table. Used by main.ts's defer predicate — a * tier-less-booted Runner never re-runs expandTiers, so hot-applying an ARRIVING tier table splits admission * (tier words pass the expanded gate) from execution (core throws "Unknown model ref"). Hot-apply of the model * plane is safe only when BOTH the constructed generation and the candidate are tier-less. */ export declare function planeHasActiveTiers(eff: EffectiveConfig): boolean; export declare function modelPlaneChanged(prev: EffectiveConfig | undefined, next: EffectiveConfig): boolean; //# sourceMappingURL=restart-signal.d.ts.map