/** * [ref] D2/D3(316 车C)—— 记忆 **consolidation 阀门**的 operator 两口: * * · `POST /v1/admin/memory/consolidation/run` —— 跑(或**续跑**)一轮,同步回一份收执**摘要投影**; * · `GET /v1/admin/memory/consolidation` —— D3 状态投影(阀门、座位、scope 表、上一轮的账)。 * * ── 族属与门序 ──────────────────────────────────────────────────────────────────────────────────── * 与 `/v1/admin/drain` · `/v1/admin/config/refresh` 逐字同族(operator lane:同一条 `explicitOperatorOk` * 门)。门序照 operator 面既有口径:身份(401)→ 授权(403)→ 验型(400)。**授权在验型之前** —— 一个 * 够不着任何东西的调用方不该从「你的 body 形不对」上读出这台部署有没有这条面。 * * ── 为什么缺席形是 **404 族**而不是 501(D4)─────────────────────────────────────────────────────── * 本仓的 501 `capability.*` 说的是「**这家店**在本部署上不存在,换部署形态才行」(记忆引擎没接线、 * 后端没有某个复合面)。本族不是那个形:阀门关着是一句**运维表态**(`MEMORY_CONSOLIDATION_DRIVER=off`, * 而且是出厂缺省),不是部署能力的缺失。而阀门开着却结构上跑不了的三种形(引擎没接线 / 后端没有控制面 * 归属 / provenance=off)在**启动期**就被拒了(`boot/memory-consolidation.ts` 的 * `assertConsolidationDriverWirable`)—— 那些机器根本起不来,不会有一个"挂着的 501"去代表它们。 * ⇒ 剩下的唯一缺席成因就是「阀门没开」,而它的诚实形是**这条路径不存在**:挂载条件写在 server.ts 的 * 域头合取式里,能力位 `memoryConsolidationDriver` 读同一个事实,「说 yes ⟺ 打得通」因此是结构性的。 * 🔴 刻意与 permissionRules 的 501 分家:那一族的 501 是「规则店没装」,消费端的动作是换部署;本族的 * 404 的动作是「去把旋钮打开」。同码会让运维照着一条修不好的路走。 * * ── scope **恒不猜**(D2)──────────────────────────────────────────────────────────────────────── * 一轮 consolidation 读**全库**(~1e5 prompt tokens/轮)。在两个库之间替 operator 挑一个去花这笔钱, * 是本设计明确要消灭的形。所以: * · 调用方显式给 `scope` ⇒ 用它 —— 哪怕它不在 `MEMORY_CONSOLIDATION_SCOPES` 里。 * 🔴 那张表**不是授权边界**:本仓今天没有任何授权源能对一个 operator 收窄 scope(`gateMemoryScope` * 的 operator 支在查目录之前就 allow;`org-memory-admission` 明写 v1 不中央收窄 operator 声明的 * scope —— 全文见 `src/memory-operator-faces.ts` 的 `erasureEnvelopeRefusal` 头注)。在本层拿它当 * 白名单就是**发明第二套授权语义**,与 `gateMemoryScope` 对同一个身份给出相反答案; * · 省略 `scope` ⇒ 只有表**恰好一条**时才有缺省(那条就是这台部署的库);零条或两条以上一律 400, * 并把候选列进文案 —— 让运维一眼看到「我该点哪一个」。 * * ── 投影纪律:**禁投 LLM 原文**(D3 逐字)──────────────────────────────────────────────────────── * core 的收执/run 行里有两处**模型作者**的自由文本:`residue[].name`(模型提议的产物名)与 * `writeFailures[].key`(模型提议的分组键),另有 `planCache.products`(整份 mint 出来的计划)。三处 * 一律**只上计数**。理由不是洁癖:这两口是 operator 面的**审计读**,而模型作者的文本是**不可信输入** * ——把它原样回显给一个运维控制台,等于给一次 prompt injection 开一条到人眼/到日志的直通路。真正要看 * 原文的场合有正门:mint 归档(`planArchive` 定位符照常上 wire,它是文件名不是正文)。 * 其余每一格(用量/修复计数/写失败计数/停因/收敛位)都是**核算**数据 —— 那正是这一口存在的理由: * 让运维看得见每一轮花了什么。 * * ── 这一口是**分钟级**的持久作业,而且**重试安全** ──────────────────────────────────────────────── * core 的 run 是 "a persistent job measured in minutes":出厂缺省下一次冷启动折叠是十几个 cycle, * cycle 之间有 60s 硬节流。所以 HTTP 客户端可能先超时 —— 那**不是**故障:run 行是 durable 的,同一 * scope 上有 pending run 时下一次调用 **CONTINUE** 它(同一 plan 缓存、同一 force requestId、**零新 * mint**,core 的 GD-15 幂等再入)。⇒ 调用方的正确动作是「原样重发」,不是「换个 scope 再试」。 * * 计费/lane:本口**真的烧模型**(而且是本仓单次调用里最贵的一种),所以它进 `isBillableSubmitPath` * —— 三道 503 门(drain / model-roster-pending / 无 service-token)必须罩住它。状态读那一口零模型 * 工作 ⇒ billable=false。两条申明在 test/billable-route-declaration.test.ts。 * * 分层:本模块不值 import `server.ts`(那条边闭合运行时装载环),只 `import type`。 */ import type { IncomingMessage, ServerResponse } from "node:http"; import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js"; export declare const MEMORY_CONSOLIDATION_STATUS_PATH = "/v1/admin/memory/consolidation"; export declare const MEMORY_CONSOLIDATION_RUN_PATH = "/v1/admin/memory/consolidation/run"; export declare function handleMemoryConsolidation(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; export declare const MEMORY_CONSOLIDATION_ROUTES: readonly [{ readonly id: "memory-consolidation-run"; readonly path: "/v1/admin/memory/consolidation/run"; readonly billable: true; readonly methods: readonly ["POST"]; }, { readonly id: "memory-consolidation-status"; readonly path: "/v1/admin/memory/consolidation"; readonly methods: readonly ["GET"]; }]; /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽(漏一口 = 编译红)。 */ export type MemoryConsolidationRouteId = RouteIdsOf; //# sourceMappingURL=memory-consolidation.d.ts.map