/** * [ref] §3.1 / [ref] §1.3([ref] S-2)—— per-principal **memory-capture opt-out 授权表**的 operator 四口: * * · `GET /v1/admin/memory-optout` → `{ deploymentDefault: Row|null, overrides: Row[] }` * · `PUT /v1/admin/memory-optout` body `{allow, note?}` → 部署缺省行 upsert(哨兵 `principal=''`) * · `PUT /v1/admin/memory-optout/:principal` body `{allow, note?}` → per-principal 覆盖行 upsert * · `DELETE /v1/admin/memory-optout/:principal` → 撤覆盖(回落部署缺省);`{ deleted: boolean }` 诚实答 * * Row = `{ principal, allow, updatedAtMs, updatedBy, note? }`(审计行内,[ref] §1.3;`updatedBy` = 调用方 operator * principal,server 铸,body 不收)。 * * ── 稿偏离两条(如实记)──────────────────────────────────────────────────────────────────────────── * ① [ref] §1.1/§1.3 写的是 `orgDefault` + `(org_id, principal)`。亲读本仓(2026-08-30 侦察):server **没有 org 身份维** * (租户维 = 单 principal;`org` 只是记忆 scope 目录里的词),给表/wire 铸一根没人能填的 `org_id` 是编数据。一台 * worker = 一个租户面 ⇒ 「org 级缺省」落成**部署级缺省**,wire 键名随实体改叫 `deploymentDefault`。折叠律不变。 * ② [ref] §1.3 把部署缺省写成 `PUT …/memory-optout/default`。codex R1-[medium] 验真:`default` 是一个**合法 principal * 拼写**,字面路径 `/default` 与 `%64efault`(解码后同为 `default`)在第一版里分派到**两个不同的行**(哨兵行 vs * 一条名叫 default 的覆盖行)—— 命名空间碰撞,而且 DELETE 侧还不对称。修法不是「解码后再保留一个词」(那只是把 * 碰撞改成一条不可寻址的 principal),而是**让缺省行住在集合根**:`PUT /v1/admin/memory-optout`(集合本身的 * 「缺省」属性),`:principal` 面从此没有任何保留词,任何合法 principal(包括字面 `default`)都可寻址。 * * ── 族属与门序 ──────────────────────────────────────────────────────────────────────────────────── * 与 `/v1/admin/drain` · `/v1/admin/config/refresh` · `/v1/admin/memory/consolidation` 逐字同族(operator lane: * 同一条 `explicitOperatorOk` 门;billable=false;刻意不吃 drain / roster-pending 两道 503)。门序照 operator * 面既有口径:身份(401)→ 授权(403)→ **能力(501)** → 验型(400)。授权在能力之前:一个够不着任何东西 * 的调用方不该从「这台有没有授权表」上读出部署形态。 * 🔴 四口都在 `isCredentialGatedRewrite`(server.ts)门内(codex R1-[high] 验真后补):授权的**唯一**输入是 * principal 头 ∧ 一次调用的爆炸半径跨租户(改缺省行 = 改整台部署每个 principal 的 verdict;读面 = 全部授权行 + * operator 手写的 note)—— 无 service 凭证且未开 `ALLOW_UNAUTHED_WRITES` 的 worker 上那个头**可自造**,与 * `/v1/memory/erase` / `POST /v1/memory/export` 同一条论证。 * * ── 为什么缺席形是 **501 `capability.*`** 而不是 404(与 consolidation 阀门刻意分家)────────────────── * consolidation 的 404 说的是「旋钮没开」(运维表态,动作=开旋钮)。本面的缺席是「**这家店在本部署上不存在**」 * —— local 车道刻意不给授权表一个会遗忘的 in-memory twin(接口注),动作=换部署形态(接 SQL 后端)。那正是 * 本仓 501 `capability.*` 族的定义(`capability.memory_engine_required` / `capability.outcome_ledger_required` * 同族)。能力位 `memoryOptOutGrant`(`GET /v1/capabilities`)读同一个事实 + operator 名单非空。 * * ── 撤销窗([ref] §1.4)────────────────────────────────────────────────────────────────────────── * 写后**零缓存**:resolver 腿(`RuntimeCaps.allowMemoryOptOut`)每次 prepare 直读同一张表 ⇒ 下一次带声明的 * prepare 即读到新 verdict(撤权后新声明具名拒;已声明会话 record wins,core 判,server 零码)。 */ import type { IncomingMessage, ServerResponse } from "node:http"; import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js"; export declare const ADMIN_MEMORY_OPTOUT_PATH = "/v1/admin/memory-optout"; /** 带参口(`:principal`)⇒ 路由声明表(`http/route-table.ts`)里走 `pattern` 行,不是 `path` 行。 */ export declare const ADMIN_MEMORY_OPTOUT_OVERRIDE_RE: RegExp; export declare function handleMemoryOptOut(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; export declare const MEMORY_OPTOUT_ROUTES: readonly [{ readonly id: "memory-optout-grants-list"; readonly path: "/v1/admin/memory-optout"; readonly credentialGated: readonly ["GET"]; readonly methods: readonly ["GET"]; }, { readonly id: "memory-optout-put-default"; readonly path: "/v1/admin/memory-optout"; readonly credentialGated: readonly ["PUT"]; readonly methods: readonly ["PUT"]; }, { readonly id: "memory-optout-put-override"; readonly pattern: RegExp; readonly label: "/v1/admin/memory-optout/:principal"; readonly methods: readonly ["PUT"]; }, { readonly id: "memory-optout-delete-override"; readonly pattern: RegExp; readonly label: "/v1/admin/memory-optout/:principal"; readonly methods: readonly ["DELETE"]; }, { readonly prefix: "/v1/admin/memory-optout/"; readonly credentialGated: readonly ["PUT", "DELETE"]; }]; /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽(漏一口 = 编译红)。 */ export type MemoryOptOutRouteId = RouteIdsOf; //# sourceMappingURL=admin-memory-optout.d.ts.map