@sema-agent/client-core 0.83.2 → 0.83.3

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/CHANGELOG.md CHANGED
@@ -49,6 +49,37 @@
49
49
  > 挡住 ⇒ 本批把它机械化——④a0 对 `pending` 行**要求段头已是日期形**(`(未发布)` 直接红),阶段一
50
50
  > commit 漏转在发布前就红,不再靠人记。
51
51
 
52
+ ## 0.83.3(2026-09-26)
53
+
54
+ > 主题:patch —— 三件入参 / 来源面放宽,零新运行期导出。① `--settings` 一类入口交来的 flag 来源设置里写的 hooks 进请求体(此前只投 managed / user / project / local 四源,flag 来源的 hooks 到不了引擎);flag 来源排在 local 之后,设置来源的拼接次序其余不变(managed 仍在最前)。② `listAllPersistedRules` 的入参只要 `list` 一口(新具名型 `RulesListFacade`;其余四口作为可选成员认得 —— 内联对象字面量、参数不写型的箭头照样可传,拼错口名照样报错),只装读 / 撤两口的宿主可以直接用。③ 模型身份判据认「目录缺省代替启动环境里的模型名」:宿主报本机引擎接受目录缺省(`engineAcceptsCatalogDefault: true`)时,只用模型目录文件的配置判 `resolvable`;报 `false` 判 `not_resolvable`;不报仍判不出(`unknown`)。根公面运行期导出 1273 不变;公面类型 +1(`RulesListFacade`);`HookSettingsSource` +1 员;`ModelIdentityLanes` 的目录一格闭集 +`complete`;`LocalEngineModelIdentityReading` +1 可选位;peer sdk 地板 `>=11.3.0` 不动;零 wire 投影臂。
55
+
56
+ ### Changed
57
+
58
+ - **flag 来源的 hooks 进请求体**:`hooksForWire()` / `hooksWirePlan()` 的设置来源由四源扩到五源,flag 来源(宿主经 `getSettingsForSource('flagSettings')` 交来的那份 —— 启动参数给的设置文件与内联设置)拼在 local 之后;同一事件的设置来源组按 managed → user → project → local → flag 拼接(managed 仍在最前,与 0.83.2 同)。治理与 user / project / local 同进退:`allowManagedHooksOnly`、hooks 面的 `strictPluginOnlyCustomization` 锁、非 managed 来源的合并 `disableAllHooks`(或读口抛错)三条「只发 managed」的规则下 flag 来源一并不发;managed `disableAllHooks`、未受信工作区、信任 / managed 读取抛错时零发。0.83.1 起对设置来源生效的两类拿掉(带参数的 command 条目在引擎报支持之前不发、`mcp_tool` 在传了计划时不发)与不传计划时的一次性告警,对 flag 来源同样生效;计划上 `settingsDropped[].source` 可为 `flagSettings`,开机「不会执行」清单上这一源的措辞是 `Flag settings`。flag 来源单独读取抛错时只当这一源没配 hooks(记一行调试),其余来源照发。flag 来源里的 `Stop` hook 上了请求体之后,`resolveHeadlessFinalVerifyDetail` 对显式 `--final-verify` 让位(`offReason: 'stop-hook'`),与其余来源的 `Stop` hook 同判。宿主不交 flag 来源(返回 `null`)⇒ 请求体与 0.83.2 同。接入文档 **§103a H-1 / H-2 / H-9**。
59
+ - **`listAllPersistedRules(facade, …)` 入参放宽**:由完整五口 `RulesFacade` 放宽为只要 `list`:入参型是 `RulesListFacade & Partial<Omit<RulesFacade, 'list'>>`(新具名型 `RulesListFacade` = `Pick<RulesFacade, 'list'>`,其余四口是型上认得的可选成员)。宿主把完整五口、读 / 撤两口或只 `list` 写成内联对象字面量直接传进来照样过型,箭头的参数不写型也拿得到上下文类型,拼错口名(如 `revokee`)照样报错。函数本来只调 `list`;完整的 `RulesFacade` 照样可传,运行期行为不变。成员与 `RulesFacade` 同名口型不兼容的对象(如 `revoke: 42`)仍被拒,与 0.83.2 同严。接入文档另写清 `classifyRulesFailure` 的各臂里列举 / 撤销两口实际会遇到哪几臂,以及「规则店不在」为什么只认机器码 `capability.rule_store_required`(§103a-1)。接入文档 **§103a R-1**。
60
+ - **模型身份判据认目录缺省**:服务端 7.101.0 起,缺省模型的判据挪到模型目录应用之后 —— 启动环境里的模型名或目录里的缺省模型任一在场即可启动。本包:`ModelIdentityLanes` 的目录文件一格闭集加 `complete`(目录里有一只启用的、可作缺省的模型);`LocalEngineModelIdentityReading` +1 可选位 `engineAcceptsCatalogDefault?: boolean`(宿主报它要起的本机引擎接不接受「目录缺省代替启动时的模型名」—— 启动前没有能力端点可读,本包不按版本号判)。判法(本机拓扑、目录一格报 `complete` 时):位为 `true` ⇒ 这一路可解析;位为 `false`(宿主明说本机引擎不接受)⇒ 目录的 `complete` 按 `partial` 处置(其余来路都明说时 `not_resolvable`);位缺席(含值为 `undefined` 的键)/ 不是布尔 ⇒ 这一路判不出(其余来路都明说时 `unknown`,与 0.83.2 同答)。远程拓扑不受影响。措辞:目录缺省可解析一句;引擎不接受一句(说目录里有缺省模型、宿主报引擎不接受,不说「目录里没有模型名」);判不出的句子里,位没报与位读不懂各一段,都点名目录里有缺省模型;位 `false` 而别的来路判不出时(`unknown`),判不出的句子里同样有「目录里有缺省模型、宿主报引擎不接受」一段。🔴 改口:0.82.1 起目录一格报 `complete` 一律答 `unknown`(值不在闭集,措辞说这一路的读数用不了);本版起报了位 `true` 答 `resolvable`、位 `false` 答 `not_resolvable`,没报位仍答 `unknown` 但措辞改为点名目录。接入文档 **§103a M-1–M-3 / 103a′**。
61
+
62
+ ### Gates
63
+
64
+ - 扩门 `run-hooks-merged-disable-projection-test.mjs`(FS 段):flag 来源进请求体、拼接序 managed → user → project → local → flag、九种治理形下与 user / project / local 同进退、单源读抛错只丢这一源、exec 形拿掉 + 一次性告警 / 计划拿掉记录 / 开机清单措辞与来源次序(managed 在前)、下游 final-verify 让位同判、`HookSettingsSource` 五源(构建产物声明,AST);可选的引擎执行面一段(FS7):把请求体原样交给装好的服务端发布版的 hook 执行入口 —— 非 managed 组挂满事件时间预算(时钟垫片,不真等)/ 占满每事件四条模型条目 / 挤满上下文总帽三形下,managed 的拒绝 / 拦截 / 上下文照样生效(user / project / local / flag 各格);另钉已知代价:排在 managed 之后的非 managed 组在 managed 放行之后改写 `PreToolUse` 输入,答放行 + 改写后的输入(与 0.83.2 同答);四格手排请求体的自证先证服务端这三种资源确实先到先得;没装服务端包时这一段如实标为未跑。
65
+ - 扩门 `run-rules-side-test.mjs`(G3t):合成一份消费方 `.ts` 从构建产物入口引入、真跑 tsc —— 只实现 `list` 的两口对象 / 只带 `list` 的字面量 / `Pick` 切片 / 具名型 / 完整五口变量 / 完整五口内联字面量 / 读撤两口内联字面量 / 完整五口与读撤两口写成参数不写型的内联箭头都零诊断;内联字面量拼错口名恰报一条;缺 `list` 与 `list` 不是函数各报一条(判据自证);运行期两口对象照列全、只调 `list`。
66
+ - 扩门 `run-model-identity-resolvability-test.mjs`(S8 段):目录缺省可解析 / 位 `false` 按 `partial` / 位缺席与非布尔判不出(与 0.83.2 同答、不弹向导)/ 判不出的目录不挡别路 / 位不救非 `complete` 的目录读数 / 25 格回归矩阵(目录不是 `complete` 时位 true / false / 缺席判据与措辞逐字同答)/ 远程拓扑不读位 / 原型链上的位不算 / 位的取值器抛错不抛 / 目录一路四段措辞(判不出的句子点名目录,没报与读不懂分开,值为 `undefined` 的键按没报;与别路读不出并存时两件都说,位 `false` 那一形同样)/ 构建产物声明型面(合成消费方真跑 tsc)。
67
+ - 改门 `run-approval-frame-keys-test.mjs`:服务端 7.102.0 发布版的审批帧已带 `mandate`,按登记自己的退出条件删掉「领先服务端发布版」那一格;SDK 运行期锚仍无此键,领先登记本身保留。
68
+ - 编译期钉:目录一路「可解析」只能拿「位是字面 `true`」的证据铸(证据型的位放宽到收得下缺席或 `false` ⇒ 构建即红;可解析的「来路」臂型上不收目录一路);flag 来源进遍历表与计划型面来源联合两向钉(沿用 0.83.1 的两向钉)。
69
+
70
+ ### Known limits(本版新增)
71
+
72
+ - flag 来源按宿主 `getSettingsForSource('flagSettings')` 交来的那一份读:本包不分「启动参数给的文件」与「内联设置」,两者由宿主合成一份交来。宿主只交文件那一份时,内联设置里的 hooks 仍到不了引擎。
73
+ - 设置来源之间不去重:同一条 hook 同时写在两个来源里,请求体上出现两次(与 0.83.2 对四源的处置相同,本版把 flag 来源纳入同一处置)。
74
+ - 宿主报的启动模式位 `suppressedByStartupMode`(安全 / bare)只筛插件 hook;设置来源(user / project / local / flag)在这一位下不收窄,照发引擎。
75
+ - 设置来源 hooks 的拼接次序 managed 在前:`PreToolUse` 上排在 managed 之后的非 managed hook(设置来源与插件注册的组)能在 managed 放行之后改写输入(与 0.83.2 同)。把 managed 排到最后会让它被引擎 hook 执行器的每事件时间预算、每事件模型条目上限与上下文总帽挤掉(不执行、调用照常);两种次序在逐条执行的执行器上都有绕过,候引擎侧支持。
76
+ - 模型身份:目录一格 `complete` 只说「目录里有一只启用的、可作缺省的模型」,那只模型在本机能不能服务、网关认不认那个名,由引擎启动与首轮调用判,本判据不答;配置中心下发的目录在启动预算之后才到的,启动时算不在场。宿主不报 `engineAcceptsCatalogDefault` 时只用目录的配置答 `unknown`(不弹向导,也不宣称已配置)。
77
+ - 列举口第一页的 `request.query_invalid`(过滤 `scope` 读不出形,此时还没有游标)经 `classifyRulesFailure` 落 `cursor-stale` 一臂,`listAllPersistedRules` 不重试、原样交出(失败信息里带服务端原句);按 `cursor-stale` 提示「重试」对这一形没有用。
78
+ - 完整台账见接入文档 §103 末行「包侧缺口」。
79
+ ```
80
+
81
+ ---
82
+
52
83
  ## 0.83.2(2026-09-26)
53
84
 
54
85
  > 主题:patch —— 只增公面,两组公共判定归包。① 审批卡一族三件:引擎 7.32.0 提货,卡上认「强制位站在哪一个词上」(`mandate`,六词闭集)并给读口与每词一句说明,通告码册 +2(CC-195);停泊审批行重开的卡带上出身词 `origin`(CC-196);常驻姿态(bypass 一类)下「哪一只 ask 不许被姿态替人放行」的三端单一谓词 `askSurvivesPosture`(CC-193)。② 后台子代「缺席行」的判定、计数、sweep 豁免、回收与措辞收成一组纯判定(CC-194)。根公面运行期导出 1254 → **1273**(+19),公面类型 +13,`ApprovalCardRequest` / `ToolApprovalFrame` 各 +1 可选键;开发依赖引擎 `~7.32.0`;peer sdk 地板 `>=11.3.0` 不动;零 wire 投影臂。
package/README.md CHANGED
@@ -35,7 +35,7 @@ Renamed from **`@sema-agent/wire-cc-adapter`** (0.1.x, deprecated — see *Migra
35
35
 
36
36
  ## Scope
37
37
 
38
- **Version:** 0.83.2
38
+ **Version:** 0.83.3
39
39
 
40
40
  - **Today** — the adapter seam, the whole `adapt()` pipeline (all 14 A-layer arms plus the
41
41
  B/D/E tool-card layers), the notification/caps/model families, the adapter kernel (stream driver
@@ -293,7 +293,7 @@ guard still cross-checks the table by name).
293
293
  | `scripts/run-client-core-portability-test.mjs` | Kernel / A-layer / index import closures, the runtime-dependency equality gate, barrel reachability, and a real esbuild `--platform=browser` bundle |
294
294
  | `scripts/run-client-core-diff-test.mjs` | Differential equivalence against the CLI reference bridge + replay-id invariant + ledger round-trip |
295
295
  | `scripts/run-seat-contract-keys-test.mjs` | The seat IPC contract: verb list ↔ SPEC ↔ types, element-wise |
296
- | `scripts/run-approval-frame-keys-test.mjs` | The tool-approval frame key mirror, element-wise against the SDK's runtime anchor (one carve-out: AHEAD_OF_ANCHOR entries — keys the server already emits but the SDK anchor has not caught up to — may lead by one generation; the gate turns red the day the SDK catches up, forcing the entry's removal — the register is occupied again — this time by the bit that says a saved allow rule cannot retire a given approval card, carrying both the release that minted it and the byte coordinates that prove it, so the lead is a dated record rather than an exemption; its predecessor left the register the other way, by being retired upstream rather than by the anchor catching up). Beside the key mirror it now guards three further faces of that bit: the closed word table the durable leg reads it through must be **the very array object the SDK exports**, not a same-looking copy — reference identity, because an equal-contents check still permits a second table that diverges the day upstream adds a member; the one predicate a client is meant to call answers over both legs — the live card's bit and the parked row's absence word, which is all the row carries, since the row has no such bit at all — and answers `false` for a malformed value exactly as its presence-only siblings do, a strictness the upstream mint shares; and the one sentence minted for it must never point the reader at writing a rule, since a rule written in answer to a mandated question can never take effect where it was written. The same bit's key also has to reach the card request itself, which the SDK's card anchor does not list — a fact that arrives at the package boundary and stops there is the shape of defect this file's guards exist to catch Since 0.83.2 the frame also mirrors `mandate` (the word a mandated question stands on) ahead of the SDK anchor and of the released server fixture, each allowance carrying its own exit condition; the installed engine must declare the member with the six-word closed type, and the key must reach the card request. |
296
+ | `scripts/run-approval-frame-keys-test.mjs` | The tool-approval frame key mirror, element-wise against the SDK's runtime anchor (one carve-out: AHEAD_OF_ANCHOR entries — keys the server already emits but the SDK anchor has not caught up to — may lead by one generation; the gate turns red the day the SDK catches up, forcing the entry's removal — the register is occupied again — this time by the bit that says a saved allow rule cannot retire a given approval card, carrying both the release that minted it and the byte coordinates that prove it, so the lead is a dated record rather than an exemption; its predecessor left the register the other way, by being retired upstream rather than by the anchor catching up). Beside the key mirror it now guards three further faces of that bit: the closed word table the durable leg reads it through must be **the very array object the SDK exports**, not a same-looking copy — reference identity, because an equal-contents check still permits a second table that diverges the day upstream adds a member; the one predicate a client is meant to call answers over both legs — the live card's bit and the parked row's absence word, which is all the row carries, since the row has no such bit at all — and answers `false` for a malformed value exactly as its presence-only siblings do, a strictness the upstream mint shares; and the one sentence minted for it must never point the reader at writing a rule, since a rule written in answer to a mandated question can never take effect where it was written. The same bit's key also has to reach the card request itself, which the SDK's card anchor does not list — a fact that arrives at the package boundary and stops there is the shape of defect this file's guards exist to catch. Since 0.83.2 the frame also mirrors `mandate` (the word a mandated question stands on) ahead of the SDK anchor, with its own exit condition; the released server carries it from 7.102.0, so the allowance for the server fixture was removed by its own exit condition. The installed engine must declare the member with the six-word closed type, and the key must reach the card request. |
297
297
  | `scripts/run-segment-authority-single-source-test.mjs` | The authoritative-segment replacement verdict, single-sourced. `text_end.content` and the `text_delta` stream stopped being byte-identical the day the engine started redacting the former through the same filter as the result, so every consumer now has to decide six ways what to do with the segment it has half-emitted — and until this release that decision existed **twice**: once here for the transcript lane, once in the shell for the print lane, hot-fixed a version apart. The verdict is now one pure function both lanes call, and the guard pins it on the quantity that actually decides the outcome: whether the authoritative text still *starts with* the bytes that already left, not whether a flush has happened — the latter is a precondition, and anchoring on it withholds a perfectly ordinary answer. Each of the six forms is checked with its counter-case, the prefix length is pinned to UTF-16 code units against a non-ASCII sample whose UTF-8 byte count differs (slicing by bytes leaves the very thing being redacted on screen), and the withheld-segment ledger is compared by normalised equality rather than substring, because a short redaction marker quoted in an unrelated later answer would otherwise suppress that answer entirely. The same file pins the session-level memory-capture declaration to one mint point — the wire value is a single-member closed set, and a consumer that spells it wrong gets a loud refusal rather than a silently dropped privacy request — and pins the SDK URL/health transit to be the **same function reference**, since wrapping it would discard the one guarantee the transit exists for. A last section strips comments with the TypeScript parser and asserts the second expression has not grown back |
298
298
  | `scripts/run-print-bash-iserror-test.mjs` | The print lane's Bash `is_error` authority (structured over regex). A second section pins where the denial classification word lands on this lane: on the message envelope, never inside the tool-result block, because that block is forwarded verbatim to the provider on compaction and a self-minted key there is the shape of an old, real defect. A word outside the upstream table — or an empty string, a non-string, or nothing at all — mints no key rather than a guess, and the word never moves the error flag, because attribution does not decide anything |
299
299
  | `scripts/run-bash-benign-exit-interpretation-test.mjs` | Benign non-zero Bash exits (`returnCodeInterpretation`) stay non-errors across all three derivation arms, and the annotation transits to the card |
@@ -369,7 +369,7 @@ guard still cross-checks the table by name).
369
369
  | `scripts/run-package-hygiene-test.mjs` | Everything `package.json` `files` ships — dist JS/typings and the Markdown docs — is screened line-by-line against a deny-list of strings that must never reach a public tarball (internal hostnames, codenames, person names, collaboration-process words, other repos' ledger ids and repo names; opaque ticket ids `CC-nnn` and post numbers `[nnnn]` are allowed as traceability references). Since 0.77.2 the build strips comments (`removeComments`; enforced by `run-dist-comments-test.mjs`), so what this gate screens in dist is code, string literals and type-level text. Markdown docs are enforced forward-only (CHANGELOG from 0.77.2, the integration doc from §81) because published sections are frozen.
370
370
  | `scripts/run-integration-doc-freshness-test.mjs` | The **integration contract** (`docs/INTEGRATION-CLIENTS.md`) and the **changelog** (`CHANGELOG.md`) checked against the code, because a document with no guard rots — this one had a whole nest of drift found on it within a day of being written. Five directions, each a claim a machine can actually evaluate. (1) *Counting discipline*: the version-anchor row for the guard count may no longer carry a hand-copied number at all — it changes every time a guard is added, and writing it down is planting a timer; the export counts that are still hand-copied (the surface total, the test-hook count, the sentence describing the surface's internal composition, the sum of the sixteen domain rows, and the three sub-counts) are each compared against a value **derived** from `public-export-baseline.json`, which is the drift a human reviewer caught last time. (2) *Coordinates alive*: every `src/` `scripts/` `docs/` path the doc quotes must be on disk **and tracked by git** — on disk is not in the repo, and a doc that points readers at a file living only in its author's working tree sends every clone to nothing. A file landing in the same commit takes a named carve-out that **stops applying** the moment the file is really tracked (it can no longer let anything through, and the guard prints a line asking for it to be deleted) — deliberately not a red, since turning red on the very commit that lands the file would just manufacture a break that only a follow-up commit could clear. (3) *Arm tables*: the `hitl_out_of_slice` row and the `not_in_slice` fenced list must equal, name for name and in **both** directions, the case labels that really fall into those two buckets — read through the **TypeScript AST**, since which bucket an arm lands in is decided by the argument to `nothing(...)` and by nothing a comment says. The extractor is anchored to the one production projector: exactly one function named `eventToSdkMessage`, exactly one `switch (ev.type)` inside it, and no repeated case label — anything else is a broken anchor rather than a verdict, because a second same-shaped switch elsewhere in the file would otherwise overwrite the real one's conclusions and leave the doc agreeing with a switch nobody runs. The list is delimited by a machine-readable fence rather than by section headings, because the same section also names the terminal arms as a counter-example and prose boundaries cannot tell a member from a foil. (4) *Released sections are frozen*: an **append-only ledger** carries every version ever published — its number, the commit it was published from, and the sha256 of its section — and each one is checked, not just the current release, since pinning only the latest would set every earlier version free the moment the next one ships. The ledger cannot vouch for itself either: each recorded hash is **re-derived from that release commit** through git, so editing an old section and its constant together no longer passes — and the commit the row names is in turn checked against the `gitHead` npm recorded at publish time, which is the one value this repository cannot rewrite, so pointing an old version at a freshly written commit does not pass either. The *set* of versions that must be frozen comes from the registry too, so deleting an old row together with its section — which would otherwise remove that version from every set the guard looks at — is red rather than invisible. A failed registry call is classified rather than swallowed, and the classification consults the registry's own status code *before* it considers connection-level symptoms, so an auth refusal whose body happens to mention the network is still red rather than a skip. The version set is compared as full SemVer including prereleases — matching only `x.y.z` would silently drop a published `0.30.0-beta.1` and reopen the very hole this direction closes — and section headings are matched on a whole-version boundary so a stable release cannot bind itself to the release-candidate section sitting above it. Publishing itself is a two-phase protocol rather than a paradox: before a release, exactly one row may be marked pending and must name the current `package.json` version, exempt from the checks whose inputs do not exist yet; once the registry has that version the row must be promoted, so the temporary state cannot survive its own release. And because the pending exemption rests entirely on "this version is not out yet," it is refused outright when the registry cannot be reached to confirm that — an unverifiable premise is not a licence. Three reverse directions close the rest: a section claiming to be released but absent from the ledger, a ledger entry whose section has vanished, and a `package.json` version that was never frozen. Publishing appends a row; it never rewrites one. (6) *Sentinels*: the readers §5a hands hosts for "is this port installed" are checked against what the source actually declares it returns — `hasXxx()` is a `boolean`, the card port / HITL surface / wire target return `T \| null`, the `installHost` family returns `T \| undefined`. Testing a `null`-returning reader for `!== undefined` is *always true*, and a self-check that passes whether or not the port is installed is worse than none, because hosts retire their own fallback on the strength of it. Both directions are red: an implementation that changes its sentinel without the doc following, and a doc that names the wrong one. The roster covers the zero-argument readers and their `*For` variants alike — a multi-session host reads the variants, so leaving them off would let exactly the surface desktop depends on drift unwatched — and the §5a table and the §8-B checklist line are each checked against the source, because hosts tick the checklist, and a guard that only watches the prose table misses the line people actually follow. (5) *Packaging*: the README ships with the package and opens by pointing hosts at the integration doc, and the checklist names two more files as required reading before an upgrade — all three must really appear in the `npm pack` manifest, or an npm consumer follows a relative link that npmjs rewrites onto a private repository. Missing tooling never takes the whole verdict down with it: when git, npm or the registry is unreachable those legs print the `SKIPPED-SECTION` marker and the rest still judges, while a release commit the ledger names but git cannot resolve is red rather than skipped. The guard says in its own header what it does **not** do: it judges counts, coordinates, arm sets, released bytes and the packing list — whether a sentence is *right* is still for review and for the hosts to report (7) *Retired names*: every name in the per-version `removed` ledger of `scripts/export-liveness.json` may appear in the integration doc only where a retirement note follows the name inside the same clause (or the table row's label cell is itself a retirement label); the scan is by identifier boundary after invisible text (HTML comments, link targets, reference-link labels, tag attributes) has been stripped, so a signature line in a code block, an inline `NAME = 4096`, a hidden note, or a note that belongs to a neighbouring name all count as a bare recommendation and go red. |
371
371
  | `scripts/run-type-superset-ledger-test.mjs` | The type/wire **superset ledger** (`docs/type-superset.json`): positions this package adds on top of a CC-shaped contract, each carrying the evidence for what CC's own type surface does or does not have there. Completeness is deliberately uneven and the ledger says so. The `_sema_*` private-key class is checked in **both** directions (a key in the source that never entered the ledger is red, naming key and file; a ledger row whose key left the source is red) — but only for keys written as literals, which is the convention the ledger mandates. A key assembled by string arithmetic is beyond what any static rule can enumerate, so the guard fails closed on every shape it *can* decide (a bare `_sema_` prefix is red wherever it appears, save one pinned guard site) and leaves the rest as a convention violation for review to catch, rather than claiming a completeness it does not have. The two hand-surveyed classes are only checked for coordinate and evidence integrity, never discovered. Both directions read the source through the **TypeScript AST**, not a text scan, and they read two different sets out of it. A *key site* is an identifier, or a string whose whole value is the key — so `'_sema_decision-v2'` is carried whole rather than truncated at the first non-identifier character into some *other* key that happens to be registered. A *mention* is the key appearing inside a longer string, which is prose, not usage. The staleness direction counts key sites only: a comment or a doc sentence left behind after the last real mint site is deleted must not keep the row alive (mutation-proven — with both the comment and the prose string untouched, removing the one real site turns the guard red). And because a prefix can be concatenated or interpolated into a key no static set will ever see, the bare `_sema_` literal is refused outright rather than traced: every occurrence is red except the single inline `startsWith` guard the sanitizer needs, because the set of expressions a bare prefix can travel through on its way to a concatenation is open-ended and enumerating it is always one form behind. Every row's `host` must still resolve, with the key being a real **member of that declaration** rather than a string occurring somewhere in the same file — `governanceForced`/`delegation` each live on two different shapes in one file, and a member commented out is a member deleted, which a text-shaped check happily reads as still present. And the direction worth the most: each machine-form `ccAbsenceEvidence` is re-derived from the row's own `key` — the ledger's recorded string must match that derivation verbatim, since a row quietly witnessing `\bnever_present\b` is green forever while watching nothing (mutation-proven: the same edit passes the unbound form and is caught by the bound one) — and the check runs against the names the installed `@sema-agent/agent-types` `.d.ts` set actually declares, parsed with the TypeScript AST rather than grepped, so a name CC merely mentions in a comment cannot force the row into the manual escape hatch and thereby retire the very witness that was supposed to fire the day CC declares that name for real. That escape hatch is gated by an allowlist living **in the guard**, not the ledger, so claiming it costs a reviewed diff. Missing material never reads as a pass, and the verdict splits by *why* it is missing: no TypeScript parser skips the suite before it starts; a missing `agent-types` still runs and prints the first three directions, then exits **1** when `package.json` declares the mirror but it is not installed — a broken install must not retire the repository's only "the day CC declares this name" alarm, and reporting it as a skip would leave "never evaluated" and "evaluated, no drift" indistinguishable to the runner — and exits 3 only when nothing declares the mirror at all, which is the one case where the direction genuinely does not apply. Either way a run that evaluated no witness is never counted as one that did. When the mirror *is* present its **installed version** is witnessed too (the two declared floors must agree with each other and the installed copy must meet them), since four preflight probes are satisfied by an arbitrarily stale mirror — they prove the extractor speaks, not that it is current. Every direction carries a positive control — known-present CC symbols, a comment-only sample proving the extractor distinguishes declaration from mention, and synthetic corpora fed through the **same** discriminator function the real verdict uses, so a verdict quietly rewritten to return nothing takes its own control down with it |
372
- | `scripts/run-rules-side-test.mjs` | The persisted-permission-rules lane's shared decision half. The two capability bits are checked as **two independent gates** — a worker can honestly advertise the rules lane while predating the revoke routes, and that shape must *hide* the governance surface rather than render a dead entry. Failure classification is by **disposition, not cause**: the two 404s (route missing vs. dead ticket) never share a bucket, a 503 `rule_import_retry` means *the ticket is still alive* (the opposite handling of a dead one), and a stale-cursor 400 drops the cursor and re-lists from the top exactly once — never resuming a stale keyset, never surfacing a partial governance list, and never paging past the hard cap. The persist-ack reader is **merged into** `readToolApprovalRespondAck`: the three-state verdict (`persisted` / `refused` / `unknown`) is derived only from an ack that passed the package's structural narrowing, and a half-shaped object such as `{rulePersisted: true}` with no `delivery` reads as `unknown` — the pre-merge shell read would have said `persisted`, which is precisely the double-ledger drift this file closes, so that case is pinned in reverse. The local-allow-rule skeleton pins all five narrowings (whole-tool, tool-name match, literal anchor with the escaped-star counter-example, bare interpreter prefix consulted only for Bash, and the canonical dangerous-pattern overlay) **with their refusal strings byte-for-byte** — the cli's 128-assertion suite anchors the same strings, so a one-character edit here changes observable behaviour on three clients — and asserts the parse is a pure function of its input, because the same call backs both "render the option" and "resolve the selected value" |
372
+ | `scripts/run-rules-side-test.mjs` | The persisted-permission-rules lane's shared decision half. The two capability bits are checked as **two independent gates** — a worker can honestly advertise the rules lane while predating the revoke routes, and that shape must *hide* the governance surface rather than render a dead entry. Failure classification is by **disposition, not cause**: the two 404s (route missing vs. dead ticket) never share a bucket, a 503 `rule_import_retry` means *the ticket is still alive* (the opposite handling of a dead one), and a stale-cursor 400 drops the cursor and re-lists from the top exactly once — never resuming a stale keyset, never surfacing a partial governance list, and never paging past the hard cap. The persist-ack reader is **merged into** `readToolApprovalRespondAck`: the three-state verdict (`persisted` / `refused` / `unknown`) is derived only from an ack that passed the package's structural narrowing, and a half-shaped object such as `{rulePersisted: true}` with no `delivery` reads as `unknown` — the pre-merge shell read would have said `persisted`, which is precisely the double-ledger drift this file closes, so that case is pinned in reverse. The local-allow-rule skeleton pins all five narrowings (whole-tool, tool-name match, literal anchor with the escaped-star counter-example, bare interpreter prefix consulted only for Bash, and the canonical dangerous-pattern overlay) **with their refusal strings byte-for-byte** — the cli's 128-assertion suite anchors the same strings, so a one-character edit here changes observable behaviour on three clients — and asserts the parse is a pure function of its input, because the same call backs both "render the option" and "resolve the selected value" `listAllPersistedRules` needs only `list` (`RulesListFacade`; the other four methods are known to the parameter type as optional members): a synthetic consumer compiled against the built declarations passes a two-method object, a list-only literal, a `Pick` slice, the named type, the full facade, and the full or two-method facade written as an inline object literal — including arrow functions with untyped parameters — all with zero diagnostics, while a misspelled method name in such a literal is still reported. |
373
373
  | `scripts/run-park-decision-layer-test.mjs` | The decision layer behind the "stuck behind a card" family, shared by every client. A pending row that is **not in the queue** is three states, not one: a bounded, interruptible re-probe loop distinguishes *a decidable row*, *not born yet* (no positive evidence that anything settled — an empty queue proves nothing) and *settled elsewhere*, always probes at least once so a zero budget keeps the pre-fix semantics verbatim, cuts a hung read face off at the window rather than only noticing afterwards, and reports the honest failure when the window is spent instead of inventing a decision. The decision-note reader is likewise three-state: an explicit `noteRecorded: false` outranks an echoed note body, absence renders **no line at all**, and untrusted note text is flattened and bounded before it ever reaches a renderer. Row routing anchors on the deciding quantity — a row carrying `gateKind: "human"` with `toolName: "Write"` is a tool gate, because `human` is the engine's *generic* "someone must decide", not a synonym for a question — and the queue scan refuses to surface a row it cannot positively prove belongs to this session. A chain that fails after the row vanished is split by whether a card was ever presented: decided-elsewhere, or not-its-turn-yet. A row-level single-flight makes "at most one card per pending item" structural rather than incidental. The resume three-way card pins the option **order** (the zero-effect choice sits at index 0, because the frame carries no default-focus field and a stray Enter must not attach or cancel), renders only options the wired verbs can honour, collapses every ambiguous answer to zero action, omits the liveness line entirely when the engine gave no evidence, and — when there is no card lane at all — prints three real routes and exits on a dedicated code rather than reporting success |
374
374
  | `scripts/run-selfheal-reopen-test.mjs` | The 409 active-run self-heal decision chain: `governanceForced` narrows on strict `true` only; triage prefers the wire's `pendingGate.kind` and falls back to the status table (an off-table kind is never guessed into a card arm — hands-off plus the honest wording); a first-sight card makes zero closed/reopened claims and a host presentation receipt of `presented: false` demotes the outcome to reopen-failed; park-row ownership is a fail-closed positive proof (own-run ledger or session id — unprovable is not owned); the three gate-identity key literals live in exactly one mint (`hitl/gateIdentity.ts`, AST string-token scan); the armed-gate presentation ledger is per-session; and the `plan_review` reopen arm shares the arm arm's card body, three-state verdict and delivery pipe, consuming the presentation history once a decision is delivered. The same chain also carries the `running` three-way card: both plan-family gate kinds route to the plan arm and all four ask-family kinds to the ask arm (an off-table kind still never gets guessed into either); the card is offered only for verbs that can actually be honoured and a missing presenter means zero action rather than a silent cancel; a steer is sent **exactly once** with its three delivery outcomes worded apart (a `queued` receipt is the wire correcting the triage input, so the named park word decides which card gets reopened, and an unrecognised park word drives neither arm), and a steer failure is split into *provably not delivered* (4xx) and *delivery unknown*, because telling a user to resend a non-idempotent instruction that may already have landed is how duplicates get made. After a user-chosen cancel, "the session is free" is asserted only from a whitelist of terminal states — park states hold the claim, an unrecognised state word is not a release, a failed read is *unknown* rather than a release, and only a 404 counts as one — and the honest timeout line quotes how long it really waited. The two "card could not be reopened" rows can carry a host-declared way to keep the conversation, which says the card comes back on resume only if it is still waiting: it is placed before the route that abandons it, never offered for an injected submission, while a decision is still on its way, or once the pending approval has been proven gone (the outcome then carries a flag saying so; the proof only counts before the cleanup card is shown, so a fallback after the card carries no flag unless a fresh read finds the run finished, and a recheck that finds the approval back clears it), the host function is not even called in those cases, and it is treated as unavailable when it throws or returns an empty value; a host can also switch off the engine decide route on the interactive rows while the cancel route stays, and with neither given all four rows are pinned byte-for-byte to the text the previous release produced. |
375
375
  | `scripts/run-terminal-identity-copy-test.mjs` | Terminal-state **identity**, in both lanes where a stop gets a name. A run stopped by this deployment's own governance knobs — the open-set `limits.*` family, `output.invalid`, and the `blocked` contract terminal a ReportBlocked agent produces — is not a provider failure, and labelling it `API Error:` sends the reader to check the network, the key and the quota when the handle is the `--max-turns` they passed themselves. Those terminals now render a neutral row; the reverse direction is guarded just as hard, because asserting "this is *not* an API error" on a code the package does not recognise is the same misfiling pointed the other way — a real `gateway HTTP 502`, a `conflict.session_active_run` and any unknown code all keep the `API Error:` prefix, and the row keeps its `isApiErrorMessage` class flag so brief-mode visibility filtering does not silently drop it. The second half is who the rejected submission belonged to: the self-heal copy told every caller "Your message was NOT sent … send it again", which is three separate untruths for a system injection (a plan-review outcome, a cron wake-up, a task notification) — not the user's message, and not re-sendable, since a host queue marks those non-editable and non-recallable. The injected form says so instead, and the one sentence that promises re-delivery is pinned to the single disposition that earns it: `selfHealSubmissionDisposition` is the same function the host consults before putting the item back on its queue, so the promise and the behaviour cannot drift apart, and the arms where no card could be surfaced state plainly that nothing was delivered and nothing will retry. Since 0.72.6 the same gate pins the **follow intent** after a steer (): a message handed to a live run only pays off if someone tails that run's own event stream, so `steerFollowIntent` decides from the delivery word whether to tail now, after the pending decision, or only after a wake — and the "watch that run" sentence ("watch that reply" on the rows about follow-up messages sema sent on its own) turns into a factual "sema is following that run" ("… that reply") **only** when the host declares it attached that tail, so a shell that did not wire it can never claim it did. Since 0.83.0 the rows about follow-up messages sema sent on its own carry no engine-internal words and say what happened per delivery shape, promising a resend or "nothing for you to do" only where the code guarantees it |
@@ -419,10 +419,10 @@ guard still cross-checks the table by name).
419
419
  | `scripts/run-rewind-archive-capability-test.mjs` | The read face for whether a rewind can restore the code archive, and the honest three-state answer the ends render from it. The shells used to decide this from a local backup table that only their own in-process tools ever fill, so on any session where the engine runs the tools it stayed empty and the two code-restoring rewind modes simply never appeared, while the engine had been keeping a file history the whole time. The judgement now comes from what the engine itself advertises, and each of the four bits it advertises answers a different question: whether the conversation can be forked at a message at all, whether a fork can restore the tracked set, whether a code-only restore is possible, and whether this deployment understands the current spelling of the request key. The mode that rewinds the conversation and restores the code together needs both of the first two, and the engine offers no single bit for that combination, so the combination is made here: one bit stated off is enough to rule the mode out, both stated on make it available, anything else stays unknown — reading the file-history bit alone would offer that mode on a deployment that keeps file history but has no conversation anchors, where the request can only fail. A bit that is absent means an older engine that never spoke about it, which is not the same as an engine that said no, and a bit reported in a shape this reader cannot read is a third thing again — it is recorded as unreadable rather than quietly filed under "not reported", because those two send an operator to different places. One unreadable bit does not discard its siblings; only a response that is not a capability object at all clears the cell. What the ends get is available, unavailable or unknown, and unknown stays unknown: folding it into unavailable would hide the mode again, which is the mirror image of the bug this replaces. The sentences the doctor row can print are checked to be pairwise distinct and to avoid implying a refusal the engine never made, and the spelling of the outgoing request is deliberately not made to follow the epoch bit, since the older spelling is rejected outright by current engines |
420
420
  | `scripts/run-registry-quota-usage-test.mjs` | The projection of the cloud control plane's quota reading, and the three different things a missing number can mean there. This response says `null` in two places and means something different each time: no token quota is configured for this principal on this instance, and this window has no cap at all. Both are **facts the server is asserting**, not gaps in the reading — while a key that is absent or carries the wrong type is a genuine gap. All three have to survive to the screen separately, because folding them is how a user ends up staring at a confident `0`: an uncapped window rendered as if nothing were left, or a deployment that simply never configured quotas rendered as if the quota were exhausted. The complaint that started this was the opposite direction — a centrally configured quota that the command line could not see at all — so the reading also refuses to let an unreadable response masquerade as "no quota configured". Two fields deliberately do not share one signal: whether a window is exhausted and whether there is a recovery time, since the recovery time is only ever populated in the exhausted case and reading its absence as "not exhausted" would answer a question the response never answered. Counts that the server always provides are narrowed no further than the mint: a used counter has no uncapped state, so a null there is unreadable rather than zero. The wording helper carries the only human-facing phrasing, and the sentences for "no cap" and "unknown" are checked to contain no digits at all |
421
421
  | `scripts/run-file-history-capture-capability-test.mjs` | The engine's file-history-capture self-description (`capabilities.fileHistoryCapture`), read the same four-state way as its sibling capability readers: an absent key is reported as not reported (never folded into `off`), words are taken as an open set so a newer mode is not mistaken for a malformed answer, `fileHistoryCaptureMode` recognises only `off` and `on-always`, and the wording for `off` speaks about capture only — whether code can be rewound is left to the rewind readings. |
422
- | `scripts/run-model-identity-resolvability-test.mjs` | The model-identity judgement a client makes before letting anyone in: can the engine it is about to use start with a model name? Each end reports what it read from each place that can feed a model name to a local engine (complete, partial — a gateway address or a credential but no model name —, absent, or unreadable), or, for an engine that runs elsewhere, whether that engine has been seen answering; `modelIdentityResolvability` answers resolvable, unresolvable or unknown. Having part of an upstream configuration is not having enough of one, so partial lanes never add up to resolvable; a lane that was not reported or could not be read makes the answer unknown rather than unresolvable; an engine that runs elsewhere is never judged unresolvable and local lanes are never consulted for it (it does not start without a model name, so seeing it answer is enough to call it resolvable). `modelSetupDecision` combines that answer with whether this end can configure a model at all: setup is offered only for unresolvable on an end that can configure one, an end that cannot says so and points at whoever runs the engine, and unknown never opens setup. The detail and notice sentences are checked to be pairwise distinct, unknown sentences neither claim a model is configured nor that it is not, and the module is checked to import no platform I/O |
422
+ | `scripts/run-model-identity-resolvability-test.mjs` | The model-identity judgement a client makes before letting anyone in: can the engine it is about to use start with a model name? Each end reports what it read from each place that can feed a model name to a local engine (complete, partial — a gateway address or a credential but no model name —, absent, or unreadable), or, for an engine that runs elsewhere, whether that engine has been seen answering; `modelIdentityResolvability` answers resolvable, unresolvable or unknown. Having part of an upstream configuration is not having enough of one, so partial lanes never add up to resolvable; a lane that was not reported or could not be read makes the answer unknown rather than unresolvable; an engine that runs elsewhere is never judged unresolvable and local lanes are never consulted for it (it does not start without a model name, so seeing it answer is enough to call it resolvable). `modelSetupDecision` combines that answer with whether this end can configure a model at all: setup is offered only for unresolvable on an end that can configure one, an end that cannot says so and points at whoever runs the engine, and unknown never opens setup. The detail and notice sentences are checked to be pairwise distinct, unknown sentences neither claim a model is configured nor that it is not, and the module is checked to import no platform I/O The catalog lane counts as complete only when the host reports that the local engine accepts a catalog default; a report of `false` reads the catalog as partial, and no report (an explicit `undefined` included) or an unusable one leaves that lane undetermined — the same answer as before the catalog could be complete. Every sentence about a complete catalog names the catalog, including the undetermined sentence when the report is `false` and another lane cannot be read, and a 25-cell matrix pins that the report changes nothing when the catalog is not complete. |
423
423
  | `scripts/run-cloud-effective-projection-test.mjs` | The cloud control plane's effective-configuration response beyond its four configuration domains, and what a locally started engine does with the models document derived from it. Three top-level keys are read with the meaning their producer gives them: `warnings` (degradation warnings from the build that produced the served view — an empty list is a clean build, an absent key is an older server that cannot tell), and `budget` / `runtimeCaps`, where `null` means two different things: nothing resolves for this principal when you view yourself, and values withheld when the response previews another principal. A missing key or a wrong type is a third state, unknown, and none of the three is ever folded into a zero, a `false` or "no budget". A malformed warning row, budget field or cap costs only itself, and a known budget field of the wrong type is named as not shown rather than silently read as "no limit on this axis"; warning kinds are an open set, so a kind this client does not recognise still produces a warning line. The budget and cap readers are reconciled against the installed settings schema. The single wording source puts degradation warnings first and keeps every "not set / withheld / unknown" sentence free of digits, while a zero the server really sent is shown as a zero. On the models side, when the host injects an entry check the models document carries the default model, the tier groups and the active tier group (without the check none of the three is written), and every catalog reference the local engine's schema would reject — a default, role, @-mention entry, tier binding or active group that names something outside the catalog served to this principal — is dropped and recorded, because one dangling reference makes the local engine discard the whole models domain and fall back to its environment catalog; this is proven by reading the produced document with the installed file store. An @-mention allowlist that would be pruned to empty is kept as sent, since an empty list means "everything may be mentioned"; that case is recorded, produces its own warning that a locally started engine will reject the cloud model settings and use its environment catalog instead, and the gate reads the document with the installed file store to confirm exactly that outcome, so the sentence turns red the day the local reader becomes lenient. A per-model budget in which no field could be read is never described as having no limits. Registry annotation keys on model entries (`origin`, `overridesTeam`) are removed before the models document is written: the local engine's schema does not accept them, and a configuration refresh would otherwise be rejected as a whole. A model entry the host-injected entry check rejects is left out of the document and references to it are dropped: the local engine drops such an entry at startup, but a refresh rejects the whole configuration over it, so the gate requires a clean read of the produced document; when no entry passes the check, the catalog is kept as sent and gets its own warning, which the gate proves by reading the document back. The check receives a copy, so it cannot alter what is written. Tier words outside the local schema's closed set are dropped and recorded as unsupported, and the package's tier word list is reconciled against the installed schema in both directions; an active tier group is judged against group names, never model names. |
424
424
  | `scripts/run-websearch-verdict-test.mjs` | The per-request web-search configuration a host puts on the wire. Newer servers refuse the whole request when that section is malformed — and a missing or misspelled search provider now counts as malformed, because the section names where the searches go and an unknown destination is refused rather than silently swapped for the deployment's own backend. The old readers in this package dropped such a section without a word, which let the server swap destinations after all. The guard pins the new three-way verdict (absent, honoured, malformed with the field that is wrong) against the server's own judge, vector by vector, whenever that judge is available next to this package; it pins that a half-configured environment is malformed rather than ignored, that a malformed environment never falls back to the settings file (that would change the destination too), and that neither the sentence shown to the user nor the recorded reason repeats an endpoint, a key, or a search-parameter name or value — an unrecognised provider is never echoed either (the sentence lists the valid words instead), so a URL or key pasted into the wrong field does not come back out, even when it happens to be all letters. A host's key store is plugged in through a callback the package calls only after the provider has been recognised, so the precedence between environment and settings stays inside the package. Since 0.83.0 an endpoint that carries a user name or password is malformed as well (the server judges the same way from 7.101.0), the reason sentences match the server's own word for word, and the three older readers that dropped a misspelled provider are gone. |
425
- | `scripts/run-hooks-merged-disable-projection-test.mjs` | The fourth governance leg of the hooks projection: `disableAllHooks` set in a non-managed settings source. The value that counts is the **merged** one, read from the host through the optional `SettingsPort.mergedDisableAllHooks()`, because a per-source approximation ("any source says true") reads user `true` with local `false` backwards — the merged value there is `false` and every source's hooks ship. When the merged value is `true`, only managed-settings hooks are sent to the engine: non-managed settings can switch off their own hooks, never the managed ones, and a managed `disableAllHooks` is still judged first and sends nothing at all. A full matrix over the four sources, each true, false or absent, is merged with the reference rule (later sources override earlier ones, managed settings last) and every cell's projection is asserted. The reader is the only authority: per-source values never second-guess it, and only a strict `true` counts. A host that does not implement it keeps the previous behaviour and gets exactly one warning per installed settings port, never one per request, and none on paths where the reader would not have been consulted; a reader that throws is treated as `true`, so managed hooks still ship. The session goal's Stop hook and the final-verification yield rule, which reads the projected hooks, follow the same verdict, and the trust gate and the three managed gates are evaluated before the reader is ever called. The last leg pins the member's declared shape in the built declarations: optional, no parameters, returning a boolean or `undefined`. |
425
+ | `scripts/run-hooks-merged-disable-projection-test.mjs` | The fourth governance leg of the hooks projection: `disableAllHooks` set in a non-managed settings source. The value that counts is the **merged** one, read from the host through the optional `SettingsPort.mergedDisableAllHooks()`, because a per-source approximation ("any source says true") reads user `true` with local `false` backwards — the merged value there is `false` and every source's hooks ship. When the merged value is `true`, only managed-settings hooks are sent to the engine: non-managed settings can switch off their own hooks, never the managed ones, and a managed `disableAllHooks` is still judged first and sends nothing at all. A full matrix over the four sources, each true, false or absent, is merged with the reference rule (later sources override earlier ones, managed settings last) and every cell's projection is asserted. The reader is the only authority: per-source values never second-guess it, and only a strict `true` counts. A host that does not implement it keeps the previous behaviour and gets exactly one warning per installed settings port, never one per request, and none on paths where the reader would not have been consulted; a reader that throws is treated as `true`, so managed hooks still ship. The session goal's Stop hook and the final-verification yield rule, which reads the projected hooks, follow the same verdict, and the trust gate and the three managed gates are evaluated before the reader is ever called. The last leg pins the member's declared shape in the built declarations: optional, no parameters, returning a boolean or `undefined`. The flag settings source (a settings file or inline settings given at startup) is projected after the local source, and settings hooks stay concatenated managed first (managed → user → project → local → flag): the engine runs hooks in request order, and three of its budgets go to whoever comes first — the per-event wall-clock budget, the per-event cap on model-backed entries, and the total cap on added context — so a managed hook placed after the others could be crowded out and silently not run. The flag source moves with user, project and local under every managed or merged gate; its exec-form entries are dropped and warned about like any other settings source, and the not-run notice names it `Flag settings`. An optional leg feeds the request body to an installed server's hook runner and requires the managed deny, block and context to take effect while non-managed hooks exhaust each of those budgets, and pins the known cost of that order: a non-managed `PreToolUse` hook placed after the managed one can still rewrite the input after the managed check allowed it. Without an installed server the leg reports that it did not run. |
426
426
  | `scripts/run-memory-saved-projection-test.mjs` | Engine memory writes (a successful `Remember` tool call) moved off the transcript onto the additive `memory_saved` chrome event, driven through the real pipeline: zero transcript rows for the write (the transcript is byte-identical to the same frames with the write reported as not successful), exactly one event whose `notes` carry the note text verbatim (notes, not file paths) and whose key set is exactly kind / laneProof / id / notes; no event for a missing, empty or non-string note, a non-`true` `ok`, a tool error, a missing result or another tool name; two writes give two events in order with distinct ids; a sub-agent write rides the sub-agent lane and an empty parent id emits nothing rather than falling back to the main lane; the `id` is derived from the write's wire key (the tool-end event id, else the tool-start event id, else the call id; empty ids count as absent), so projecting the same wire events twice gives the same id, and it never collides with the tool result row of the same or another call; the event sits right after the tool result row; the arm is registered as required. |
427
427
  | `scripts/run-result-frame-projection-test.mjs` | Result frames and the synthesized terminal rows. The CC key `terminal_reason` is minted on result frames only where it follows from what the engine reported: `completed` on success, `max_turns`, `budget_exhausted` and `structured_output_retry_exhausted` for the three matching engine codes, on both the done-frame path and the failed-event path. Every other outcome leaves the key absent as an own property rather than present with an undefined value: wall-clock and token-budget limits, the classifier denial limit, cancellation, unknown codes, blocked, paused, unreadable or missing terminal records, and the busy-session refusal. The public reader `terminalReasonForResult` shares the minting predicate and is checked to agree with the minted key on every frame the gate produces. Both the minted key and the reader derive the word from the frame's CC subtype (success with `is_error` strictly false, and the three limit subtypes), not from the error code, so a replayed row whose status is paused, blocked or unrecognised never carries a word that contradicts its subtype. The four words are checked against the mirrored CC union, and the minting file is checked to hold no hand-copied code literals. The renamed superset keys (`_sema_error_code`, `_sema_salvaged_result`, `_sema_model_degraded`, `_sema_selected_model`, and the row flag `_sema_api_error_message`) are driven through the real stream pipeline. Each must be present under its new name, the old name must be absent, and every frame the gate saw is swept for old names. The selected model appears on error envelopes whenever the terminal record carries it, and never on a failed event, which has no record. It stays separate from the provider-reported model name. The two in-package readers still work: the interactive result arm reads the salvaged text under its new name (and old-shape frames under the old one), and the print init gate treats the renamed flag as the run having ended. |
428
428
  | `scripts/run-layering-shadow-export-test.mjs` | Same-name shadows across the first-party clients that consume this package (terminal, desktop, web and the admin console). Each client's product sources are read at the local clone's `origin/main` (or its HEAD when there is no such ref), without fetching, and parsed with the TypeScript parser; every top-level runtime export the client declares itself is compared with this package's public runtime exports. The guard prints which ref, commit and commit date it read for each client, and warns (without failing) when that commit is more than seven days old, because the result then only describes that older snapshot. A client-side declaration carrying the name of a package export means a piece of shared logic now lives in two places and can drift apart. It fails the guard unless it is listed in `scripts/layering-shadow-exemptions.json`, and a listed row must carry a retire-by version no more than three minor lines ahead (it fails once the package reaches it). It also fails once the client has removed the shadow and the row still stands. Re-exports of this package's own exports are the intended form and never count. A client tree that is not present is reported as a skipped section, not as a pass. The ruler proves itself on an in-memory fake client (planted shadows must be caught, legal forms must not), on a throwaway repository (a missing `origin/main` falls back to HEAD, a broken one is a fault rather than a silent fallback), and refuses to report zero on a client whose scan surface is empty. |
@@ -16,6 +16,7 @@ export interface RulesFacade {
16
16
  signal?: AbortSignal;
17
17
  }): Promise<CcImportRedeemResult>;
18
18
  }
19
+ export type RulesListFacade = Pick<RulesFacade, 'list'>;
19
20
  export declare function persistedRulesLaneAvailable(baseUrl: string | undefined): boolean;
20
21
  export declare function persistedRulesGovernanceAvailable(baseUrl: string | undefined): boolean;
21
22
  export declare function persistedRulesWriteAvailable(baseUrl: string | undefined): boolean;
@@ -90,7 +91,7 @@ export type ListAllPersistedRulesOutcome = {
90
91
  ok: false;
91
92
  failure: RulesFailure;
92
93
  };
93
- export declare function listAllPersistedRules(facade: RulesFacade, params?: Omit<RuleListParams, 'cursor'>, opts?: {
94
+ export declare function listAllPersistedRules(facade: RulesListFacade & Partial<Omit<RulesFacade, 'list'>>, params?: Omit<RuleListParams, 'cursor'>, opts?: {
94
95
  signal?: AbortSignal;
95
96
  }): Promise<ListAllPersistedRulesOutcome>;
96
97
  declare const DIRECT_WRITE_EXCLUDED_BEHAVIOR = "allow";
@@ -7,7 +7,7 @@ import { MAX_HOOK_NOTICE_TEXT_CHARS } from './notifications.js';
7
7
  import { goalStopHookMatcher, __resetGoalStopHookForTests } from './goalStopHook.js';
8
8
  export { GOAL_STOP_HOOK_WIRE_ENV, CC_STOP_SEMANTICS_MIN_SERVER, ccStopSemanticsFromVersion, engineCcStopSemantics, isGoalStopHookWireArmed, setWireSessionStopHook, getWireSessionStopHook, getWireSessionStopHookCcSemantics, buildGoalStopHookPrompt, } from './goalStopHook.js';
9
9
  const EDITABLE_HOOK_SOURCES = ['userSettings', 'projectSettings', 'localSettings'];
10
- const ALL_HOOK_SOURCES = ['policySettings', ...EDITABLE_HOOK_SOURCES];
10
+ const ALL_HOOK_SOURCES = ['policySettings', ...EDITABLE_HOOK_SOURCES, 'flagSettings'];
11
11
  const _hookSourceListsPin = [true, true];
12
12
  void _hookSourceListsPin;
13
13
  function hooksLockedToPluginOnly(policyValue) {
@@ -8,13 +8,14 @@ type ModelIdentityLaneTuple = readonly [
8
8
  export type ModelIdentityLane = ModelIdentityLaneTuple[number];
9
9
  export type ModelIdentityLaneReading = 'complete' | 'partial' | 'absent' | 'unreadable';
10
10
  export type ModelIdentityLanes = {
11
- [L in ModelIdentityLane]: L extends 'modelCatalogFile' ? Exclude<ModelIdentityLaneReading, 'complete'> : ModelIdentityLaneReading;
11
+ [L in ModelIdentityLane]: ModelIdentityLaneReading;
12
12
  };
13
13
  export type EngineAnswerObservation = 'answered' | 'not_observed' | 'unreachable';
14
14
  export interface LocalEngineModelIdentityReading {
15
15
  engine: 'local';
16
16
  lanes: ModelIdentityLanes;
17
17
  engineAnswer?: EngineAnswerObservation;
18
+ engineAcceptsCatalogDefault?: boolean;
18
19
  }
19
20
  export interface RemoteEngineModelIdentityReading {
20
21
  engine: 'remote';
@@ -19,11 +19,12 @@ function laneState(lanes, lane) {
19
19
  if (hit === undefined)
20
20
  return 'not_reported';
21
21
  const v = hit.v;
22
- const _catalogPin = true;
23
- void _catalogPin;
24
- if (v === 'complete')
25
- return lane === 'modelCatalogFile' ? 'unusable' : v;
26
- return v === 'partial' || v === 'absent' || v === 'unreadable' ? v : 'unusable';
22
+ return v === 'complete' || v === 'partial' || v === 'absent' || v === 'unreadable' ? v : 'unusable';
23
+ }
24
+ function catalogDefaultEvidence(catalog, accepts) {
25
+ const _evidencePin = true;
26
+ void _evidencePin;
27
+ return catalog === 'complete' && accepts === true ? { catalog, engineAccepts: accepts } : undefined;
27
28
  }
28
29
  function analyse(reading) {
29
30
  try {
@@ -40,16 +41,36 @@ function analyse(reading) {
40
41
  return malformed();
41
42
  const lanesHit = own(reading, 'lanes')?.v;
42
43
  const order = laneOrder();
43
- if (!isPlainObject(lanesHit))
44
- return { verdict: 'unknown', why: 'lanes', unreadable: [], unreported: [...order], unusable: [] };
44
+ if (!isPlainObject(lanesHit)) {
45
+ return { verdict: 'unknown', why: 'lanes', unreadable: [], unreported: [...order], unusable: [], catalogUnconfirmed: null, catalogRefused: false };
46
+ }
45
47
  const partial = [];
46
48
  const unreadable = [];
47
49
  const unreported = [];
48
50
  const unusable = [];
51
+ let catalogRefused = false;
52
+ let catalogUnconfirmed = null;
49
53
  for (const lane of order) {
50
54
  const s = laneState(lanesHit, lane);
51
- if (s === 'complete')
55
+ if (lane === 'modelCatalogFile') {
56
+ if (s === 'complete') {
57
+ const bit = own(reading, 'engineAcceptsCatalogDefault');
58
+ const evidence = catalogDefaultEvidence(s, bit?.v);
59
+ if (evidence !== undefined)
60
+ return { verdict: 'resolvable', why: 'catalog_default', evidence };
61
+ if (bit !== undefined && bit.v === false) {
62
+ partial.push(lane);
63
+ catalogRefused = true;
64
+ }
65
+ else {
66
+ catalogUnconfirmed = bit === undefined || bit.v === undefined ? 'not_reported' : 'unusable';
67
+ }
68
+ continue;
69
+ }
70
+ }
71
+ else if (s === 'complete') {
52
72
  return { verdict: 'resolvable', why: 'lane', lane };
73
+ }
53
74
  if (s === 'partial')
54
75
  partial.push(lane);
55
76
  else if (s === 'unreadable')
@@ -59,10 +80,10 @@ function analyse(reading) {
59
80
  else if (s === 'unusable')
60
81
  unusable.push(lane);
61
82
  }
62
- if (unreadable.length > 0 || unreported.length > 0 || unusable.length > 0) {
63
- return { verdict: 'unknown', why: 'lanes', unreadable, unreported, unusable };
83
+ if (unreadable.length > 0 || unreported.length > 0 || unusable.length > 0 || catalogUnconfirmed !== null) {
84
+ return { verdict: 'unknown', why: 'lanes', unreadable, unreported, unusable, catalogUnconfirmed, catalogRefused };
64
85
  }
65
- return { verdict: 'not_resolvable', partial };
86
+ return { verdict: 'not_resolvable', partial, catalogRefused };
66
87
  }
67
88
  catch {
68
89
  return malformed();
@@ -97,13 +118,25 @@ export function modelIdentityDetail(reading) {
97
118
  if (a.why === 'engine_answered') {
98
119
  return 'the engine is up and answering, and it does not start without a model name, so it has one — whether its gateway accepts that name is a separate check';
99
120
  }
121
+ if (a.why === 'catalog_default') {
122
+ return `${laneLabel('modelCatalogFile')} supplies a model name as its default, and the local engine accepts a catalog default in place of a startup model name, so it can start with it — whether its gateway accepts that name is a separate check`;
123
+ }
100
124
  return `${laneLabel(a.lane)} supplies a model name, so the local engine can start with it — whether its gateway accepts that name is a separate check`;
101
- case 'not_resolvable':
102
- if (a.partial.length > 0) {
103
- const labels = joinPhrases(a.partial.map(laneLabel));
104
- return `no model name is configured for the local engine — ${labels} ${a.partial.length > 1 ? 'carry' : 'carries'} part of a model configuration (such as a gateway address or a credential) but no model name, and the engine does not start without one`;
125
+ case 'not_resolvable': {
126
+ const others = a.catalogRefused ? a.partial.filter((l) => l !== 'modelCatalogFile') : a.partial;
127
+ const partialClause = others.length > 0
128
+ ? `${joinPhrases(others.map(laneLabel))} ${others.length > 1 ? 'carry' : 'carries'} part of a model configuration (such as a gateway address or a credential) but no model name`
129
+ : '';
130
+ if (a.catalogRefused) {
131
+ return (`no model name is configured for the local engine to start with — ${laneLabel('modelCatalogFile')} names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name` +
132
+ (partialClause !== '' ? `, and ${partialClause}` : '') +
133
+ ', and the engine does not start without one');
134
+ }
135
+ if (others.length > 0) {
136
+ return `no model name is configured for the local engine — ${partialClause}, and the engine does not start without one`;
105
137
  }
106
138
  return 'no model name is configured for the local engine — none of the places this client reads supplies one, and the engine does not start without it';
139
+ }
107
140
  case 'unknown':
108
141
  if (a.why === 'remote') {
109
142
  return a.answer === 'unreachable'
@@ -116,6 +149,15 @@ export function modelIdentityDetail(reading) {
116
149
  ...a.unreported.map((l) => `${laneLabel(l)} was not reported`),
117
150
  ...a.unusable.map((l) => `${laneLabel(l)} gave no usable reading`),
118
151
  ];
152
+ if (a.catalogUnconfirmed === 'not_reported') {
153
+ parts.push(`${laneLabel('modelCatalogFile')} names a default model, but whether the local engine accepts a catalog default in place of a startup model name was not reported`);
154
+ }
155
+ else if (a.catalogUnconfirmed === 'unusable') {
156
+ parts.push(`${laneLabel('modelCatalogFile')} names a default model, but the report of whether the local engine accepts a catalog default in place of a startup model name gave no usable reading`);
157
+ }
158
+ else if (a.catalogRefused) {
159
+ parts.push(`${laneLabel('modelCatalogFile')} names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name`);
160
+ }
119
161
  return `whether the local engine has a model name is unknown — ${joinPhrases(parts)}, and no other place this client reads provides one`;
120
162
  }
121
163
  return "this reading of the engine's model configuration could not be interpreted, so whether the engine has a model name is unknown";
@@ -10,7 +10,7 @@ export declare const PLUGIN_HOOK_EXCLUSION_REASONS: readonly ["workspace_untrust
10
10
  export type PluginHookExclusionReason = (typeof PLUGIN_HOOK_EXCLUSION_REASONS)[number];
11
11
  export declare const SETTINGS_HOOK_DROP_REASONS: readonly ["exec_form_unsupported", "mcp_tool_unsupported"];
12
12
  export type SettingsHookDropReason = (typeof SETTINGS_HOOK_DROP_REASONS)[number];
13
- export type HookSettingsSource = 'policySettings' | 'userSettings' | 'projectSettings' | 'localSettings';
13
+ export type HookSettingsSource = 'policySettings' | 'userSettings' | 'projectSettings' | 'localSettings' | 'flagSettings';
14
14
  export interface PluginHookKey {
15
15
  readonly pluginId: string;
16
16
  readonly pluginName: string;
@@ -332,6 +332,7 @@ const SOURCE_TEXT = {
332
332
  userSettings: 'User settings',
333
333
  projectSettings: 'Project settings',
334
334
  localSettings: 'Local settings',
335
+ flagSettings: 'Flag settings',
335
336
  };
336
337
  export function pluginHookReasonText(reason) {
337
338
  return REASON_TEXT[reason];
@@ -19,8 +19,8 @@
19
19
 
20
20
  | 项 | 值 | 真源 |
21
21
  |---|---|---|
22
- | 本包 | `@sema-agent/client-core` **0.83.2**(本批发布版 = **patch**:只增 —— 审批卡一族三件(常驻姿态下的放行谓词 `askSurvivesPosture`,三态、「不知道」不折成放行;卡上 `mandate` 六词闭集 + 读口 + 每词一句说明,通告码册 +2,开发依赖引擎 `~7.32.0`;停泊卡带出身词 `origin`;CC-193 / CC-195 / CC-196)与后台子代缺席行的判定、计数、sweep 豁免、回收与措辞单源(回收只在后台代理登记确认离场时;CC-194);公面类型 +13;peer sdk 地板 `>=11.3.0` 不动;根公面 1273;§102)。上一版 0.83.1 = **patch**:只增 + 行为订正 —— 展示层安全出口三端单源 `displayUntrusted`(凭据两网 ∘ 字符三网,选项按载体选;CC-112);本包合成的终局行正文与结果帧 `errors[]` 在铸点洗凭据(`errors[]` wire 可见,方向只会更安全)、交互车道合成行带上行类旗,回决备注与子代续跑收据多收双向 / 格式字符(CC-187 / CC-112);会话规则记录的无损判定 `sessionPolicyDeliverable` + 措辞单源 `sessionPolicyWithheldNotice` + 五词成因 `SESSION_POLICY_WITHHELD_WHY`(整批可送才送,首尾带空白的名字比宿主侧更严;CC-117);插件 hook 每轮计划 `hooksWirePlan` + `SettingsPort` 可选读口 `enabledPluginHooks` + `hooksForWire({ plan })`,逐条判「投给引擎 / 本客户端执行 / 如实不跑」、开机「不会执行」清单与 `/hooks` 标注措辞单源(投给引擎那一臂候引擎能力位 `taskSettings.pluginHooks`),设置来源的 `mcp_tool` 与 exec 形 hook 条目不再上请求体、手写的 `plugin` 键剥掉(CC-174);公面类型 +26;peer sdk 地板 `>=11.3.0` 不动;根公面 1254;§101)。上一版 0.83.0 = **minor**:行为面与型面都有 BREAKING —— CC 形消息 24 项按裁定 C-R103 退役名:结果帧 `degraded` / `errorCode` / `model` 与错误信封 `result` → `_sema_model_degraded` / `_sema_error_code` / `_sema_selected_model` / `_sema_salvaged_result`,合成终局行 `isApiErrorMessage` → `_sema_api_error_message`,工具结果记录删过渡名 `toolUseResult`,system 行 `attachedFiles` → `_sema_attached_files`、到达时戳 `timestamp` 与 `isMeta` 删,print 完成通知帧十三键平铺 `_sema_*`,记忆写入改走 chrome 臂 `memory_saved`(新型 `MemorySavedChromeEvent`,`CHROME_ARMS` required);本包只铸新名、端两名并读一版 + 结果帧 CC 键 `terminal_reason` 与读口 `terminalReasonForResult`(CC-175),错误信封知道就铸 `_sema_selected_model` + 转录 id 改 UUID 形(CC-147)+ `SettingsPort` 可选合并读口 `mergedDisableAllHooks`、用户层 `disableAllHooks` 在引擎腿上生效(CC-162)+ 退化审批卡三形拒收改写、`FsApprovalOutcome` 的 `failed` 臂 +可选位 `editRefused`(CC-135)+ 注入件自愈句整族重写 + 联网搜索旧三读口 `webSearchFromEnv` / `webSearchFromSettings` / `resolveWebSearch` 退出公面,`resolveLiveInitToolFace` 可选 `opts.webSearchStamped`(`LiveInitToolFaceOptions`),endpoint userinfo 律跟服务端 7.101.0(CC-184)+ 公面类型 −4(CC-171)+ 通告码册 69 → 71 与结构化卡白名单 +`read-inbox`(CC-186,开发依赖引擎 `~7.31.0`)+ 合成终局行 `uuid` 改 UUID 形;peer sdk 地板 `>=11.3.0` 不动;根公面 1238;§100)。上一版 0.82.7 = **patch**:只增不改 —— 每请求联网搜索配置的三态判决 `judgeWebSearchSettings` / `webSearchVerdictFromEnv` / `resolveWebSearchVerdict`(与 7.100.0 及以后 server 的受理判官同序同判,认不出的 provider 判形错、不再静默丢段;settings 段凭据注入回调 `apiKeyFor`)+ 措辞单源 `webSearchVerdictMessage`(不回显任何用户配的值)+ 调试日志用 `webSearchEndpointForDisplay`;旧三读口 `webSearchFromEnv` / `webSearchFromSettings` / `resolveWebSearch` 行为不变、标过渡期,0.83.0 删(CC-182);peer sdk 地板 `>=11.3.0` 不动;根公面 1240;§99)。上一版 0.82.6 = **patch**:只增不改 —— 停泊行上选「本会话允许」却没被记住时与活卡腿同句告知(回体 `rememberApplied: false`,或 server 以会话级放行专属拒绝码拒了 remember 后回退普通批准;其余失败一律未知不告知),回执 `DecideReceiptView` +1 可选位 `rememberApplied`(CC-181);决断落定后与桥重试臂的诊断留痕不再因宿主日志口抛错回流进决断;接入文档改口:server ≥7.100.0 上 park 行卡的 `requiresRealApproval` / `approvalIsMandated` 生效(CC-180,零代码改动);peer sdk 地板 `>=11.3.0` 不动;根公面 1235;§98)。上一版 0.82.5 = **patch**:只增不改 —— print 车道 init 帧工具面名册优先:流包装器 `withPrintInitFrame`(首选接法,init 恒为首行、其后按到达序)/ 判定闸 `createPrintInitGate` / 分类口 `printInitRosterSignal` / 判定口 `decidePrintInitToolFace` / 留痕措辞 `printInitToolFaceDebugLine` + 等待上界 `PRINT_INIT_ROSTER_WAIT_MS`(150 000);回落估计表补 `ListAgents`(7.30.0 及以后的引擎上与 `SendMessage` 同条件)(CC-169);peer sdk 地板 `>=11.3.0` 不动;根公面 1235;§97)。上一版 0.82.4 = **patch**:只增不改 —— park 行审批卡新增门类位 `irreversibleParkGate`(待决行门类恰为 irreversible_ask,今天即生效,门类事实不是保证);`requiresRealApproval` 在待决行顶层带时透传(就绪,待决列表带出后才生效,今天零行为变化)(CC-180);`ApprovalCardRequest` +1 可选位;peer sdk 地板 `>=11.3.0` 不动;根公面 1229;§96)。上一版 0.82.3 = **patch**:只增不改的公面 —— 自愈提示的「保住对话」出路槽 `keepSessionWayOut` 与交互面引擎决断入口开关 `engineDecidePath`(CC-177;两位都不给时措辞与 0.82.2 逐字节同);自愈结局两臂 +机读位 `pendingRowGone`(重开链证实待决项已不在);peer sdk 地板 `>=11.3.0` 不动;根公面 1229;§95)。上一版 0.82.2 = **patch**:只增不改的公面 + 若干行为订正 —— 新增措辞单源 `cloudEffectiveNotices`:云控制面有效配置回体的降级告警 / 预算 / 能力上限三读数(CC-164,四态,不读成 0 或「没有预算」);本机引擎 models 文档在宿主注入本机条目判定 `entryAccepted` 时补 `default` / `tierGroups` / `activeTierGroup`,剔掉会让本机整份拒收的目录引用与判定口不收的条目,去掉 registry 注记键 `origin` / `overridesTeam`(CC-165;结果新增 `modelRefIssues`);计划复核结局机读位 `_sema_planReviewOutcome`(CC-160 ①);停泊审批决断操作起止回调 `onDecideOperation` 与操作句柄 `openDecideOperation`(CC-160 ③);新增超集键 `_sema_planReviewOutcome`;peer sdk 地板 `>=11.3.0` 不动;根公面 1229;§94)。上一版 0.82.1 = **patch**:只增不改的公面 + 若干行为订正 —— 新增读口 15 个(续跑折叠码读口与措辞 / 文件历史捕获读口六口 / 模型身份可解析判据五口 / 自定义代理载荷作废重投口 / 决断失败码「门还在」判定)+ 宿主车道声明 `EmitContext.lane`;新增超集键 `_sema_response_model`(终帧 / 每轮用量)与 chrome 用量两臂 `responseModel`、重开判决 `_sema_decisionInFlight`、自愈结局两臂 `decisionInFlight`、内部臂 `_sema_denial_unclassified`、通知码 +1;行为订正:计划复核决断在飞不重开卡且自愈提示不再教人再决一次(CC-160 ②)、决断出口补折叠句且停泊腿不再把折叠 / 坏档误判已决(CC-154)、执行车道 `in-process` 措辞(CC-153)、`-p` 车道 Bash 良性退出与交互同判(CC-168)、`-p` 工具结果帧补结构化结果(CC-149)、被拒分类词两车道同判(CC-172)、非交互车道子代工具帧(CC-158,宿主声明车道才生效)、终帧被拒清单对账流内拒绝(CC-159)、自定义代理载荷作废重投(CC-161);peer sdk 地板 `>=11.3.0` 不动;根公面 1228;§93)。上一版 0.82.0 = **minor**:只增不改 —— 新增只读读口 17 个 + 1 常量、工具名册行一格 `mountedBy`、turn 错误判决 `http` 臂一格 `storedRowWhere`:`/rewind` 代码档与对话档能不能用由引擎能力位回答(CC-146)、云控制面额度读数三分(CC-150)、装配期「这一条腿有没有手」(CC-152)、续跑拒收按原码判(CC-154);两处既有面行为订正:自动模式分类器拒的类别词由 `permission-rule` 改为 `automode-*` 三词(CC-155,订正 0.81.1)、续跑上下文读不出时引擎点名的那一行不再丢(CC-156);0.81.0 预告的 23 键 + 1 子型删改**改到 0.83.0**(§92y ㉙);零 wire 键、零投影臂;peer sdk 地板 `>=11.3.0` 不动;§92。上一版 0.81.1 = **patch**:被拒分类词读器加第③路(CC-148):引擎「没问过就拒」的工具调用(deny 规则 / 权限模式 / hook / 分类器 / 写保护 —— 无 `settlement` 只有 `gate.disposition.deniedBy`)在 user 工具结果记录与终帧 `permission_denials[]` 上此前恒缺 `_sema_denial_kind` / `toolDenialKind`,现按层名落 `permission-rule`(其中「分类器」一项已由 0.82.0 CC-155 订正)(`ask_resolution` 无结算 / 结算段不成形 / 层名表外仍缺席不猜);交互与 `--print` 两条车道同一只读器;另钉终帧两臂 `_sema_effective_*` 键集不变量 —— 成功臂展开单铸函数、错误信封显式重发,覆盖性钉在返回对象自己的类型上(漏键 / 多键编译期即红)+ 门格判两臂键集相等且值逐字节同,给单铸函数加键时错误臂不会再静默少键(本版无键增减);零 wire 键、零投影臂、根公面 1195;§91。上一版 0.81.0 = **minor**:CC 形消息一张脸(C-R85 / CC-131):user 工具结果记录加 SDK 面键 `tool_use_result`(与过渡键 `toolUseResult` 同引用,删驼峰原定 0.82.0、已改到 0.83.0)+ DS-19 普查门升硬门(键集按语法解析、按 type/subtype 分表;23 键 + 1 子型过渡表到期窗原为 0.82.0、已改到 0.83.0,零常驻豁免)+ CC-145 `/rewind` both 臂改发 `restoreFiles:true`、`projectRewind(pending)` 单参;零 wire 键、零投影臂、根公面 1195;§90。上一版 0.80.2 = **patch**:`conflict.resume_context_unavailable` 的 `staleAfterSec` / `runId` 在真 SDK 上读不到(CC-137:sdk 11.1.0 起 `APIError` 把体上非具名键收进 `extra`,这一码映射成 `ConflictError` 无具名位,读口只读顶层 ⇒ 真调用链恒缺席)⇒ 体源结构位改「顶层有效值优先、`extra` 兜底」三只类型化读口单铸,有具名子类位的三处(`retryAfterSec` × 2 / `allowlist`)行为不变只多兜底,头源 `retryAfterMs` 只读具名位;零 wire 键、零投影臂、根公面 1195;§89。上一版 0.80.1 = **patch**:去键重发判据句按「铸」计(CC-143;§87「带键的体恰一次」作废 → 被铸恰一次,POST 几次随传输层)+ 接入文档段落自带射程限定词自 §88 起向前执法 + 模型预设表 deepseek 项改闭集真名 deepseek-flash(CC-144,C-R82 ①)+ 门里 git 兜底自陈探针(CC-142);零 wire 键、零投影臂、根公面 1195;§88。上一版 0.80.0 = **minor**:🔴 peer sdk 地板 >=11.2.1 → >=11.3.0 + 策略拒的归因上 wire(CC-133:发送面 deny+policy 带 settledBy / 读侧 policy_refused 十三词入 CC 规则桶 / 三错误码读口 / 直连门去键重发恰一次)+ 删除规则后果句归包(CC-132)+ /mcp 详情卡两腿分说归包(CC-134:六档读口 + 九句铸点,同批改口八处说满的话)+ 🔴 终帧旧拼法 `structuredOutput` 按 0.79.1 的宣告删除(只剩 CC 形 `structured_output`);根公面 1195;§87。上一版 0.79.1 = **patch**:终帧结构化产出同帧铸 CC 形 `structured_output`(旧拼法 `structuredOutput` 过渡一版,0.80.0 删;CC-130)+ 写审批 `argsOmitted` 退化卡在无受护写入部署形上重新解得出路径(CC-129)+ 云控制面十值二型经本包第二个入口 `@sema-agent/client-core/registry` 原样转口(根入口零变;CC-128 ①);根公面 1184;§86。上一版 0.79.0 = **minor**:server 7.93.0 过境批 —— peer sdk 地板 >=11.2.1 + 写口回执第六臂 unverified 与 503 体 committed 分臂(CC-124)+ 无 run 可读的 MCP 状态面(CC-74)+ 审批卡 mandated 位(CC-110)+ 请求装配第三车道 utility 与 approverPosture / maxTokens / outputRetries 三键 + print 车道 model 座(CC-116 / 118 / 123)+ 拒因两面分铸与四个机读位(CC-125)+ 模型轮边界划消息界(CC-126)+ 委派结果人类面读口按来源声明体内定位(CC-127)+ sdk 转口三件(CC-128)+ 通告码 memory.project_scope_absent(CC-122);公面 1184;§85。上一版 0.78.2 = **patch**:门的棘轮登记数字单真源 —— 五只门十一格棘轮 + 218 条沿革账搬进 scripts/registry.json、门只读不抄、负控改篡改登记物、下调通道 RATCHET-SLACK、新门 run-registry-test(CC-79 第一期)+ 两格存量松量收掉 + submit-wiring-manifest 门补 count===1 边界格;src 零改动,dist 逐字节同 0.78.1;公面 1154;§84。上一版 0.78.1 = **patch**:两辆并行车收货 + 三张跟进票 —— displayBody 人类面读口 + 围栏解析头尾配对收紧(CC-113)/ MCP 两处「没报」措辞分句(CC-115)/ 记忆治理面五动词调用口(CC-97 b)/ 非流式提交回执接线回执读口 readSubmitWiringManifest(CC-121)/ 三份失败判官抛出物读取收口(CC-119);公面 1154;§83。上一版 0.78.0 = **minor**:peer sdk 地板 >=9.8.1 → >=11.0.1(CC-106)+ 单步写口 200 体按 stillLive 判别联合改读、第五臂 revoked、三型取自 sdk、RulesFacade.write 必填、PersistedRuleLiveness 转口(CC-103)+ DeniedBy 第十词 read_boundary 专句(CC-106 ④)+ excludeAllTools 车道行;型面 BREAKING 三处、行为面同 0.77.2;公面 1143;§82。上一版 0.77.2 = **patch**:出包面结构卫生 —— 构建期 removeComments,dist js / d.ts 零注释(新门 run-dist-comments-test.mjs + 卫生门词表 32 条 + 文档向前执法;CC-100)+ gateDeniedByDetail 表外词兜底句改「本版不认识这个层名」(CC-111 ①);行为 / 型面逐字节同 0.77.1;公面 1143;§81。上一版 0.77.1 = **patch**:外部验收三件回填 —— 读器族边界残留 projectMcpReconnectCapability 只认自有键(CC-107)/ rewind 四子键恰读一次(CC-108)/ 子代输出合并按回体 output.type · retrieval_status 定处置(CC-109,server ≥7.92.0 cursorSemantics 缺席面);型面 additive 一处;公面 1143;§80。上一版 0.77.0 = **minor**:请求装配逐键去向回执 + print 车道补座 + 表外键响亮拒(CC-101,四条行为 BREAKING)/ 会话策略写端口(CC-105)/ 持久规则单步写面(CC-103)/ workflow 子代面板行代际三向恢复(CC-104,零改码)/ 能力位读器族口径整族改齐 + 外部验收 F-A / F-B 处置 + 合并树异源复审两轮处置;公面 1143;§79。上一版 0.76.2 = **patch**:制品卫生 —— 清 dist 重 build 去掉两只已撤出源码的编译产物 + dist ⇄ src 对账门;零源码 / 零型面 / 零行为改动;公面 1122;§78。上一版 0.76.1 = **patch**:能力位读器工厂(CC-75)/ MCP 活性观察读口(CC-36)/ `capabilities.peerLane` · `permissionRulesWrite` 四态读口(CC-102)/ 记忆治理面两只读口 + 三只条目面回体读口(CC-97 a)/ 主车道证明逐次新建(CC-99)+ 修 0.76.0 的 F1 / F2(身份四键一次性快照只修了投影口一侧);公面 1122;§77。上一版 0.76.0 = **minor**:六票一批 —— `prompt_assembled` 投影臂 / 审批 feed 三态(**型面 BREAKING**)/ `ApprovalResolution` 单源联合 / 记忆 spec 读口 / 终态词表上游钉 / `tasks_expand` 退役(**型面 BREAKING**),外加身份四键一次性快照(跨全部内部臂);公面 1081;§76。上一版 0.75.1 = **patch**:面板短命子代反序缓行放不出的残洞(外部复验 D1)+ 同代 running 帧三向定形(B4)+ #969 提货 `spawnName` 透传与 `agentType` 改读诚实来源(CC-95);§75。上一版 0.75.0 = **minor**:压缩的非 compacted 结局上 chrome 面 `compaction_outcome`(新内部臂 —— 自建 print 出口的端先表态)+ peer sdk 地板 `>=9.8.1`;型面 additive(ChromeEvent +1 臂)、公面 1065、零 wire 新键;§74。上一版 0.74.5 = **patch**:core 7.24.0 提货 `_sema_freed_tokens?` + 首见即终态的行零事件(幽灵完成行)+ `isNewEngineAgentPanelCycle` / `approvalOutcomeNoteOf` 上公面;型面 additive、公面 1065、peer 不动;§73。上一版 0.74.4 = **patch**:面板键「先发布的键为准」(tick 归不了一的三序不再两行)+ 前代 UUID 迟到 tick 丢弃 + `readRunCancelContext` 下钻收紧;型面 additive、公面 1061、peer 不动;§72。上一版 0.74.3 = **patch**:面板子代身份归一(tick / end 的 UUID 归到 fleet 尾段,宿主零改)+ run 记录 `cancelContext` 读口与成因四词 + workflow 行 `errorCode` + reopen 第二臂两件;型面纯 additive、公面 1061、peer 不动;§71。上一版 0.74.2 = **patch**:`capabilities.deviceExecutor.management` 四态读口(缺席 ≠ false;`deviceExecutor: false` = 车道缺席;管理动词可用性三态归包);公面 1052;§70。上一版 0.74.1 = **patch**:审批卡无决断收口 + 结局回交;§69。上一版 0.74.0 = **minor**:peer sdk 地板 >=9.7.1 + covers 过境 + 面板周期身份 + 离场读口;§68。上一版 0.73.5 = **patch**:workflow 规模告警判定上收进包(`evaluateWorkflowSize` 三态:未知的规模不当作规模正常;分母口径与帽优先级单源;env 读口纯函数);型面纯 additive、公面 1044、peer 不动;§67。上一版 0.73.4 = **patch**:终帧 `permission_denials` 第三键 ⇐ 同一条流 `tool_start` 入参按 `toolCallId` join(三道闸;join 不上留 sema 载体;🔴 更正 0.73.2「自动升级收口」一句)+ 审批 feed push 侧取件失败的欠账退避重试;型面纯 additive、公面 1033、peer 不动;§66。上一版 0.73.3 = **patch**:CC-61 sdk 9.7.1 提货 + `capabilities.approvalsStreamLive` 四态读口(缺席 = 判不出;`livePendingNeedsReconcile` 只在引擎明说会推时才让对账节拍降兜底)+ CC-60 五条模型面文案锚包侧半场(cursorSemantics 机读位 / result 行注记 / bash 首行两变体与良性槽 / 通知 seed 并集 / parked 臂);型面纯 additive、公面 1032、peer 不动;§65。上一版 0.73.2 = **patch**:CC-59 悬挂 ask 全卡 —— `livePending[].frame`(server ≥7.87.0)两道闸窄读进视图,在场即走流内帧腿同一条路(入参可见、改写可转发),缺席保持盲卡;CC-34 收口(引擎半场随 7.87.0 到货,判据交黑盒);型面纯 additive、公面 1026、peer 不动;§64。上一版 0.73.1 = **patch**:CC-57 `decidePlanReview` outcome 尾句按「决断有没有生效」四态选(单铸点 `planReviewOutcomeTail`;此前本地拒发仍让模型汇报已拒绝)+ CC-56 cancel 的 409 按机器码分家(`cancelConflictFromError` 三形 / 新安全码 `cancel_run_not_running`)与提交面 429 用量窗读口 + 人话;型面纯 additive、公面 1026、peer 不动;§63。上一版 0.73.0 = **minor,型面 BREAKING**:fleet 视图八个数值键改可选 —— CC-52 `FleetTaskView.elapsedMs` / `tokens` / `queuedCount` 与 `FleetWorkflowView.doneCount` / `totalCount` / `failedCount` / `tokens` / `elapsedMs` 不再 `?? 0`(有键 = 真值含真 0,缺键 = 不知道;逐键缺席语义见 §62b)+ 台账补偿链无基数不铸;公面导出名零增减 1019、零 wire 变化、peer 不动;§62。上一版 0.72.14 = **patch**:悬挂的流内 ask 拉半场 —— CC-55 `startApprovalsFeed` 快照加 `livePending` 段并进变化摘要(键缺席 = 未报,不铸空)+ 视图 / 去重账 / 与流内帧腿同链的决断口(入参不可见上卡明说、改写不转发)+ 宿主闸对账节拍 + 待决计数读口(不知道 = null);型面纯 additive、公面 1019、peer 不动;§61。上一版 0.72.13 = **patch**:server 7.86.0 提货 —— CC-46 plan_review `permissionModeAfter` 发口(三选卡双闸:宿主声明只读起步 ∧ 引擎 ≥7.86.0;400 field_conflict 两种处置)+ CC-54 `capabilities.executionLane` 四态读面(键缺席 ≠ 不是本机车道;`toolsRunHere` 判据归包)+ CC-53 detach 版本闸三态;型面 additive(另撤回 0.72.12 的主通道 `absent` 臂,改独立缺席订阅口)、公面 1011、peer 不动;§60;**预告 0.73.0 BREAKING**:fleet 视图数值键改可选。上一版 0.72.12 = **patch**:「缺席被折成正向终态」按类清剿 —— CC-50 M1 头条(fleet 行缺席改发 `absent` 不再铸 `end{isError:false}`)+ 六站一次改齐(缺席 ⇒ `unknown`)+ 结果边界 fail-closed 取舍 + `_sema_outcome` + `Outcome unknown:` 行 + CC-51 M6(default 臂不再谎报 running)+ 普查门 + DS-06;型面 additive、公面 993、peer 不动;行为面三处真变化见 CHANGELOG 取舍段;§59。上一版 0.72.11 = **patch**:core 7.23.0 提货 —— CC-49 通告码 66 → 67 `config.write_protection_unresolved`(operator;兄弟码 `target_view_absent` = 没有视图,这枚 = 有视图解析不出)+ `permission_denials` 自动升级腿通电(`gates[].toolCallId` ⇒ `tool_use_id`;CC-34 引擎半场);型面零变化、公面 989、peer 不动、devDep core ~7.23.0;§58。上一版 0.72.10 = **patch**:CC-41 leader run 终局 `needs_human` + `result.conflict` 三形读面(none 缺席不可分 / unreadable 在场读不懂 / conflict;`salvaged[]` 原样给落盘口;措辞单源不提重试);型面纯 additive、公面 989、peer 不动;§57。上一版 0.72.9 = **patch**:server 7.85.0 提货 —— CC-30 会话内 MCP re-dial 消费口(`reconnectMcpServer` 三态 / unsupported 恒五键 / 交易文案单源)+ CC-39② memory-status `autoConsolidationArmed` 三态 + CC-45 resume 补充句渲保留秒数;型面纯 additive、公面 985、peer 不动;§56。上一版 0.72.8 = **patch**:清账三票 —— `memory:"off"` 请求键(CC-39③,server 7.84.0 S-405)+ `runStream` 第二条中性臂 `Model output error:`(CC-43)+ 注入件撞活 run 自动 steer 零卡(CC-44);型面纯 additive、公面 977、peer 不动;§55。上一版 0.72.7 = **patch**:core 7.22.0 提货 —— 通告码 66 `mcp.server_redialed` + 读器 `readMcpServerRedialed` + `wiring_manifest.readDeny` 第九段 `_sema_readDeny`(缺席 = 没有内置行判这条腿);型面纯 additive、公面 971、peer 不动、devDep core ~7.22.0;§54。上一版 0.72.6 = **patch**:cli L-379 包侧半场 —— `steerFollowIntent` steer 后续听意图三态(tail / after-decision / after-wake)+ `activeRunSelfHealRow` 续听声明第五参;型面纯 additive、公面 969、peer 不动;§53。上一版 0.72.5 = **patch**:server 7.82.1 提货 —— `capabilities.webSearch.backend` 部署默认 WebSearch 后端四态读面(键缺席 = 老引擎判不了 ≠ `none`);型面纯 additive、公面 968、peer 不动;§52。上一版 0.72.4 = **patch**:core 7.21.x 三件经 server 7.82.0 提货 —— `wiring_manifest.autoConsolidation` 第八段 `_sema_autoConsolidation`(缺席 = indeterminate 不折 false);型面纯 additive、公面 962、peer 不动;§51。上一版 0.72.3 = **patch**:core #863 记忆单系统半场 ① —— `projectAgentsForWire` 投影 `agents[].memory`(user|project|local 三词同映射引擎平面 agent:<type>);型面纯 additive、公面 962、零 wire 新键、peer 不动;§50。上一版 0.72.2 = **patch**:workflow 视图两票 —— `LiveWorkflowController.resolution()` 六态(snapshot() 的 null 三义拆开)+ `noteOwnWorkflowRun` own 台账同拍登记;型面纯 additive、公面 961、零 wire 键、peer 不动;§49。上一版 0.72.1 = **patch**:server 7.80.1 提货 —— 409 `conflict.resume_context_unavailable` 结构读数(`staleAfterSec` / `runId`;sdk 9.6.0 尚未带键,经 sdk 今天恒缺席)+ `SkillSpec.baseDir`(只在本机车道带);型面纯 additive、公面 960、peer 不动;§48。上一版 0.72.0 = **minor**:型面 BREAKING —— 39 个零消费导出退出公面(CC-32 退役批,[7419] §45 预告 / cli [7422] 同意 / web-client·desktop 过节拍沉默 = 同意;名单见 §47a S-1);运行期零 BREAKING、公面 956、peer 不动、devDep core ~7.20.1;随批:已退役名账 `removed` + export-liveness 门 G 段 + 冻结账门 ⑧c;§47。上一版 0.71.4 = **patch**:core 7.20.1 提货 —— `ENGINE_NOTICE_CODES` 65 + `wiring_manifest.writeProtection` 第七段 `_sema_writeProtection`;型面纯 additive、公面 995、peer 不动、devDep core `~7.20.1`;§46。上一版 0.71.3 = **patch**:门体系清账批 —— CC-24 export-liveness 门 + 39 个导出退役预告(0.72.0 删,表态制)/ CC-26 `as unknown as` 铸链棘轮 / CC-25 冻结账门 ⑧ 段 / CC-06 B-081 包侧半场(终帧 `_sema_effective_reasoning` / `_sema_effective_memory_scopes` + resume reopen 族 + `routePairingVerdict`);型面纯 additive、公面 986 → 995、peer 不动;§45。上一版 0.71.2 = **patch**:接入方验收两票归包 —— CC-28 B-132 decide 拒体三句去内部车道词 / CC-29 B-133 committedUuids 唯一性(重复 ⇒ 形 f);零型面变化、公面 986、peer 不动;§44。上一版 0.71.1 = **patch**:接入档打回修正 —— CC-27 `ApprovalCardRequest.readRootCandidate?` 帧→卡透传位 + 新导出型 `ReadRootCandidateView`;型面纯 additive、公面 986 不变、peer 不动;§43。上一版 0.71.0 = **minor**:型面 BREAKING 六件 —— peer sdk 地板 >=9.6.0 + agent-types >=0.3.0 / `SkillsListingTruncatedFactsView` 删 `requestedBudgetBytes?`·`laneClamped?` / `WiringManifestMcpEntry` → `WiringManifestMcpEntryView` / `MAX_AGENT_SKILLS` 删 / `decide.workflow_host_not_parked` 退役;运行期零 BREAKING。内容:core 7.20.0 提货(闭集 +5 六十四码)/ 🔴 CC-16 `text_segment_end.committedUuids[]` / CC-08 全五件(tool_disclosure / tool_progress 两 chrome 臂、wiring_manifest tools·hooks·lsp 进切片、tool_roster_delta 接上、context_usage 进切片、`readRootCandidate` 镜像)/ CC-19 `mcpEngineLegPresence` 归包 / CC-20 not_parked clean-cut;公面 986;§42 / 42y 八条)|
23
- | peer:wire 契约 | `@sema-agent/sdk` **>=11.3.0**(value-level,非 type-only;**0.80.0 抬版**:11.3.0 在两条回决口体上声明 `settledBy?: "policy"`、`Settlement.kind` 第十三词 `policy_refused` 与三错误码;0.83.0 / 0.83.1 / 0.83.2 不动。此前 **0.79.0 曾抬到 >=11.2.1**:11.2.x 声明 `capabilities.mcpProbe`、`mcpCapabilities` / `probeMcp` + `McpProbeFace`、写回执第三支 `stillLive: "unknown"`,11.2.1 再补 `TaskRequest.approverPosture` 与审批帧键 `mandated`(型面 + 运行期键锚),本包按 11.2.1 编译,11.0.1 失去物料见证;**0.78.0 曾抬到 >=11.0.1**:11.x 声明 `DeniedBy` 第十词 `read_boundary`、`rules.write` 200 体按 `stillLive` 判别联合、`RemovalLiveness` / `RuleWriteRequest` / `RuleWriteResult` / `RuleWriteBehavior` 包根导出、`TaskRequest.excludeAllTools`,本包按 11.0.1 编译,9.8.1 失去物料见证;**0.75.0 曾抬到 >=9.8.1**:9.8.x 声明 `Capabilities.deviceExecutor.management?`,9.7.1 失去物料见证;**0.74.0 曾抬到 >=9.7.1**:9.7.x 追平的六处型面是本包 0.73.3 起的编译基线,且 9.6.0 失去物料见证;**0.71.0 曾抬到 >=9.6.0**:`tool_disclosure` / `tool_progress` 两帧型与 `ToolApprovalFrame.readRootCandidate` 自 9.6.0 起;0.69.0 曾抬到 >=9.4.0(`reasoning_end` / `lastLegMcp`),0.60.0 抬到 >=8.4.0;地板由 `scripts/run-sdk-floor-test.mjs` 的 `FLOOR` 与 public-surface 门 C-CC-3「不低于见证到的最低实装版」双钉)| `package.json` `peerDependencies` |
22
+ | 本包 | `@sema-agent/client-core` **0.83.3**(本批发布版 = **patch**:入参 / 来源面 —— hooks 投影加 flag 来源(`--settings` 那一层,排在 local 之后;设置来源 hooks 维持托管在前拼接);规则列举口 `listAllPersistedRules` 入参只要 `list`(`RulesListFacade`,其余四口作可选成员);模型身份认目录缺省(本机读数加宿主报位 `engineAcceptsCatalogDefault`,位 `true` 才算目录可解析);公面类型 +1;peer sdk 地板 `>=11.3.0` 不动;根公面 1273;§103)。上一版 0.83.2 = **patch**:只增 —— 审批卡一族三件(常驻姿态下的放行谓词 `askSurvivesPosture`,三态、「不知道」不折成放行;卡上 `mandate` 六词闭集 + 读口 + 每词一句说明,通告码册 +2,开发依赖引擎 `~7.32.0`;停泊卡带出身词 `origin`;CC-193 / CC-195 / CC-196)与后台子代缺席行的判定、计数、sweep 豁免、回收与措辞单源(回收只在后台代理登记确认离场时;CC-194);公面类型 +13;peer sdk 地板 `>=11.3.0` 不动;根公面 1273;§102)。上一版 0.83.1 = **patch**:只增 + 行为订正 —— 展示层安全出口三端单源 `displayUntrusted`(凭据两网 ∘ 字符三网,选项按载体选;CC-112);本包合成的终局行正文与结果帧 `errors[]` 在铸点洗凭据(`errors[]` wire 可见,方向只会更安全)、交互车道合成行带上行类旗,回决备注与子代续跑收据多收双向 / 格式字符(CC-187 / CC-112);会话规则记录的无损判定 `sessionPolicyDeliverable` + 措辞单源 `sessionPolicyWithheldNotice` + 五词成因 `SESSION_POLICY_WITHHELD_WHY`(整批可送才送,首尾带空白的名字比宿主侧更严;CC-117);插件 hook 每轮计划 `hooksWirePlan` + `SettingsPort` 可选读口 `enabledPluginHooks` + `hooksForWire({ plan })`,逐条判「投给引擎 / 本客户端执行 / 如实不跑」、开机「不会执行」清单与 `/hooks` 标注措辞单源(投给引擎那一臂候引擎能力位 `taskSettings.pluginHooks`),设置来源的 `mcp_tool` 与 exec 形 hook 条目不再上请求体、手写的 `plugin` 键剥掉(CC-174);公面类型 +26;peer sdk 地板 `>=11.3.0` 不动;根公面 1254;§101)。上一版 0.83.0 = **minor**:行为面与型面都有 BREAKING —— CC 形消息 24 项按裁定 C-R103 退役名:结果帧 `degraded` / `errorCode` / `model` 与错误信封 `result` → `_sema_model_degraded` / `_sema_error_code` / `_sema_selected_model` / `_sema_salvaged_result`,合成终局行 `isApiErrorMessage` → `_sema_api_error_message`,工具结果记录删过渡名 `toolUseResult`,system 行 `attachedFiles` → `_sema_attached_files`、到达时戳 `timestamp` 与 `isMeta` 删,print 完成通知帧十三键平铺 `_sema_*`,记忆写入改走 chrome 臂 `memory_saved`(新型 `MemorySavedChromeEvent`,`CHROME_ARMS` required);本包只铸新名、端两名并读一版 + 结果帧 CC 键 `terminal_reason` 与读口 `terminalReasonForResult`(CC-175),错误信封知道就铸 `_sema_selected_model` + 转录 id 改 UUID 形(CC-147)+ `SettingsPort` 可选合并读口 `mergedDisableAllHooks`、用户层 `disableAllHooks` 在引擎腿上生效(CC-162)+ 退化审批卡三形拒收改写、`FsApprovalOutcome` 的 `failed` 臂 +可选位 `editRefused`(CC-135)+ 注入件自愈句整族重写 + 联网搜索旧三读口 `webSearchFromEnv` / `webSearchFromSettings` / `resolveWebSearch` 退出公面,`resolveLiveInitToolFace` 可选 `opts.webSearchStamped`(`LiveInitToolFaceOptions`),endpoint userinfo 律跟服务端 7.101.0(CC-184)+ 公面类型 −4(CC-171)+ 通告码册 69 → 71 与结构化卡白名单 +`read-inbox`(CC-186,开发依赖引擎 `~7.31.0`)+ 合成终局行 `uuid` 改 UUID 形;peer sdk 地板 `>=11.3.0` 不动;根公面 1238;§100)。上一版 0.82.7 = **patch**:只增不改 —— 每请求联网搜索配置的三态判决 `judgeWebSearchSettings` / `webSearchVerdictFromEnv` / `resolveWebSearchVerdict`(与 7.100.0 及以后 server 的受理判官同序同判,认不出的 provider 判形错、不再静默丢段;settings 段凭据注入回调 `apiKeyFor`)+ 措辞单源 `webSearchVerdictMessage`(不回显任何用户配的值)+ 调试日志用 `webSearchEndpointForDisplay`;旧三读口 `webSearchFromEnv` / `webSearchFromSettings` / `resolveWebSearch` 行为不变、标过渡期,0.83.0 删(CC-182);peer sdk 地板 `>=11.3.0` 不动;根公面 1240;§99)。上一版 0.82.6 = **patch**:只增不改 —— 停泊行上选「本会话允许」却没被记住时与活卡腿同句告知(回体 `rememberApplied: false`,或 server 以会话级放行专属拒绝码拒了 remember 后回退普通批准;其余失败一律未知不告知),回执 `DecideReceiptView` +1 可选位 `rememberApplied`(CC-181);决断落定后与桥重试臂的诊断留痕不再因宿主日志口抛错回流进决断;接入文档改口:server ≥7.100.0 上 park 行卡的 `requiresRealApproval` / `approvalIsMandated` 生效(CC-180,零代码改动);peer sdk 地板 `>=11.3.0` 不动;根公面 1235;§98)。上一版 0.82.5 = **patch**:只增不改 —— print 车道 init 帧工具面名册优先:流包装器 `withPrintInitFrame`(首选接法,init 恒为首行、其后按到达序)/ 判定闸 `createPrintInitGate` / 分类口 `printInitRosterSignal` / 判定口 `decidePrintInitToolFace` / 留痕措辞 `printInitToolFaceDebugLine` + 等待上界 `PRINT_INIT_ROSTER_WAIT_MS`(150 000);回落估计表补 `ListAgents`(7.30.0 及以后的引擎上与 `SendMessage` 同条件)(CC-169);peer sdk 地板 `>=11.3.0` 不动;根公面 1235;§97)。上一版 0.82.4 = **patch**:只增不改 —— park 行审批卡新增门类位 `irreversibleParkGate`(待决行门类恰为 irreversible_ask,今天即生效,门类事实不是保证);`requiresRealApproval` 在待决行顶层带时透传(就绪,待决列表带出后才生效,今天零行为变化)(CC-180);`ApprovalCardRequest` +1 可选位;peer sdk 地板 `>=11.3.0` 不动;根公面 1229;§96)。上一版 0.82.3 = **patch**:只增不改的公面 —— 自愈提示的「保住对话」出路槽 `keepSessionWayOut` 与交互面引擎决断入口开关 `engineDecidePath`(CC-177;两位都不给时措辞与 0.82.2 逐字节同);自愈结局两臂 +机读位 `pendingRowGone`(重开链证实待决项已不在);peer sdk 地板 `>=11.3.0` 不动;根公面 1229;§95)。上一版 0.82.2 = **patch**:只增不改的公面 + 若干行为订正 —— 新增措辞单源 `cloudEffectiveNotices`:云控制面有效配置回体的降级告警 / 预算 / 能力上限三读数(CC-164,四态,不读成 0 或「没有预算」);本机引擎 models 文档在宿主注入本机条目判定 `entryAccepted` 时补 `default` / `tierGroups` / `activeTierGroup`,剔掉会让本机整份拒收的目录引用与判定口不收的条目,去掉 registry 注记键 `origin` / `overridesTeam`(CC-165;结果新增 `modelRefIssues`);计划复核结局机读位 `_sema_planReviewOutcome`(CC-160 ①);停泊审批决断操作起止回调 `onDecideOperation` 与操作句柄 `openDecideOperation`(CC-160 ③);新增超集键 `_sema_planReviewOutcome`;peer sdk 地板 `>=11.3.0` 不动;根公面 1229;§94)。上一版 0.82.1 = **patch**:只增不改的公面 + 若干行为订正 —— 新增读口 15 个(续跑折叠码读口与措辞 / 文件历史捕获读口六口 / 模型身份可解析判据五口 / 自定义代理载荷作废重投口 / 决断失败码「门还在」判定)+ 宿主车道声明 `EmitContext.lane`;新增超集键 `_sema_response_model`(终帧 / 每轮用量)与 chrome 用量两臂 `responseModel`、重开判决 `_sema_decisionInFlight`、自愈结局两臂 `decisionInFlight`、内部臂 `_sema_denial_unclassified`、通知码 +1;行为订正:计划复核决断在飞不重开卡且自愈提示不再教人再决一次(CC-160 ②)、决断出口补折叠句且停泊腿不再把折叠 / 坏档误判已决(CC-154)、执行车道 `in-process` 措辞(CC-153)、`-p` 车道 Bash 良性退出与交互同判(CC-168)、`-p` 工具结果帧补结构化结果(CC-149)、被拒分类词两车道同判(CC-172)、非交互车道子代工具帧(CC-158,宿主声明车道才生效)、终帧被拒清单对账流内拒绝(CC-159)、自定义代理载荷作废重投(CC-161);peer sdk 地板 `>=11.3.0` 不动;根公面 1228;§93)。上一版 0.82.0 = **minor**:只增不改 —— 新增只读读口 17 个 + 1 常量、工具名册行一格 `mountedBy`、turn 错误判决 `http` 臂一格 `storedRowWhere`:`/rewind` 代码档与对话档能不能用由引擎能力位回答(CC-146)、云控制面额度读数三分(CC-150)、装配期「这一条腿有没有手」(CC-152)、续跑拒收按原码判(CC-154);两处既有面行为订正:自动模式分类器拒的类别词由 `permission-rule` 改为 `automode-*` 三词(CC-155,订正 0.81.1)、续跑上下文读不出时引擎点名的那一行不再丢(CC-156);0.81.0 预告的 23 键 + 1 子型删改**改到 0.83.0**(§92y ㉙);零 wire 键、零投影臂;peer sdk 地板 `>=11.3.0` 不动;§92。上一版 0.81.1 = **patch**:被拒分类词读器加第③路(CC-148):引擎「没问过就拒」的工具调用(deny 规则 / 权限模式 / hook / 分类器 / 写保护 —— 无 `settlement` 只有 `gate.disposition.deniedBy`)在 user 工具结果记录与终帧 `permission_denials[]` 上此前恒缺 `_sema_denial_kind` / `toolDenialKind`,现按层名落 `permission-rule`(其中「分类器」一项已由 0.82.0 CC-155 订正)(`ask_resolution` 无结算 / 结算段不成形 / 层名表外仍缺席不猜);交互与 `--print` 两条车道同一只读器;另钉终帧两臂 `_sema_effective_*` 键集不变量 —— 成功臂展开单铸函数、错误信封显式重发,覆盖性钉在返回对象自己的类型上(漏键 / 多键编译期即红)+ 门格判两臂键集相等且值逐字节同,给单铸函数加键时错误臂不会再静默少键(本版无键增减);零 wire 键、零投影臂、根公面 1195;§91。上一版 0.81.0 = **minor**:CC 形消息一张脸(C-R85 / CC-131):user 工具结果记录加 SDK 面键 `tool_use_result`(与过渡键 `toolUseResult` 同引用,删驼峰原定 0.82.0、已改到 0.83.0)+ DS-19 普查门升硬门(键集按语法解析、按 type/subtype 分表;23 键 + 1 子型过渡表到期窗原为 0.82.0、已改到 0.83.0,零常驻豁免)+ CC-145 `/rewind` both 臂改发 `restoreFiles:true`、`projectRewind(pending)` 单参;零 wire 键、零投影臂、根公面 1195;§90。上一版 0.80.2 = **patch**:`conflict.resume_context_unavailable` 的 `staleAfterSec` / `runId` 在真 SDK 上读不到(CC-137:sdk 11.1.0 起 `APIError` 把体上非具名键收进 `extra`,这一码映射成 `ConflictError` 无具名位,读口只读顶层 ⇒ 真调用链恒缺席)⇒ 体源结构位改「顶层有效值优先、`extra` 兜底」三只类型化读口单铸,有具名子类位的三处(`retryAfterSec` × 2 / `allowlist`)行为不变只多兜底,头源 `retryAfterMs` 只读具名位;零 wire 键、零投影臂、根公面 1195;§89。上一版 0.80.1 = **patch**:去键重发判据句按「铸」计(CC-143;§87「带键的体恰一次」作废 → 被铸恰一次,POST 几次随传输层)+ 接入文档段落自带射程限定词自 §88 起向前执法 + 模型预设表 deepseek 项改闭集真名 deepseek-flash(CC-144,C-R82 ①)+ 门里 git 兜底自陈探针(CC-142);零 wire 键、零投影臂、根公面 1195;§88。上一版 0.80.0 = **minor**:🔴 peer sdk 地板 >=11.2.1 → >=11.3.0 + 策略拒的归因上 wire(CC-133:发送面 deny+policy 带 settledBy / 读侧 policy_refused 十三词入 CC 规则桶 / 三错误码读口 / 直连门去键重发恰一次)+ 删除规则后果句归包(CC-132)+ /mcp 详情卡两腿分说归包(CC-134:六档读口 + 九句铸点,同批改口八处说满的话)+ 🔴 终帧旧拼法 `structuredOutput` 按 0.79.1 的宣告删除(只剩 CC 形 `structured_output`);根公面 1195;§87。上一版 0.79.1 = **patch**:终帧结构化产出同帧铸 CC 形 `structured_output`(旧拼法 `structuredOutput` 过渡一版,0.80.0 删;CC-130)+ 写审批 `argsOmitted` 退化卡在无受护写入部署形上重新解得出路径(CC-129)+ 云控制面十值二型经本包第二个入口 `@sema-agent/client-core/registry` 原样转口(根入口零变;CC-128 ①);根公面 1184;§86。上一版 0.79.0 = **minor**:server 7.93.0 过境批 —— peer sdk 地板 >=11.2.1 + 写口回执第六臂 unverified 与 503 体 committed 分臂(CC-124)+ 无 run 可读的 MCP 状态面(CC-74)+ 审批卡 mandated 位(CC-110)+ 请求装配第三车道 utility 与 approverPosture / maxTokens / outputRetries 三键 + print 车道 model 座(CC-116 / 118 / 123)+ 拒因两面分铸与四个机读位(CC-125)+ 模型轮边界划消息界(CC-126)+ 委派结果人类面读口按来源声明体内定位(CC-127)+ sdk 转口三件(CC-128)+ 通告码 memory.project_scope_absent(CC-122);公面 1184;§85。上一版 0.78.2 = **patch**:门的棘轮登记数字单真源 —— 五只门十一格棘轮 + 218 条沿革账搬进 scripts/registry.json、门只读不抄、负控改篡改登记物、下调通道 RATCHET-SLACK、新门 run-registry-test(CC-79 第一期)+ 两格存量松量收掉 + submit-wiring-manifest 门补 count===1 边界格;src 零改动,dist 逐字节同 0.78.1;公面 1154;§84。上一版 0.78.1 = **patch**:两辆并行车收货 + 三张跟进票 —— displayBody 人类面读口 + 围栏解析头尾配对收紧(CC-113)/ MCP 两处「没报」措辞分句(CC-115)/ 记忆治理面五动词调用口(CC-97 b)/ 非流式提交回执接线回执读口 readSubmitWiringManifest(CC-121)/ 三份失败判官抛出物读取收口(CC-119);公面 1154;§83。上一版 0.78.0 = **minor**:peer sdk 地板 >=9.8.1 → >=11.0.1(CC-106)+ 单步写口 200 体按 stillLive 判别联合改读、第五臂 revoked、三型取自 sdk、RulesFacade.write 必填、PersistedRuleLiveness 转口(CC-103)+ DeniedBy 第十词 read_boundary 专句(CC-106 ④)+ excludeAllTools 车道行;型面 BREAKING 三处、行为面同 0.77.2;公面 1143;§82。上一版 0.77.2 = **patch**:出包面结构卫生 —— 构建期 removeComments,dist js / d.ts 零注释(新门 run-dist-comments-test.mjs + 卫生门词表 32 条 + 文档向前执法;CC-100)+ gateDeniedByDetail 表外词兜底句改「本版不认识这个层名」(CC-111 ①);行为 / 型面逐字节同 0.77.1;公面 1143;§81。上一版 0.77.1 = **patch**:外部验收三件回填 —— 读器族边界残留 projectMcpReconnectCapability 只认自有键(CC-107)/ rewind 四子键恰读一次(CC-108)/ 子代输出合并按回体 output.type · retrieval_status 定处置(CC-109,server ≥7.92.0 cursorSemantics 缺席面);型面 additive 一处;公面 1143;§80。上一版 0.77.0 = **minor**:请求装配逐键去向回执 + print 车道补座 + 表外键响亮拒(CC-101,四条行为 BREAKING)/ 会话策略写端口(CC-105)/ 持久规则单步写面(CC-103)/ workflow 子代面板行代际三向恢复(CC-104,零改码)/ 能力位读器族口径整族改齐 + 外部验收 F-A / F-B 处置 + 合并树异源复审两轮处置;公面 1143;§79。上一版 0.76.2 = **patch**:制品卫生 —— 清 dist 重 build 去掉两只已撤出源码的编译产物 + dist ⇄ src 对账门;零源码 / 零型面 / 零行为改动;公面 1122;§78。上一版 0.76.1 = **patch**:能力位读器工厂(CC-75)/ MCP 活性观察读口(CC-36)/ `capabilities.peerLane` · `permissionRulesWrite` 四态读口(CC-102)/ 记忆治理面两只读口 + 三只条目面回体读口(CC-97 a)/ 主车道证明逐次新建(CC-99)+ 修 0.76.0 的 F1 / F2(身份四键一次性快照只修了投影口一侧);公面 1122;§77。上一版 0.76.0 = **minor**:六票一批 —— `prompt_assembled` 投影臂 / 审批 feed 三态(**型面 BREAKING**)/ `ApprovalResolution` 单源联合 / 记忆 spec 读口 / 终态词表上游钉 / `tasks_expand` 退役(**型面 BREAKING**),外加身份四键一次性快照(跨全部内部臂);公面 1081;§76。上一版 0.75.1 = **patch**:面板短命子代反序缓行放不出的残洞(外部复验 D1)+ 同代 running 帧三向定形(B4)+ #969 提货 `spawnName` 透传与 `agentType` 改读诚实来源(CC-95);§75。上一版 0.75.0 = **minor**:压缩的非 compacted 结局上 chrome 面 `compaction_outcome`(新内部臂 —— 自建 print 出口的端先表态)+ peer sdk 地板 `>=9.8.1`;型面 additive(ChromeEvent +1 臂)、公面 1065、零 wire 新键;§74。上一版 0.74.5 = **patch**:core 7.24.0 提货 `_sema_freed_tokens?` + 首见即终态的行零事件(幽灵完成行)+ `isNewEngineAgentPanelCycle` / `approvalOutcomeNoteOf` 上公面;型面 additive、公面 1065、peer 不动;§73。上一版 0.74.4 = **patch**:面板键「先发布的键为准」(tick 归不了一的三序不再两行)+ 前代 UUID 迟到 tick 丢弃 + `readRunCancelContext` 下钻收紧;型面 additive、公面 1061、peer 不动;§72。上一版 0.74.3 = **patch**:面板子代身份归一(tick / end 的 UUID 归到 fleet 尾段,宿主零改)+ run 记录 `cancelContext` 读口与成因四词 + workflow 行 `errorCode` + reopen 第二臂两件;型面纯 additive、公面 1061、peer 不动;§71。上一版 0.74.2 = **patch**:`capabilities.deviceExecutor.management` 四态读口(缺席 ≠ false;`deviceExecutor: false` = 车道缺席;管理动词可用性三态归包);公面 1052;§70。上一版 0.74.1 = **patch**:审批卡无决断收口 + 结局回交;§69。上一版 0.74.0 = **minor**:peer sdk 地板 >=9.7.1 + covers 过境 + 面板周期身份 + 离场读口;§68。上一版 0.73.5 = **patch**:workflow 规模告警判定上收进包(`evaluateWorkflowSize` 三态:未知的规模不当作规模正常;分母口径与帽优先级单源;env 读口纯函数);型面纯 additive、公面 1044、peer 不动;§67。上一版 0.73.4 = **patch**:终帧 `permission_denials` 第三键 ⇐ 同一条流 `tool_start` 入参按 `toolCallId` join(三道闸;join 不上留 sema 载体;🔴 更正 0.73.2「自动升级收口」一句)+ 审批 feed push 侧取件失败的欠账退避重试;型面纯 additive、公面 1033、peer 不动;§66。上一版 0.73.3 = **patch**:CC-61 sdk 9.7.1 提货 + `capabilities.approvalsStreamLive` 四态读口(缺席 = 判不出;`livePendingNeedsReconcile` 只在引擎明说会推时才让对账节拍降兜底)+ CC-60 五条模型面文案锚包侧半场(cursorSemantics 机读位 / result 行注记 / bash 首行两变体与良性槽 / 通知 seed 并集 / parked 臂);型面纯 additive、公面 1032、peer 不动;§65。上一版 0.73.2 = **patch**:CC-59 悬挂 ask 全卡 —— `livePending[].frame`(server ≥7.87.0)两道闸窄读进视图,在场即走流内帧腿同一条路(入参可见、改写可转发),缺席保持盲卡;CC-34 收口(引擎半场随 7.87.0 到货,判据交黑盒);型面纯 additive、公面 1026、peer 不动;§64。上一版 0.73.1 = **patch**:CC-57 `decidePlanReview` outcome 尾句按「决断有没有生效」四态选(单铸点 `planReviewOutcomeTail`;此前本地拒发仍让模型汇报已拒绝)+ CC-56 cancel 的 409 按机器码分家(`cancelConflictFromError` 三形 / 新安全码 `cancel_run_not_running`)与提交面 429 用量窗读口 + 人话;型面纯 additive、公面 1026、peer 不动;§63。上一版 0.73.0 = **minor,型面 BREAKING**:fleet 视图八个数值键改可选 —— CC-52 `FleetTaskView.elapsedMs` / `tokens` / `queuedCount` 与 `FleetWorkflowView.doneCount` / `totalCount` / `failedCount` / `tokens` / `elapsedMs` 不再 `?? 0`(有键 = 真值含真 0,缺键 = 不知道;逐键缺席语义见 §62b)+ 台账补偿链无基数不铸;公面导出名零增减 1019、零 wire 变化、peer 不动;§62。上一版 0.72.14 = **patch**:悬挂的流内 ask 拉半场 —— CC-55 `startApprovalsFeed` 快照加 `livePending` 段并进变化摘要(键缺席 = 未报,不铸空)+ 视图 / 去重账 / 与流内帧腿同链的决断口(入参不可见上卡明说、改写不转发)+ 宿主闸对账节拍 + 待决计数读口(不知道 = null);型面纯 additive、公面 1019、peer 不动;§61。上一版 0.72.13 = **patch**:server 7.86.0 提货 —— CC-46 plan_review `permissionModeAfter` 发口(三选卡双闸:宿主声明只读起步 ∧ 引擎 ≥7.86.0;400 field_conflict 两种处置)+ CC-54 `capabilities.executionLane` 四态读面(键缺席 ≠ 不是本机车道;`toolsRunHere` 判据归包)+ CC-53 detach 版本闸三态;型面 additive(另撤回 0.72.12 的主通道 `absent` 臂,改独立缺席订阅口)、公面 1011、peer 不动;§60;**预告 0.73.0 BREAKING**:fleet 视图数值键改可选。上一版 0.72.12 = **patch**:「缺席被折成正向终态」按类清剿 —— CC-50 M1 头条(fleet 行缺席改发 `absent` 不再铸 `end{isError:false}`)+ 六站一次改齐(缺席 ⇒ `unknown`)+ 结果边界 fail-closed 取舍 + `_sema_outcome` + `Outcome unknown:` 行 + CC-51 M6(default 臂不再谎报 running)+ 普查门 + DS-06;型面 additive、公面 993、peer 不动;行为面三处真变化见 CHANGELOG 取舍段;§59。上一版 0.72.11 = **patch**:core 7.23.0 提货 —— CC-49 通告码 66 → 67 `config.write_protection_unresolved`(operator;兄弟码 `target_view_absent` = 没有视图,这枚 = 有视图解析不出)+ `permission_denials` 自动升级腿通电(`gates[].toolCallId` ⇒ `tool_use_id`;CC-34 引擎半场);型面零变化、公面 989、peer 不动、devDep core ~7.23.0;§58。上一版 0.72.10 = **patch**:CC-41 leader run 终局 `needs_human` + `result.conflict` 三形读面(none 缺席不可分 / unreadable 在场读不懂 / conflict;`salvaged[]` 原样给落盘口;措辞单源不提重试);型面纯 additive、公面 989、peer 不动;§57。上一版 0.72.9 = **patch**:server 7.85.0 提货 —— CC-30 会话内 MCP re-dial 消费口(`reconnectMcpServer` 三态 / unsupported 恒五键 / 交易文案单源)+ CC-39② memory-status `autoConsolidationArmed` 三态 + CC-45 resume 补充句渲保留秒数;型面纯 additive、公面 985、peer 不动;§56。上一版 0.72.8 = **patch**:清账三票 —— `memory:"off"` 请求键(CC-39③,server 7.84.0 S-405)+ `runStream` 第二条中性臂 `Model output error:`(CC-43)+ 注入件撞活 run 自动 steer 零卡(CC-44);型面纯 additive、公面 977、peer 不动;§55。上一版 0.72.7 = **patch**:core 7.22.0 提货 —— 通告码 66 `mcp.server_redialed` + 读器 `readMcpServerRedialed` + `wiring_manifest.readDeny` 第九段 `_sema_readDeny`(缺席 = 没有内置行判这条腿);型面纯 additive、公面 971、peer 不动、devDep core ~7.22.0;§54。上一版 0.72.6 = **patch**:cli L-379 包侧半场 —— `steerFollowIntent` steer 后续听意图三态(tail / after-decision / after-wake)+ `activeRunSelfHealRow` 续听声明第五参;型面纯 additive、公面 969、peer 不动;§53。上一版 0.72.5 = **patch**:server 7.82.1 提货 —— `capabilities.webSearch.backend` 部署默认 WebSearch 后端四态读面(键缺席 = 老引擎判不了 ≠ `none`);型面纯 additive、公面 968、peer 不动;§52。上一版 0.72.4 = **patch**:core 7.21.x 三件经 server 7.82.0 提货 —— `wiring_manifest.autoConsolidation` 第八段 `_sema_autoConsolidation`(缺席 = indeterminate 不折 false);型面纯 additive、公面 962、peer 不动;§51。上一版 0.72.3 = **patch**:core #863 记忆单系统半场 ① —— `projectAgentsForWire` 投影 `agents[].memory`(user|project|local 三词同映射引擎平面 agent:<type>);型面纯 additive、公面 962、零 wire 新键、peer 不动;§50。上一版 0.72.2 = **patch**:workflow 视图两票 —— `LiveWorkflowController.resolution()` 六态(snapshot() 的 null 三义拆开)+ `noteOwnWorkflowRun` own 台账同拍登记;型面纯 additive、公面 961、零 wire 键、peer 不动;§49。上一版 0.72.1 = **patch**:server 7.80.1 提货 —— 409 `conflict.resume_context_unavailable` 结构读数(`staleAfterSec` / `runId`;sdk 9.6.0 尚未带键,经 sdk 今天恒缺席)+ `SkillSpec.baseDir`(只在本机车道带);型面纯 additive、公面 960、peer 不动;§48。上一版 0.72.0 = **minor**:型面 BREAKING —— 39 个零消费导出退出公面(CC-32 退役批,[7419] §45 预告 / cli [7422] 同意 / web-client·desktop 过节拍沉默 = 同意;名单见 §47a S-1);运行期零 BREAKING、公面 956、peer 不动、devDep core ~7.20.1;随批:已退役名账 `removed` + export-liveness 门 G 段 + 冻结账门 ⑧c;§47。上一版 0.71.4 = **patch**:core 7.20.1 提货 —— `ENGINE_NOTICE_CODES` 65 + `wiring_manifest.writeProtection` 第七段 `_sema_writeProtection`;型面纯 additive、公面 995、peer 不动、devDep core `~7.20.1`;§46。上一版 0.71.3 = **patch**:门体系清账批 —— CC-24 export-liveness 门 + 39 个导出退役预告(0.72.0 删,表态制)/ CC-26 `as unknown as` 铸链棘轮 / CC-25 冻结账门 ⑧ 段 / CC-06 B-081 包侧半场(终帧 `_sema_effective_reasoning` / `_sema_effective_memory_scopes` + resume reopen 族 + `routePairingVerdict`);型面纯 additive、公面 986 → 995、peer 不动;§45。上一版 0.71.2 = **patch**:接入方验收两票归包 —— CC-28 B-132 decide 拒体三句去内部车道词 / CC-29 B-133 committedUuids 唯一性(重复 ⇒ 形 f);零型面变化、公面 986、peer 不动;§44。上一版 0.71.1 = **patch**:接入档打回修正 —— CC-27 `ApprovalCardRequest.readRootCandidate?` 帧→卡透传位 + 新导出型 `ReadRootCandidateView`;型面纯 additive、公面 986 不变、peer 不动;§43。上一版 0.71.0 = **minor**:型面 BREAKING 六件 —— peer sdk 地板 >=9.6.0 + agent-types >=0.3.0 / `SkillsListingTruncatedFactsView` 删 `requestedBudgetBytes?`·`laneClamped?` / `WiringManifestMcpEntry` → `WiringManifestMcpEntryView` / `MAX_AGENT_SKILLS` 删 / `decide.workflow_host_not_parked` 退役;运行期零 BREAKING。内容:core 7.20.0 提货(闭集 +5 六十四码)/ 🔴 CC-16 `text_segment_end.committedUuids[]` / CC-08 全五件(tool_disclosure / tool_progress 两 chrome 臂、wiring_manifest tools·hooks·lsp 进切片、tool_roster_delta 接上、context_usage 进切片、`readRootCandidate` 镜像)/ CC-19 `mcpEngineLegPresence` 归包 / CC-20 not_parked clean-cut;公面 986;§42 / 42y 八条)|
23
+ | peer:wire 契约 | `@sema-agent/sdk` **>=11.3.0**(value-level,非 type-only;**0.80.0 抬版**:11.3.0 在两条回决口体上声明 `settledBy?: "policy"`、`Settlement.kind` 第十三词 `policy_refused` 与三错误码;0.83.0 / 0.83.1 / 0.83.2 / 0.83.3 不动。此前 **0.79.0 曾抬到 >=11.2.1**:11.2.x 声明 `capabilities.mcpProbe`、`mcpCapabilities` / `probeMcp` + `McpProbeFace`、写回执第三支 `stillLive: "unknown"`,11.2.1 再补 `TaskRequest.approverPosture` 与审批帧键 `mandated`(型面 + 运行期键锚),本包按 11.2.1 编译,11.0.1 失去物料见证;**0.78.0 曾抬到 >=11.0.1**:11.x 声明 `DeniedBy` 第十词 `read_boundary`、`rules.write` 200 体按 `stillLive` 判别联合、`RemovalLiveness` / `RuleWriteRequest` / `RuleWriteResult` / `RuleWriteBehavior` 包根导出、`TaskRequest.excludeAllTools`,本包按 11.0.1 编译,9.8.1 失去物料见证;**0.75.0 曾抬到 >=9.8.1**:9.8.x 声明 `Capabilities.deviceExecutor.management?`,9.7.1 失去物料见证;**0.74.0 曾抬到 >=9.7.1**:9.7.x 追平的六处型面是本包 0.73.3 起的编译基线,且 9.6.0 失去物料见证;**0.71.0 曾抬到 >=9.6.0**:`tool_disclosure` / `tool_progress` 两帧型与 `ToolApprovalFrame.readRootCandidate` 自 9.6.0 起;0.69.0 曾抬到 >=9.4.0(`reasoning_end` / `lastLegMcp`),0.60.0 抬到 >=8.4.0;地板由 `scripts/run-sdk-floor-test.mjs` 的 `FLOOR` 与 public-surface 门 C-CC-3「不低于见证到的最低实装版」双钉)| `package.json` `peerDependencies` |
24
24
  | peer:会话词汇表 | `@sema-agent/agent-types` **>=0.3.0**(type-only,零运行时;0.71.0 抬版:devDep 与 peer 同步,type-superset 门 ④ 撞名预警对着 0.3.0 的 .d.ts 求值) | 同上 |
25
25
  | runtime dep | `diff` ^9.0.0(**唯一**一条;portability 门按**等值**钉死) | `package.json` `dependencies` |
26
26
  | 公开导出面 | **1273** 个运行期符号(+ **59 个测试钩,两种拼法**:35 个 `__*ForTests` + 24 个单下划线开头(22 个 `_*ForTest` + `_resetLiveQuestionStore` / `_resetUltracodePreset`) —— 两种都在 `public-export-baseline.json` 的 `testHookNames` 里、各自受棘轮管,**不在** `names` 的 1273 里。运行期 `Object.keys(dist/index.js)` 的全量 = 1273 + 59 = **1332**;只剔双下划线那 35 个会多数出 24 个来,那不是棘轮盲区;最简单的剔法是去掉所有以 `_` 开头的名字(公面运行期名没有一个以 `_` 开头);= 下一版(未发布)的值:相对 0.75.1 **+16**,两票合计 —— **CC-77 ①** 审批决断结局单源判别联合 6 件:`approvalResolutionOf` / `isApprovalDecided` / `approvalNotSentCause` / `approvalUnsettledCause` + 两张 cause 词表 `APPROVAL_NOT_SENT_CAUSES` / `APPROVAL_UNSETTLED_CAUSES`(域 3);**CC-96** 记忆 spec 读面 10 件:`readAgentMemorySpec` / `unknownMemorySpecKeys` / `unknownMemorySpecKeysNote` / `memoryConfigRefusalNoteOf` / `KNOWN_AGENT_MEMORY_SPEC_KEYS` / `PENDING_MEMORY_SPEC_KEYS` / `MAX_UNKNOWN_MEMORY_SPEC_KEYS` / `CONFIG_MEMORY_PROJECT_KEY_SPELLING` / `CONFIG_MEMORY_WRITE_SCOPE_MISMATCH` + 判别形型(域 6 / 16)。CC-89 / CC-91 / CC-92 / CC-98 四票**零值导出增减**(新臂走 `ChromeEvent` 联合与内部臂表,`tasks_expand` 退役删的是联合成员不是导出名);1065 = 0.74.5 / 0.75.0 / 0.75.1 的值:相对 0.74.4 +4 —— `isNewEngineAgentPanelCycle`(CC-87,域 4)+ `approvalOutcomeNoteOf` 与两句固定文案常量(CC-88,域 3);1065 = 0.74.5 / 0.75.0 的值:相对 0.74.4 +4 —— `isNewEngineAgentPanelCycle`(CC-87,域 4)+ `approvalOutcomeNoteOf` 与两句固定文案常量(CC-88,域 3);1061 = 0.74.3 / 0.74.4 的值:相对 0.74.2 +9 —— CC-70 / CC-71 / CC-72 / CC-73 八件 + CC-80 `lastFlagValue`,见 §2b 域 3 / 4 / 10 / 15;1052 = 0.74.2 的值:相对 0.74.1 +6 —— CC-69 六件,见 §2b 域 9;1046 = 0.74.1 的值:相对 0.74.0 +1 —— `RETRACTED_CARD_DECISION_KIND`,见 §2b 域 3;1045 = 0.74.0 的值:相对 0.73.5 +1 —— `isStaleEngineAgentPanelEnd`,见 §2b 域 4;1044 = 0.73.5 的值:相对 0.73.4 +11 —— CC-58 规模告警十一件,名单见 §2b 域 12;1033 = 0.73.4 的值:相对 0.73.3 +1 —— `TOOL_INPUT_JOIN_MAX_CALLS`,见 §2b 域 1;1032 = 0.73.3 的值:相对 0.73.2 +6 —— CC-61 六件,名单见 §2b 域 9;1026 = 0.73.2 的值(导出名零增减);= 0.73.1 的值:相对 0.73.0 +7 —— CC-56 六件 / CC-57 一件,名单见 §2b 域 3 / 15;1019 = 0.73.0 的值(导出名零增减,BREAKING 在类型面);= 0.72.14 的值:相对 0.72.13 +8 —— CC-55 八件,名单见 §2b 域 3;1011 = 0.72.13 的值:相对 0.72.12 +18 —— CC-46 八件 / CC-54 六件 / CC-53 两件 / CC-50 缺席口两件,名单见 §2b 域 3 / 4 / 9 / 10;993 = 0.72.12 的值(测试钩 45):相对 0.72.11 +4 —— CC-50 `OUTCOME_UNKNOWN_ROW_PREFIX` / `isOutcomeUnknownRowText` / `TASK_NOTIFICATION_TERMINAL_STATUSES` / `isTaskNotificationTerminalStatus`;989 = 0.72.10 的值:相对 0.72.9 +4 —— CC-41 `LEADER_RUN_STATUSES` / `LEADER_REJ_HEAD_DISPLAY_MAX` / `projectLeaderConflict` / `leaderConflictDetail`;985 = 0.72.9 的值:相对 0.72.8 +8 —— CC-30 `MCP_RECONNECT_OUTCOMES` / `MCP_RECONNECT_TRANSACTION_NOTICE` / `projectMcpReconnectResult` / `classifyMcpReconnectFailure` / `reconnectMcpServer` / `projectMcpReconnectCapability` / `mcpReconnectOutcomeDetail`、CC-39② `readAutoConsolidationArmed`;977 = 0.72.8 的值:相对 0.72.7 +6 —— CC-39③ `MEMORY_OFF` / `memoryOffDeclarationField` / `memoryOffDeclared`、CC-43 `MODEL_OUTPUT_ERROR_PREFIX` / `isModelOutputErrorText` / `isModelOutputErrorRowText`;971 = 0.72.7 的值:相对 0.72.6 +2 —— CC-42 core 7.22.0 提货 `MCP_REDIAL_OUTCOMES` / `readMcpServerRedialed`;969 = 0.72.6 的值:相对 0.72.5 +1 —— CC-40 `steerFollowIntent`;968 = 0.72.5 的值:相对 0.72.4 +6 —— CC-31 server 7.82.1 提货 `capabilities.webSearch.backend` 四态读面:`WEB_SEARCH_BACKEND_NONE` / `projectWebSearchBackendCapability` / `observedWebSearchBackend` / `noteEngineCapsForWebSearchBackend` / `forgetWebSearchBackendReading` / `webSearchBackendDoctorDetail`;962 = 0.72.3 的值:相对 0.72.2 +1 —— CC-39① `AGENT_MEMORY_WORDS`;0.72.2 相对 0.72.1 +1 —— CC-37 `noteOwnWorkflowRun`;0.72.1 相对 0.72.0 +4 —— CC-33 server 7.80.1 提货:`RESUME_CONTEXT_UNAVAILABLE` / `resumeContextUnavailableFromError` / `resumeContextUnavailableContent` / `skillBaseDirOf`;0.72.0 相对 0.71.4 −39 —— CC-32 退役批删 export-liveness 登记 retire 的 39 个零消费导出(23 常量 + 16 函数,名单见 §47);995 = 0.71.3 的值:相对 0.71.2 +9 —— CC-06 `readEffectiveReasoning` / `readEffectiveMemoryScopes` / `resumeReopenFromError` / `resumeReopenContent` / `routePairingVerdict` 五函数 + `RESUME_REOPEN_CODES` / `RESUME_ENV_FAILED` / `RESUME_TOOL_UNAVAILABLE` / `RESUME_TOOL_CONTRACT_MISMATCH` 四常量;986 = 0.71.0 的值:相对 0.70.2 −`MAX_AGENT_SKILLS` −`DECIDE_WORKFLOW_HOST_NOT_PARKED` +`projectToolRosterDelta` +`mcpEngineLegPresence`;986 = 0.70.0 的值:相对 0.69.2 **一件 additive(`readSkillsListingTruncated`,§39)、零删除**;985 = 0.69.2 的值:相对 0.69.1 **三件 additive、零删除**(CC-13 `isSubFlowSegmentEnd` / `SEGMENT_END_IDENTITY_KEYS` / `droppedWhySentence`,§38);982 = 0.69.0 未发布版的值(原排 0.68.3,因 peer 地板抬升改 minor)= 相对 0.68.2 **十七件 additive、零删除**:`fetchMcpPanel`(CC-03 补件,§36e)+ `readWorkflowResumeAdmissionIncomplete`(CC-05 core 7.18.0 #755)+ `installCoreValuePorts`/`hasCoreValuePorts`/`hasCoreValuePort`/`coreValuePortMisses`/`CORE_VALUE_PORT_NAMES` + 十读口(CC-07 core 值级端口,§36d);0.68.2 相对 0.68.1 十三件 additive:`SEMA_SEGMENT_ID_KEY`(CC-01 段身份键,§35f)/ `projectMcpPanel`+`mcpPanelLastLegDetail`+`projectMcpSection`(CC-03 `/mcp` 面板读视图,§35g)/ `resolveTextSegmentAuthority`/`createTextSegmentLedger`(L-318 `text_end` 权威段替换的判决单源 + print 形段账,详见 §35b/§35c)/ `memoryCaptureDeclarationField`/`MEMORY_CAPTURE_OFF`(L-316 会话级隐私声明的字面唯一铸点,§35d)/ `engineUrl`/`probeHealth`(L-61 件④ SDK 纯工具面原样转口,§35d)/ `AgentClient`/`isApprovalRequestFrameV1`/`isApprovalRevokeFrameV1`(L-61 存量清零:SDK **wire 面**原样转口,§35e)。`0.68.1`/`0.68.0` 是 **952**,那批是相对 0.67.2 **二十件 additive、🔴 两件删除(BREAKING)**:additive = `TERMINAL_CAUSE_KINDS`/`isTerminalCauseKind`/`RUN_TERMINAL_NOT_SUCCESS_STATUSES`/`RUN_TERMINAL_STATUSES`(L-247 终态词两表分源,详见 §33b)/ `SEMA_SUBAGENT_USAGE_PARTIAL_KEY`/`subagentUsageIsPartial`(L-244 子代下界位自有名,§33g)/ `ASK_UNRESOLVABLE_CAUSES`/`readAskUnresolvable`/`DURABLE_MANDATE_SOURCES`/`readDurableGateUnavailable`(core 7.17.0 #709 ①② 两只通告事实窄读器,§33c)/ `WORKFLOW_PARK_TRUTH_UNREADABLE`/`WORKFLOW_PARK_NOT_PENDING`/`WORKFLOW_PARK_BINDING_BROKEN`/`WORKFLOW_PARK_REQUIRES_RUN_STORE`(四个单码常量 🔧 0.72.0 退役)/`WORKFLOW_PARK_REFUSAL_CODES`/`isWorkflowParkRefusalCode`/`readWorkflowParks`(core 7.17.0 #652 park 真相四码 + parks 三键读器,§33d)/ `ENGINE_STOP_REASONS`/`engineStopReasonToCc`(L-246 A13 停止原词映射下沉,§33g)/ `readCancelRequested`(L-230 读面,§33f);🔴 **删除两件** `TERMINAL_NOT_SUCCESS_STATUSES`/`TERMINAL_STATUSES`(随 L-247 两表分源更名成 `RUN_TERMINAL_*`,clean-cut **不留别名** —— 留一个别名等于让端可以继续按合起来的那张表读,分源就白做了,详见 §33b)。`0.67.0` 是 **934**,那批是相对 0.66.0 **七件 additive、🔴 两件删除**:additive = `CLASSIFIER_DENY_CAUSES`/`isClassifierDenyCause`/`classifierDenyCauseOf`/`classifierDenyCauseDetail`(core 7.14.0 退役 `classifierUnavailable` 之后的**拒绝面**继任读器与措辞,详见 §32b)/ `RULE_STORE_UNREADABLE_KINDS`/`isRuleStoreUnreadableKind`/`ruleStoreUnreadableDetail`(core 7.14.0 #688 C3 的规则店机制位三件,详见 §32d);🔴 **删除两件** `classifierUnavailableOf`/`classifierUnavailableDetail`(随 core 7.14.0 的 Retired keys 表整族退役,clean-cut 不留别名,详见 §32b;同批删的还有**型** `ClassifierUnavailableView`、卡位与帧位 `classifierUnavailable`、以及一条恒真的型面钉 `_askOriginWordsPin`)。`0.66.0` 是 **929**,那批是一件 additive、零删除:`readRunCostFacts`(终局成本事实的唯一读器:`costBreakdown` / `nested` 窄读 + 对账三段与两个判别位,终帧超集键与 chrome 对账臂共用它;详见 §31c);已发的 **0.65.x 十一件 additive、两件删除**:additive = `DECIDE_WORKFLOW_HOST_UNKNOWN`/`DECIDE_WORKFLOW_HOST_NOT_PARKED`/`DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED`/`DECIDE_WORKFLOW_LANE_CODES`/`readDecideReceipt`/`decideAcceptedNotResolved`/`decideRefusalFromError`(B-070 `/decide` 回执读面与三码人话,详见 §30h)/ `TERMINAL_NOT_SUCCESS_STATUSES`/`isTerminalNotSuccess`/`TERMINAL_STATUSES`/`isTerminalStatus`(L-215② 终局词汇单铸谓词,详见 §30j);🔴 **删除两件** `AUTO_MODE_BREAKER_CAUSES`/`classifierBreakerOf`(熔断族随 core 7.12.0 的 Removed(BREAKING) 整只退役,clean-cut 不留别名,详见 §30k②;同批删的还有**型** `ClassifierBreakerView` 与 `ClassifierStatusView.breaker` 一位)。`0.64.2` 是 **919**,那批是一件 additive、零删除:`readDenialLimitFallback`(限额回落卡的窄读器上公面,壳侧同判据副本退役,详见 §29③);`0.64.0` 是 **918**,那批是件①+件② 十三件 additive、零删除:`CLASSIFIER_STATUS_STATES`/`classifierBreakerOf`/`classifierStatusOf`/`classifierStatusDetail`(分类器状态面,详见 §28②)/ `THINKING_FORMATS`/`THINKING_FORMAT_WIRE_TWINS`/`THINKING_DISABLE_PROBE_ORDER`/`MODEL_PROBE_VERDICTS`/`PROBE_PROMPT`/`PROBE_MAX_TOKENS`(两个探针常量 🔧 0.72.0 退役)/`probeRequestBody`/`probeModelCapability`/`applyProbeToEntry`(模型思考能力探测,详见 §28①);`0.63.0` 是 **905**,那批是八件 additive、零删除:`projectServerGateKnobs`/`postureKnobSourceOf`/`postureSourceIsOperatorPinned`/`postureKnobDetail`/`POSTURE_SOURCE_WORDS`(S-178 三根 posture 旋钮读数,详见 §27b)/ `PERSISTED_RULE_BEHAVIORS`/`PERSISTED_RULE_BEHAVIOR_UNKNOWN`/`persistedRuleBehaviorOf`/`persistedRuleBehaviorLabel`/`revokeTargetFromPersistedRule`(三态规则身份,§27c)/ `engineIdentityOf`/`engineIdentityVerdict`/`engineIdentityChanged`/`engineIdentityChangedBy`/`ENGINE_IDENTITY_ANCHORS`(S-179 代际锚,§27d)/ `GATE_DENIED_BY_WORDS`/`gateDeniedByDetail`/`ASK_ORIGIN_WORDS`/`askOriginDetail`(门词汇 +2,§27e)/ `PERMISSION_RULE_ISSUE_CODES`/`RETIRED_PERMISSION_RULE_ISSUE_CODES`/`permissionRuleIssueDetail`(规则 lint 码表,§27f)/ `projectToolRoster`/`toolRosterNames`/`toolShimFromRoster`/`applyToolRosterDelta`(L-161 工具名册,§27g)/ `ENGINE_NOTICE_CODES`/`ENGINE_NOTICE_AUDIENCE`/`noticeAudienceOf`/`engineNoticeInCatalog`/`MCP_INJECTION_DROP_REASONS`/`readMcpInjectionDrop`(L-167 通告码册,§27h)/ `AUTO_MODE_UNAVAILABLE_CAUSES`/`AUTO_MODE_BREAKER_CAUSES`/`classifierUnavailableOf`/`classifierUnavailableDetail`(件⑧ 分类器不可用事实,§27h2);`0.62.0` 是 **869**,那批是五件 additive、**零删除**:`capForDisplay`(呈前消毒 + 封长的共用铸点,详见 §26⑦)/ `SEAT_SEND_MESSAGE_KEY_ORIGINS`(座位载荷逐键出身表,详见 §26③)/ `configureSubagentContentStore`+`subagentContentStoreConfig`+`SUBAGENT_CONTENT_STORE_DEFAULTS`(子代内容账本字节预算,测试钩 `__resetSubagentContentStoreConfigForTests` +1,详见 §26②);`0.61.0` 是 **864**,那批是三件 additive、**零删除**:`projectReadFacePosture`/`readFacePostureDetail`/`readFaceDisagreement`(S-167 READ 容纳面 operator 读器,详见 §25);`0.60.0` 是 **861**,那批是二十五件 additive、**零删除**:`readRunTerminal`/`runTerminalCode`/`runTerminalGateKind`/`runTerminalGateToolName`/`isReviewPark`/`REVIEW_PARK_GATE_KINDS` 六件终局因由读器 + `gateOutcomeOf`/`isDeniedGate`/`gateDeniedBy`/`gateApprover`/`isApprovalWindowExpiredGate`/`isDenialLimitAutoDeniedGate`/`isParkSlaExpiredGate`/`isHumanSettledGate` 八件门记录读器 + `projectWriteProtectionCapability`/`noteEngineCapsForWriteProtection`/`observedWriteProtection`/`forgetWriteProtectionReading`/`writeProtectionDoctorDetail`/`projectWriteProtectionPosture`/`writeProtectionPostureDetail` 七件写保护读面(测试钩 `__resetWriteProtectionReadingsForTests` +1)+ `readWireErrorCode` + 真机边界①的两件 `isGateParkedToolEnd`/`GATE_PARKED_ERROR_CODE` + 异源复审逼出的 `engineCapsGeneration`;`0.59.0` 是 **836**,那批是八件 additive:`RULE_OFFERS_ABSENCE_REASONS`/`DENIAL_LIMIT_KINDS` 两张闭词表再导出 + `engineCapValue` 能力位四态通用读口 + `projectSqlEngineCapability`/`observedSqlEngine`/`noteEngineCapsForSqlEngine`/`forgetSqlEngineReading`/`sqlEngineDoctorDetail` 五件 SQL 姿态读面(测试钩 `__resetSqlEngineReadingsForTests` +1);`0.58.0` 是 **828**,那批是三件 additive:`RULE_OFFER_MATCHES`/`RULE_OFFER_BATCH_MEMBER_KINDS`/`RULE_OFFER_UNCOVERED_REASONS` 三张闭词表再导出 + `RESUME_REFUSAL_CODES`/`RESUME_PLACEMENT_MISMATCH`/`resumeRefusalFromError`/`resumeRefusalContent` 四件文案铸点;`0.57.0` 是 **821**;`0.56.0`/`0.55.0` 是 **815**;已发 `0.54.0`(design/385 十件 additive 含 `AUTHORITY_ENVELOPE_TAGS` 🔧 0.72.0 退役);`0.52.0` 是 **805**(L-69⑨ 两件);`0.51.0` 是 **803**;`0.50.0` 是 **800**(S-81 五件);`0.49.0` 是 **795**;`0.48.0` 是 **794**;npm `0.47.0` 是 **790**,`0.46.0` 是 **787**,`0.44.0` 是 **783**,`0.43.1`/`0.43.0` 是 **776**,`0.42.0` 是 **771**,`0.41.0` 是 **767**,`0.39.0` 是 **766**,`0.38.0` 是 **764**;`0.37.0` 是 **753**,见 `CHANGELOG.md`) | `scripts/public-export-baseline.json` 的 `count` / `testHookCount` —— **别手抄进别处,以该文件为准** |
@@ -1553,7 +1553,7 @@ CHANGELOG 0.29.0「已知局限」段与相应 JSDoc 都有成文。**别在读
1553
1553
 
1554
1554
  | **P-42** | low @cli @web @desktop | 🆕 **Esc halt 只上收了判定,发射面仍在各端**(0.47.0 件③,刻意的分工不是半成品):`planInteractiveHalt` 给判据与升级码闭集,`POST /v1/runs/:id/interrupt` 的**发射**(以及 `?session=` 供给、超时窗、台账、留痕)仍归端。cli 侧那条「裸 fetch 直拨 interrupt」的网络面豁免,**退役条件就是端接上这个口子**(壳换装不在 0.47.0 批内) | `src/interactiveHalt.ts`;§10 | 按 §10b 的分支表接:判定用本包,发射用端自己的传输腿;🔴 halt 必须排在撕 SSE **之前**(§10c 第 1 条) |
1555
1555
 
1556
- | **P-43** | ✅ **已收(对实现了读口的宿主)**(0.83.0,CC-162) | 🔧 **`hooksForWire()` 第四条治理规则 0.83.0 已补**:非 managed 来源(user / project / local / flag)的 `disableAllHooks` 按**合并值**判 —— `SettingsPort.mergedDisableAllHooks?()` 为 `true` ⇒ 只发 managed 的 hooks(非 managed 设置关不掉组织下发的),会话目标的 Stop 钩子一并不发;宿主没实现这个可选读口 ⇒ 仍是旧行为(只认 managed 那一份),每个已装端口告警一次;读口抛错 ⇒ 按合并值为真处置(managed 的照发)。**合并顺序订正**:本行旧文「四源按 policy→user→project→local 后写覆盖前写」是错的 —— 真序 user → project → local → flag → policy,policy 最后写、优先级最高;policy → user → project → local 是本包发往引擎的 hooks 数组的**拼接**顺序,不是合并标量的顺序。不做逐源近似的理由不变(「任一来源为 true」在 user=`true` ∧ local=`false` 上判反)。余项:CC 云会话路径的逐来源语义本版不跟、宿主的安全模式本包没有读口(§100 包侧缺口 ⑤;0.83.1 起插件 hook 有安全·bare 位 `suppressedByStartupMode`(§101),设置来源仍没有) | `src/hooksWireCaps.ts`(头注「第四条腿」段)· `src/host.ts` `SettingsPort.mergedDisableAllHooks`;§15b/§15d;§100a-5 | 装 `SettingsPort` 的宿主实现 `mergedDisableAllHooks()`,返回本机 hooks 执行器读的同一个合并值;**未实现**的宿主仍**不要**假定用户 settings 里的 `disableAllHooks` 会挡住引擎腿的 hooks |
1556
+ | **P-43** | ✅ **已收(对实现了读口的宿主)**(0.83.0,CC-162) | 🔧 **`hooksForWire()` 第四条治理规则 0.83.0 已补**:非 managed 来源(user / project / local / flag)的 `disableAllHooks` 按**合并值**判 —— `SettingsPort.mergedDisableAllHooks?()` 为 `true` ⇒ 只发 managed 的 hooks(非 managed 设置关不掉组织下发的),会话目标的 Stop 钩子一并不发;宿主没实现这个可选读口 ⇒ 仍是旧行为(只认 managed 那一份),每个已装端口告警一次;读口抛错 ⇒ 按合并值为真处置(managed 的照发)。**合并顺序订正**:本行旧文「四源按 policy→user→project→local 后写覆盖前写」是错的 —— 真序 user → project → local → flag → policy,policy 最后写、优先级最高;policy → user → project → local → flag(0.83.3 起含 flag,排在 local 之后)是本包发往引擎的 hooks 数组的**拼接**顺序,不是合并标量的顺序 —— 托管在前的理由(引擎 hook 执行器三种资源先到先得,托管排后会被挤掉)与已知代价(`PreToolUse` 上排在托管之后的 hook 能在托管放行之后改写输入)见 §103a H-9 与 §103 包侧缺口 ⑧。不做逐源近似的理由不变(「任一来源为 true」在 user=`true` ∧ local=`false` 上判反)。余项:CC 云会话路径的逐来源语义本版不跟、宿主的安全模式本包没有读口(§100 包侧缺口 ⑤;0.83.1 起插件 hook 有安全·bare 位 `suppressedByStartupMode`(§101),设置来源 —— 0.83.3 起含 flag 来源 —— 在这一位下仍不收窄,§103 包侧缺口 ③) | `src/hooksWireCaps.ts`(头注「第四条腿」段)· `src/host.ts` `SettingsPort.mergedDisableAllHooks`;§15b/§15d;§100a-5 | 装 `SettingsPort` 的宿主实现 `mergedDisableAllHooks()`,返回本机 hooks 执行器读的同一个合并值;**未实现**的宿主仍**不要**假定用户 settings 里的 `disableAllHooks` 会挡住引擎腿的 hooks |
1557
1557
 
1558
1558
  | **P-44** | ✅ **已收**(0.58.0,sdk 8.2.0 提货)@cli @web @desktop | ✅ **上游已补齐,本条转已收** —— sdk **8.2.0**(S-134 五锚)把这一族型面缺口一次补完:①`respond` 体 `persistRule` 由单臂 `{rule}` 换成具名**两臂互斥**联合 `PersistRuleSelection`(`{rule, edited?}` ∣ `{batchOfferIndex}`,互斥用 `?: never` 钉在编译期 ⇒ server 那句 `PERSIST_RULE_BATCH_EXCLUSIVE_ERROR` 400 永远打不到线上);②`ToolApprovalFrame` / `ApprovalCard` / `PendingCheckpoint` 三腿同一个 `RuleOffer` 判别联合(含 `match` 四员闭词表、成员 `command`/`directoryRead` 两臂、additive `uncoveredDetail`);③`ToolApprovalRespondAck` 补 `persistedRule` / `persistedRules` / `persistedRuleAnchors` 三位。🔴 **本包侧本来就零 cast、也不需要 cast**(0.57.0 原文,逐字仍成立):本包**不铸 respond 的 wire 体** —— `RespondToolApprovalFn` 是**宿主注入**的函数型,包只把扁平兄弟位(`persistRule: string` / `persistRuleEdited?: true` / `persistRuleBatchOfferIndex?: number`)交给注入面。⇒ 吃这个缺口的一直是**三端的注入面**。本包 0.58.0 这一侧的动作是:归一形 `RuleOffer` 一族改由 sdk 派生、`ToolApprovalRespondAckView` 与 `PersistedRuleAnchor` 两个包内自铸形按各自写下的退役条款回收成 sdk 形的别名、`AHEAD_OF_ANCHOR` 里那条 `ruleOffers` 领先登记到期自红删除(详见 **§22a**)。🔴 **三端还要做的那一半(本条转已收之后的剩余动作)**:注入面那处宽 `cast`(或自铸的 respond 包装形)现在可以删掉,改直接用 sdk 8.2.0 的 `PersistRuleSelection` —— 两臂互斥由编译期钉,`{rule, batchOfferIndex}` 同场会**编译红**(这正是要的);`batchOfferIndex: 0` 逐字进 body(`0` 不被 falsy 吞)。同样别再在端侧自铸同名 `RuleOffer` 形:归一形与它的伴生类型自 0.57.0 起在本包公面上,三张闭词表自 0.58.0 起也在(§22b) | `src/hitl/toolApprovalWire.ts`(两处「候 sdk 补锚」头注已随本批锚到 8.2.0 / 回收)· `scripts/run-approval-frame-keys-test.mjs`(该条 `AHEAD_OF_ANCHOR` 登记已删)· `scripts/run-sdk-floor-test.mjs`(地板 8.2.0) | 端按上一栏「剩余动作」删自己的宽 cast;peer 地板随本包抬到 `>=8.2.0`,提货前先抬依赖 |
1559
1559
 
@@ -9599,6 +9599,141 @@ installCoreValuePorts({ resolveAutonomousLoopPrompt, loosenReasons, combinePolic
9599
9599
 
9600
9600
  **包侧缺口:** ① 出包面注释存量(别仓名 / 票号 / 帖号 / 过程词)与卫生门判据太窄(CC-100)—— 方案候拍板(dist 去注释 vs 手清),0.77.2 · ② `DeniedBy` 第十词 `read_boundary` / `teamName` / `stillLive` 三词随 sdk 10 型面在 0.78.0 吸收(CC-106)· ③ `capabilities.mcpProbe` 候 core 7.26.0 #951 → server 7.93.0(CC-74)。
9601
9601
 
9602
+ ## §103 🆕 0.83.3(2026-09-26)flag 来源的 hooks 进请求体 + 规则列举口入参只要 `list` + 模型身份认目录缺省(patch;根公面运行期导出 1273 不变;公面类型 +1〔`RulesListFacade`〕;`HookSettingsSource` +1 员 `flagSettings`;`ModelIdentityLanes['modelCatalogFile']` 闭集 +`complete`;`LocalEngineModelIdentityReading` +1 可选位 `engineAcceptsCatalogDefault`;`listAllPersistedRules` 入参放宽〔`list` 必填、其余四口可选〕;零投影臂;peer sdk 地板 `>=11.3.0` 不动)
9603
+
9604
+ > **patch**,三件同发 + 一件「次序不变」的成文(本节按 0.83.3 的读法写;若与本版发布帖不一致,以发布帖为准):
9605
+ > ① **flag 来源的 hooks 进请求体**:宿主经 `SettingsPort.getSettingsForSource('flagSettings')` 交来的设置(启动参数给的设置文件与内联设置)里写的 hooks,此前到不了引擎;本版起与 user / project / local 同一条投影、同一套治理。
9606
+ > ② **设置来源 hooks 的拼接次序不变**:managed 仍在最前(managed → user → project → local → flag),flag 来源排在 local 之后。为什么不跟设置合并的次序(managed 最后写)走、以及托管在前的已知代价,见 H-9 与包侧缺口 ⑧。
9607
+ > ③ **规则列举口只要 `list`**:`listAllPersistedRules` 的入参由完整五口放宽为只要 `list`(具名型 `RulesListFacade`;其余四口作为可选成员认得,内联对象字面量、参数不写型的箭头照样可传,拼错口名照样报错);只装读 / 撤两口的宿主直接用本口。另写清列举 / 撤销两口会遇到 `classifyRulesFailure` 的哪几臂(103a-1)。
9608
+ > ④ **模型身份认目录缺省**:服务端 7.101.0 起启动环境里的模型名或目录缺省任一在场即可启动;宿主报本机引擎接受目录缺省时,只用模型目录文件的配置判可解析;报不接受判不可解析;不报仍判不出。
9609
+ > **服务端 7.102.0 起**:§102 候服务端的两件在真部署上到货 —— 停泊审批卡(耐久重开 / 重连出来的卡)上的 `origin`(§102 O-1)与审批卡上的 `mandate`(§102 M-1;服务端的审批帧、活挂起行与运维队列行都带)。本包零改动生效;§102 G-M5(此前按 N/A)自此可跑。
9610
+ > **表态现势**:patch,全速模式,不设表态窗;各端列写本版读点普查的结论。
9611
+
9612
+ ### 103a. 处置表
9613
+
9614
+ | # | 面 | 旧 → 新 | 终端 | 网页端 | 桌面端 | 管理台 | 验收方 | 本节 |
9615
+ |---|---|---|---|---|---|---|---|---|
9616
+ | H-1 | `hooksForWire()` / `hooksWirePlan()` 的设置来源 | 四源 → **五源**,flag 来源拼在 local 之后(拼接序见 H-9)。治理同进退:`allowManagedHooksOnly` / hooks 面的 `strictPluginOnlyCustomization` 锁 / 非 managed 来源的合并 `disableAllHooks`(读口抛错同判)⇒ flag 来源一并不发(只发 managed);managed `disableAllHooks` / 未受信工作区 / 信任或 managed 读取抛错 ⇒ 零发。0.83.1 起的两类拿掉(带参数的 command 条目、传了计划时的 `mcp_tool`)与不传计划时的一次性告警对 flag 来源同样生效。flag 来源读取抛错 ⇒ 只当这一源没配 hooks(调试记一行),其余来源照发。flag 来源的 `Stop` hook 上请求体 ⇒ 显式 `--final-verify` 让位(与其余来源同判) | consumed(零改动即得:宿主口已按来源名转交,flag 来源由宿主自己的设置读取合成文件与内联两处) | n/a(不调 `hooksForWire()`,与 §100a 同) | n/a(不调 `hooksForWire()`,与 §100a 同) | n/a | pending | 103b · G-H1–G-H5 / G-H7 |
9617
+ | H-2 | `HookSettingsSource` +`flagSettings`;计划 `settingsDropped[].source` 可为 `flagSettings`;`hooksNotRunNotice` 这一源的措辞 `Flag settings` | 四员 → 五员(型面放宽) | n/a(今天无读点) | n/a | n/a | n/a | pending | G-H4 |
9618
+ | H-9 | 请求体上同一事件的设置来源拼接次序;`plan.settingsDropped` 与 `hooksNotRunNotice(plan)` 的来源次序 | **不变**,只多一源:managed → user → project → local → **flag**(managed 仍在最前,flag 排在 local 之后)。不跟设置合并的次序(managed 最后写)走:引擎的 hook 执行器按请求体次序执行,有三种先到先得的资源 —— 每事件墙钟预算(120 秒,用完之后排在后面的同步条目不再启动)、`PreToolUse` 之外每事件四条模型条目(`prompt` / `agent`)的上限、`additionalContext` 总帽(一万字符,顺序保留、只截尾);managed 排在后面时,排在前面的非 managed hook 能把 managed 的守卫挤掉(不执行,调用照常)。已知代价(包侧缺口 ⑧):`PreToolUse` 上排在 managed 之后的非 managed hook(设置来源与插件注册的组)能在 managed 放行之后改写输入,与 0.83.2 同 | consumed(零改动;次序与 0.83.2 同) | n/a(不调 `hooksForWire()`) | n/a(不调 `hooksForWire()`) | n/a | pending | 103a′ · G-H2 / G-H4b / G-H6 / G-H6b |
9619
+ | R-1 | `listAllPersistedRules(facade: RulesListFacade & Partial<Omit<RulesFacade, 'list'>>, params?, opts?)`;新具名型 `RulesListFacade = Pick<RulesFacade, 'list'>` | 入参完整五口 `RulesFacade` → 只要 `list`(放宽:其余四口是型上认得的可选成员 ⇒ 完整五口 / 读撤两口 / 只 `list` 写成内联对象字面量都过型,箭头的参数不写型也拿得到上下文类型,拼错口名照样报错;完整五口变量照样可传,运行期行为不变。成员与 `RulesFacade` 同名口型不兼容的对象仍被拒,与 0.83.2 同严) | n/a(零改动) | pending(建议:自带的列全口与失败分类换读本包 `listAllPersistedRules` / `classifyRulesFailure`,判据见 103a-1,同批删本地同名那份) | n/a | n/a | pending | 103a-1 · G-R1 / G-R2 |
9620
+ | M-1 | `ModelIdentityLanes['modelCatalogFile']` | 闭集 `partial` / `absent` / `unreadable` → +`complete`(= 目录里有一只启用的、可作缺省的模型;算不算数看 M-2 位) | pending(接模型身份判据时按本定义报目录一格:文件存在不等于里面有一只启用的缺省模型) | n/a(远程拓扑) | pending(有本机引擎时同终端) | n/a | pending | 103b · G-M1–G-M3 |
9621
+ | M-2 | `LocalEngineModelIdentityReading.engineAcceptsCatalogDefault?: boolean` | 无 → 新增可选位:宿主报它要起的本机引擎接不接受「目录缺省代替启动时的模型名」(按宿主自己钉的引擎版本判;服务端 7.101.0 起接受)。目录一格 `complete` 时:`true` ⇒ 这一路可解析;`false` ⇒ 按 `partial`;缺席(含值为 `undefined` 的键)/ 非布尔 ⇒ 这一路判不出(`unknown`,不折「不接受」)。只对目录一格起作用;远程拓扑与别的来路不读它 | pending(同 M-1) | n/a | pending(同 M-1) | n/a | pending | 103b · G-M1 / G-M2 / G-M2′ |
9622
+ | M-3 | `modelIdentityDetail` 目录一路四段新措辞 | 新增(逐字见 103a-2);既有各句逐字不变 | 零改动即得 | n/a | 同终端 | n/a | pending | 103a-2 · G-M4 |
9623
+
9624
+ #### 103a-1 · 列举 / 撤销两口会遇到的失败臂
9625
+
9626
+ `classifyRulesFailure` 共十六个 `kind`(十五个具名臂 + 通用 `error`)。只装读 / 撤两口的宿主会遇到的是下面这些;其余几臂(`ticket-dead` / `retry-same-ticket` 属于导入口,`field-refused` / `write-indeterminate` / `write-not-committed` 属于单步写口)在这两口上不出现。
9627
+
9628
+ | `kind` | 列举(`GET /v1/rules`) | 撤销(`DELETE /v1/rules`) | 处置 |
9629
+ |---|---|---|---|
9630
+ | `lane-unavailable` | ✓ | ✓ | 这台部署没接规则店 ⇒ 整面藏起来 |
9631
+ | `forbidden` | ✓(读别人名下) | ✓(撤别人名下) | 越权被拒;不重试 |
9632
+ | `cursor-stale` | ✓ | — | 游标失效:`listAllPersistedRules` 已丢游标从头重列一次,再撞才交出;过滤 `scope` 读不出形也落这一臂(见包侧缺口) |
9633
+ | `body-shape` | — | ✓ | 撤销体读不出形(身份三键 / `scope`);改请求,不重试 |
9634
+ | `retryable` | — | ✓ | 什么都没写(`committed: "no"` 或老服务端缺席);可原样重发 |
9635
+ | `remove-indeterminate` | — | ✓ | 墓碑可能已落而读回失败;不盲重试,用列举对账 |
9636
+ | `route-missing` | ✓ | ✓ | 服务端比这条路由老 ⇒ 藏治理入口 |
9637
+ | `method-unsupported` | ✓ | ✓ | 路径在、这个动词不在(引擎自己的裸 `method_not_allowed`)⇒ 服务端比这个动词老 |
9638
+ | `method-refused` | ✓ | ✓ | 405 而码给不出出处(中间层也能发):撤销上按「结局说不清」对账,别据此要求升级或藏入口 |
9639
+ | `too-many-candidates` | — | 仅当撤销体超过服务端请求体上限(单条规则实际到不了) | 缩短后重发 |
9640
+ | `error` | ✓ | ✓ | 其余一切(未鉴权、限流、服务端 5xx、坏形 2xx 页、跨页 rev 漂移、坏规则行、坏 `nextCursor`、翻不完、没码的 501);失败信息原样可显示 |
9641
+
9642
+ 🔴 **「规则店不在」只认机器码 `capability.rule_store_required`**,不认 501 状态码本身:引擎的错误信封恒带机器码;一个没码的 501 谁都能发(反向代理对不认识的动词就回 501)。凭裸 501 藏整面、或在写口说「确知没写」,等于把出处交给了一个任何中间层都能发的状态码 —— 出错时代价是把一个活着的治理面藏掉。没码的 501 落 `error`,如实显示失败原句。自带「裸 501 ⇒ 规则店不在」判法的端换读本口时按此改口。
9643
+
9644
+ #### 103a-2 · 目录一路的四段新措辞
9645
+
9646
+ | 场景 | `modelIdentityDetail(reading)` |
9647
+ |---|---|
9648
+ | 本机 ∧ 目录一格 `complete` ∧ `engineAcceptsCatalogDefault: true`(且之前的来路都没有 `complete`) | `the local model catalog file supplies a model name as its default, and the local engine accepts a catalog default in place of a startup model name, so it can start with it — whether its gateway accepts that name is a separate check` |
9649
+ | 本机 ∧ 目录一格 `complete` ∧ 位 `false` ∧ 其余来路都明说 `partial` / `absent` | `no model name is configured for the local engine to start with — the local model catalog file names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name, and the engine does not start without one`(别的来路有 `partial` 时,在 `…startup model name` 之后接 `, and <来路> carries part of a model configuration (such as a gateway address or a credential) but no model name`) |
9650
+ | 本机 ∧ 目录一格 `complete` ∧ 位缺席(含值为 `undefined` 的键)∧ 其余来路都没有 `complete` | 判不出句 `whether the local engine has a model name is unknown — <各段>, and no other place this client reads provides one` 里目录的那一段:`the local model catalog file names a default model, but whether the local engine accepts a catalog default in place of a startup model name was not reported`(别的来路也判不出时,那几段在前,以 ` and ` 接目录这一段) |
9651
+ | 同上,位在场但不是布尔 | 同一位置的一段:`the local model catalog file names a default model, but the report of whether the local engine accepts a catalog default in place of a startup model name gave no usable reading` |
9652
+ | 本机 ∧ 目录一格 `complete` ∧ 位 `false` ∧ 别的来路有判不出的(其余都没有 `complete`) | 判不出句里目录的那一段(与第二句的目录段同一措辞):`the local model catalog file names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name`(判不出的那几段在前,以 ` and ` 接目录这一段) |
9653
+
9654
+ 例(位 `false`、设置文件 `unreadable`、其余来路 `absent`):`whether the local engine has a model name is unknown — this client's settings file could not be read and the local model catalog file names a default model, but the local engine is reported not to accept a catalog default in place of a startup model name, and no other place this client reads provides one`。
9655
+
9656
+ 例(位缺席、其余来路 `absent`):`whether the local engine has a model name is unknown — the local model catalog file names a default model, but whether the local engine accepts a catalog default in place of a startup model name was not reported, and no other place this client reads provides one`。
9657
+
9658
+ ### 103a′. 成文改口
9659
+
9660
+ - **作废**:§93 S-11(0.82.1)「目录文件一格型上没有 `complete`;运行期报 `complete` ⇒ 判不出(`unknown`),措辞说这一路给的读数用不了」的判据眼。本版起目录一格报 `complete` 时:位 `true` ⇒ `resolvable`;位 `false` ⇒ 按 `partial`;位缺席 / 非布尔 ⇒ 仍判不出(`unknown`),但措辞改为点名目录里有缺省模型(103a-2 第三 / 四段;位 `false` 而别路判不出的 `unknown` 句见第五段);「这一路给的读数用不了」只留给表外词。
9661
+ - **改读(模型身份)**:目录一格 `complete` ∧ 位 `true` ⇒ `resolvable`(决策 `proceed`);位 `false` ⇒(其余来路都明说时)`not_resolvable`(决策 `offer_setup` / `explain_unconfigured`),措辞为 103a-2 第二句;位缺席(含值为 `undefined` 的键)/ 非布尔 ⇒ `unknown`(决策 `proceed`,与 0.83.2 同答)。装 0.83.3 后按「目录 complete 一律 unknown」去判位 `true` / `false` 两形的格判红是预期行为。
9662
+ - **改读**:「本包发往引擎的 hooks 数组只含四源」的判据眼作废。
9663
+ - **新增**:G-H1–G-H7(含 G-H4b / G-H6b)/ G-R1–G-R2 / G-M1–G-M5(含 G-M2′)。
9664
+ - **不变**:请求体上设置来源 hooks 的拼接次序 —— managed 在前(§7 P-43「policy → user → project → local 是本包发往引擎的 hooks 数组的拼接顺序」一句照旧成立,本版只在末尾多一个 flag);它**不**跟合并标量的顺序(user → project → local → flag → managed,§100a-5)走,理由见 H-9;合并标量的顺序;`mergedDisableAllHooks` 读口的契约;列举口的翻页与失败语义;远程拓扑的模型身份判据。
9665
+ - 已发段(§93、§100、§101、§102)不回改,以本段为准;§7 P-43 是活段,随版改。
9666
+
9667
+ ### 103b. 缺席语义(逐键)
9668
+
9669
+ - 宿主不交 flag 来源(`getSettingsForSource('flagSettings')` 返回 `null` / 缺 `hooks`)= 这一源没配 hooks ⇒ 请求体上没有 flag 来源的组(其余来源的次序按 H-9)。宿主的设置口对不认识的来源名**抛错**时,每轮记一行调试、这一源按没配处置 —— 建议返回 `null`。
9670
+ - `settingsDropped[].source === 'flagSettings'` 只说「这一条来自 flag 来源」,不说它是文件还是内联(本包看到的是宿主合成的一份)。
9671
+ - 拼接次序:同一事件的设置来源组按 managed → user → project → local → flag 拼接;某一源没配 / 读不出 ⇒ 这一源空着,其余次序不变。`settingsDropped` 与开机清单的来源次序是同一张表。
9672
+ - `engineAcceptsCatalogDefault` 缺席(含值为 `undefined` 的自有键 —— `{ …, engineAcceptsCatalogDefault: maybe }` 一类展开写法)= 宿主没说本机引擎接不接受目录缺省 ⇒ 目录这一路**判不出**(不折「不接受」;其余来路都明说时 `unknown`,与 0.83.2 同答),措辞说 `was not reported`。在场但不是布尔 = 报了、读不懂 ⇒ 同样判不出,措辞说那份报告 `gave no usable reading`(端报了就不说「没报」)。只有字面 `false` 才按「不接受」(`partial`)处置;位 `false` 而别的来路判不出 ⇒ 整体 `unknown`,判不出句里照样有「宿主报引擎不接受」的目录段。原型链上的同名位不算(按缺席)。
9673
+ - 目录一格 `complete` 缺席(报 `partial` / `absent`)在位为 `true` 时**不会**被位救成可解析;报 `unreadable` / 缺键仍按判不出(`unknown`)。目录这一路判不出时,别的来路 `complete` 照样判可解析。
9674
+ - 远程拓扑上带着 `engineAcceptsCatalogDefault` / `lanes` = 不读(远程只看应答观测)。
9675
+ - `RulesListFacade` 不含 `revoke` / `write` / 导入两口:本包的列全口不会调它们;撤销、单步写、导入仍各走各自的口。
9676
+
9677
+ ### 103c. 黑盒判据骨架
9678
+
9679
+ > 🔴 标「本版证明」的格在 **0.83.2** 产物上必须 FAIL、在 0.83.3 上必须 PASS;标「回归约束」的格两版都 PASS;标「端侧验收」的格验的是端换读 / 升级之后的行为,不按包的两版产物对拍。请记下两次跑的产物标识(版本 + tarball shasum)。前缀:G-H = hooks、G-R = 规则列举口、G-M = 模型身份。
9680
+
9681
+ - **G-H1**(本版证明,纯包层;H-1):`installHost({ settings })`,设置口对 `flagSettings` 交 `{ hooks: { PreToolUse: [g] } }`(`g = { matcher: '*', hooks: [{ type: 'command', command: 'flag-guard' }] }`)、其余来源 `null`、信任门 `false`、`mergedDisableAllHooks: () => false` ⇒ `hooksForWire().PreToolUse[0] === g`(原对象)。判别点:0.83.2 答 `undefined`。
9682
+ - **G-H2**(本版证明,纯包层;H-1 / H-9 拼接序):五个来源各一组、命令依次 `p`(managed)/ `u` / `j` / `l` / `f` ⇒ `PreToolUse` 各组首条命令顺序为 `p u j l f`。判别点:0.83.2 为 `p u j l`(flag 缺席;其余次序两版同)。
9683
+ - **G-H3**(回归约束,纯包层;H-1 治理 —— 两版都 PASS,0.83.3 上才有判别力):同 G-H2 的五源,分别加 managed `allowManagedHooksOnly: true` / `strictPluginOnlyCustomization: true` / `strictPluginOnlyCustomization: ['hooks']` / 合并读口答 `true` / 合并读口抛错 ⇒ 只剩 `p`;managed `disableAllHooks: true` / 信任门答 `true` / 信任门抛错 / managed 读取抛错 ⇒ `hooksForWire()` 为 `undefined`。
9684
+ - **G-H4**(本版证明,纯包层;H-1 / H-2 拿掉与措辞):flag 来源一组 `[{ type: 'command', command: 'keep' }, { type: 'command', command: 'node', args: ['x.js'] }]`(事件 `PreToolUse`)⇒ 不传计划:请求体该组只剩 `keep`,告警恰一条且点名 `PreToolUse`;`hooksWirePlan({ engineOwnedByThisShell: true, shellHookEvents: [] }).settingsDropped` 恰一条 `{ source: 'flagSettings', event: 'PreToolUse', groupIndex: 0, hookIndex: 1, reason: 'exec_form_unsupported', notRun: true }`;`hooksNotRunNotice(plan)` 恰一行,以 `Flag settings: PreToolUse hook will not run — ` 开头。判别点:0.83.2 请求体无该组、零告警、零拿掉。
9685
+ - **G-H4b**(回归约束,纯包层;H-9 次序的可观察面):managed 与 user 各一组 `[{ type: 'command', command: 'node', args: ['x.js'] }]`(事件 `PreToolUse`)⇒ `hooksWirePlan({ engineOwnedByThisShell: true, shellHookEvents: [] }).settingsDropped` 的来源依次 `policySettings`、`userSettings`;`hooksNotRunNotice(plan)` 两行,依次以 `Managed settings: ` / `User settings: ` 开头。两版同答(托管在前)。
9686
+ - **G-H5**(端侧验收;射程:终端,本机引擎,升级到 0.83.3 后):启动参数 `--settings <文件>`,文件里写一条 `PreToolUse` 的 command hook(命令写一个标记文件)⇒ 让代理跑一次工具,标记文件出现(hook 在引擎侧执行);同一条写进内联设置同判。
9687
+ - **G-H6**(回归约束,包层 + 服务端发布版的 hook 执行入口;H-9 托管在前守住三种资源):把 `hooksForWire()` 原样交给服务端的 `parseHooksConfig` + `createTaskHooks`,三形:① **墙钟预算**:managed 一组 `echo managed-guard >&2; exit 2`,user 一组(另三格换成 project / local / flag)`touch <标记文件>; exit 0`;装一只时钟垫片 —— 标记文件出现后 `Date.now()` 前跳 200 秒(模拟那条命令跑满 120 秒预算,不真等),调完复原 ⇒ `PreToolUse`(`Bash`,`{ command: 'ls' }`)答 `{ action: 'deny', message: 'managed-guard' }`;`UserPromptSubmit` 同构(组不带 matcher)答 `{ block: 'managed-guard' }`。② **模型条目上限**:`UserPromptSubmit` 上 user(另一格 flag)一组四条 `prompt` 条目、managed 一组一条 `prompt` 条目;`hookLlm` 假件对 managed 那条答 `{"decision":"block","reason":"managed-dlp"}`、其余答 `{}` ⇒ 答 `{ block: 'managed-dlp' }`。③ **上下文总帽**:`UserPromptSubmit` 与 `PostToolUse` 各一格,managed 一组的 `additionalContext` 为一句短标记,user 两组、flag 一组各 4000 字 ⇒ 回体 `additionalContext` 含 managed 那句。两版都 PASS(0.83.2 同为托管在前;flag 各格在 0.83.2 上请求体只有 managed 组,同样 PASS)。尺子自证:手排「非 managed 在前」的请求体,三形都应答成 managed 被挤掉(预算形无意见 + 执行器记 `hook_event_deadline_exceeded`;上限形无意见 + 记 `llm_entries_per_event_cap`;上下文形不含那句、带截断标记)—— 这组不成立时本格没有判别力,先查服务端版本。
9688
+ - **G-H6b**(回归约束 · 已知代价显形,包层 + 服务端发布版的 hook 执行入口;H-9 / 包侧缺口 ⑧):managed 一组 `if grep -q MARK; then echo deny >&2; exit 2; fi; exit 0`(输入里见到标记就拒)、user 一组(另三格换成 project / local / flag)放行并把输入改写成带标记的命令(标准输出 `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","updatedInput":{"command":"MARK"}}}`)⇒ 对 `Bash` 输入 `{ command: 'ls' }` 调 `preToolUse` 答 `{ action: 'allow', updatedInput: { command: 'MARK' } }`(managed 看到的是改写前的输入)。user / project / local 两版同答;flag 一格 0.83.2 答无意见(请求体上没有 flag 组),0.83.3 同其余三格。这是记账格,不是期望行为:服务端支持为 managed 组按最终输入执行之后,本格随包侧缺口 ⑧ 一起改。
9689
+ - **G-H7**(本版证明,纯包层;H-1 下游):设置口只对 `flagSettings` 交 `{ hooks: { Stop: [{ matcher: '*', hooks: [{ type: 'command', command: 'flag-stop' }] }] } }` ⇒ `resolveHeadlessFinalVerifyDetail(['--final-verify'], {}, hooksForWire())` 答 `{ on: false, offReason: 'stop-hook' }`。判别点:0.83.2 答 `{ on: true }`。
9690
+ - **G-R1**(本版证明,纯包层;R-1 型面):一份消费方 `.ts` 从包入口引入,`declare const twoPort: { list: RulesFacade['list']; revoke: RulesFacade['revoke'] }` 与 `{ list: async () => ({ rules: [], rev: 1 }) }` 各传给 `listAllPersistedRules`,`import type { RulesListFacade }` 标注一个变量再传,`declare const full: RulesFacade` 后把 `{ list: full.list, revoke: full.revoke }` 与 `{ list: (p, o) => full.list(p, o), revoke: (b, o) => full.revoke(b, o) }`(参数不写型)各写成内联字面量传 ⇒ `tsc --noEmit` 零诊断。判别点:0.83.2 报 TS2345(缺 `write` / `ccImportPrepare` / `ccImportRedeem`)与 TS2724(无 `RulesListFacade`)。
9691
+ - **G-R2**(回归约束,纯包层):完整五口照样零诊断 —— `full` 变量、`{ list: full.list, revoke: full.revoke, write: full.write, ccImportPrepare: full.ccImportPrepare, ccImportRedeem: full.ccImportRedeem }` 内联字面量、五口写成参数不写型的内联箭头(`list: (p, o) => full.list(p, o)` 一类)三形;内联字面量拼错口名 `{ list: full.list, revokee: full.revoke }` 恰报一条(TS2561,点名 `revokee`)两版同;运行期同一只两页假件两版都答 `{ ok: true }`、两条、`rev` 取自服务端、只调 `list`:第一页 `{ rules: [r1], rev: 3, nextCursor: 'c1' }`、第二页 `{ rules: [r2], rev: 3 }`,规则行取服务端列举行的形 `{ behavior: 'allow', rule: 'Bash(git status)', scope: 'global', tool: 'Bash', match: 'exact', command: 'git status', adds: [], source: 'user', status: 'live' }`(`r2` 换 `rule` / `command`;本包列全口只要求 `rule` / `scope` 是非空串,判据不读其余各键);`classifyRulesFailure({ status: 501 })` 两版都答 `error`,带 `errorCode: 'capability.rule_store_required'` 两版都答 `lane-unavailable`。
9692
+ - **G-M1**(本版证明,纯包层;M-1 / M-2):`modelIdentityResolvability({ engine: 'local', lanes: { processEnv: 'absent', settingsEnv: 'absent', modelCatalogFile: 'complete', followedSettingsFile: 'absent', followedProviderEnv: 'absent' }, engineAcceptsCatalogDefault: true })` ⇒ `resolvable`;`modelSetupDecision(那个结果, true)` ⇒ `proceed`。判别点:0.83.2 答 `unknown`(目录一格的 `complete` 不在闭集)。
9693
+ - **G-M2**(本版证明,纯包层;改口格):同一读数位为 `false` ⇒ `not_resolvable`;`modelSetupDecision(…, true)` ⇒ `offer_setup`,`modelSetupDecision(…, false)` ⇒ `explain_unconfigured`。判别点:0.83.2 答 `unknown` ⇒ `proceed`。
9694
+ - **G-M2′**(回归约束,纯包层):同一读数去掉位 / 位为显式 `undefined` / `'true'` / `1` / `null` ⇒ `unknown`;`modelSetupDecision(…, true)` ⇒ `proceed`。两版同答(0.83.2 上目录一格的 `complete` 不在闭集;0.83.3 上位没报 / 读不懂 ⇒ 目录这一路判不出)。措辞两版不同,见 G-M4。
9695
+ - **G-M3**(回归约束,纯包层):目录一格 ∈ {`partial`, `absent`, `unreadable`, 缺键, 表外词} × 另一来路 ∈ {`complete`, `partial`, `absent`, `unreadable`, 缺键} 的 25 格,位 `true` / `false` / 缺席三者判据与 `modelIdentityDetail` 逐字同答,且位缺席时与 0.83.2 同答;远程拓扑带位与本地 `lanes` 仍只看应答观测。
9696
+ - **G-M4**(本版证明,纯包层;M-3):103a-2 四段逐字。第一句(可解析)匹配「已配置」形(含 `supplies a model name`)且含 `separate check`;第二句(位 `false`)匹配「没配置」形(`no model name is configured`)、不匹配「已配置」形,且不含 `carries part of a model configuration` 指目录;第三 / 四段所在的判不出句既不匹配「已配置」也不匹配「没配置」形、含 `names a default model`,第三段含 `was not reported`,第四段不含而含 `gave no usable reading`;目录 `complete` ∧ 位缺席 ∧ 设置文件 `unreadable` ⇒ 判不出句同时含 `this client's settings file could not be read` 与目录那一段;目录 `complete` ∧ 位 `false` ∧ 设置文件 `unreadable` ⇒ 判不出句同时含 `this client's settings file could not be read` 与 `the local model catalog file names a default model, but the local engine is reported not to accept a catalog default`、不含 `was not reported`;位为显式 `undefined` 与键缺席逐字同句(含 `was not reported`、不含 `gave no usable reading`)。判别点:0.83.2 上目录 `complete` 各形都答 `…the local model catalog file gave no usable reading…`(不说目录里有缺省模型)。
9697
+ - **G-M5**(端侧验收;射程:终端 / 桌面端,本机引擎,宿主接本版并按本机引擎版本报位):只写模型目录文件(有一只启用的模型)、启动环境与设置里都不写模型名 ⇒ 本机引擎为服务端 7.101.0 或更新(位 `true`):首启不弹模型配置向导,引擎正常起;换回更早的引擎(位 `false`):弹向导;宿主不报位:不弹向导(`unknown` ⇒ `proceed`),引擎起不来时显示引擎自己那句错误。
9698
+ - 包层行为钉在门 `run-hooks-merged-disable-projection-test.mjs`(FS 段;FS7a = G-H6、FS7b = G-H6b,要装好的服务端包)、`run-rules-side-test.mjs`(G3t)、`run-model-identity-resolvability-test.mjs`(S8 段)。
9699
+
9700
+ ### 103d. 端上要动的读点
9701
+
9702
+ **终端**
9703
+
9704
+ - H-1:零改动即得 —— 宿主口已按来源名转交,终端自己的设置读取对 flag 来源合成启动参数文件与内联设置两处。升级后 `--settings` 里的 hooks 在引擎侧执行(G-H5);`--settings` 里的 `Stop` hook 会让显式 `--final-verify` 让位(G-H7)。
9705
+ - H-9:零改动(次序与 0.83.2 同,flag 组排在 local 之后)。
9706
+ - M-1 / M-2:接模型身份判据时,目录一格按「目录里有一只启用的、可作缺省的模型」报 `complete`(只是文件存在报 `partial` 或按实际内容判),并按终端钉的本机引擎版本报 `engineAcceptsCatalogDefault`(服务端 7.101.0 起为 `true`,更早为 `false`)。不报位 ⇒ 只用目录的用户照常进入、不弹向导(判不出),引擎起不来时显示引擎自己那句错误。
9707
+
9708
+ **网页端**
9709
+
9710
+ - R-1(建议):自带的列全口与失败分类换读本包 `listAllPersistedRules` / `classifyRulesFailure`;两口宿主对象(变量或内联字面量)直接传。🔴 改口:「规则店不在」只认机器码(103a-1),裸 501 落 `error`、如实显示原句,不再藏整面。同批删本地同名那份。
9711
+ - H-1 / H-9 / M-1 / M-2:零读点(不调 `hooksForWire()`;模型身份恒远程拓扑)。
9712
+
9713
+ **桌面端**
9714
+
9715
+ - M-1 / M-2:有本机引擎时同终端;连远程引擎时零读点。
9716
+ - H-1 / H-9:零读点(不调 `hooksForWire()`,与 §100a 同)。
9717
+
9718
+ **管理台**
9719
+
9720
+ - 零读点。
9721
+
9722
+ **验收方**
9723
+
9724
+ - 按 103c 各格;按「目录一格报 `complete` ⇒ 一律 `unknown`」「请求体设置来源只含四源」断言的判据按 103a′ 改锚(「请求体设置来源托管在前」的判据照旧成立)。
9725
+
9726
+ ### 103y. 🔴 三端升级必读(固定段式)
9727
+
9728
+ 1. **换钉 `^0.83.3` 之前**:无前置编译改动(纯放宽:`HookSettingsSource` 多一员、目录一格闭集多一词、读数多一个可选位、列全口入参放宽为「`list` 必填、其余四口可选」、多一个具名型)。🔴 例外:按 `HookSettingsSource` 或 `ModelIdentityLanes['modelCatalogFile']` 做**穷尽**分支(`switch` 带 `never` 兜底 / `Record<HookSettingsSource, …>` 表)的代码要补一臂(今天检索未见这类读点)。可观察变化:① 宿主设置口交 flag 来源时,那一源的 hooks 上请求体(此前不上);其中的 `Stop` hook 会让显式 `--final-verify` 让位(`resolveHeadlessFinalVerifyDetail` 答 `offReason: 'stop-hook'`,G-H7);② 请求体上设置来源 hooks 的次序不变(managed 在前),flag 来源的组排在 local 之后;`settingsDropped` 与开机清单里 flag 来源的行排在 local 之后;③ 设置口对不认识的来源名抛错的宿主,每轮多一行调试(建议返回 `null`);④ 模型身份:目录一格报 `complete` 的读数,报位 `true` 由 `unknown` 变 `resolvable`、报位 `false` 由 `unknown` 变 `not_resolvable`(别的来路判不出时仍 `unknown`,措辞点名目录);没报位(含值为 `undefined` 的键)仍 `unknown`,措辞改为点名目录 —— 今天没有端报这一格 `complete`。
9729
+ 2. **逐面**:终端 —— H-1 零改动即得、H-9 次序不变;接模型身份判据时按 103d 报目录一格与位。网页端 —— 规则列全口与失败分类建议换读本包,「规则店不在」改为只认机器码;其余零读点。桌面端 —— 有本机引擎时模型身份同终端;hooks 两行零读点。管理台 —— 零读点。
9730
+ 3. **成文改口**:见 103a′(作废 / 改读 / 新增 / 不变);已发段(§93、§100、§101、§102)不回改,以本段为准;§7 P-43 随版改。
9731
+
9732
+ **包侧缺口:** hooks —— ① flag 来源按宿主交来的一份读,不分启动参数文件与内联设置;宿主只交文件那份时内联设置里的 hooks 仍到不了引擎(KL-124)· ② 设置来源之间不去重,同一条 hook 写在两个来源里请求体上出现两次(本包按来源逐份拼接、不做内容去重;KL-125)· ③ 宿主报的启动模式位 `suppressedByStartupMode`(安全 / bare)只筛插件 hook,设置来源(user / project / local,本版起含 flag)在这一位下不收窄、照发引擎(KL-128)。规则 —— ④ 列举口第一页因过滤 `scope` 读不出形回的 `request.query_invalid` 落 `cursor-stale`,列全口不重试、原样交出;按「重试」提示对这一形没有用(KL-126)· ⑤ 失败判官只留 `status` / `errorCode` / `message` / `retryAfterSec` / `committed` 几格,引擎回体里的其余机读细格停在 wire 上(同 §83y ④)。模型身份 —— ⑥ 宿主不报 `engineAcceptsCatalogDefault` 时只用目录的配置答 `unknown`(不弹向导);位由宿主按自己钉的引擎版本判,本包不按版本号判 · ⑦ 目录一格 `complete` 不答「那只模型在本机能不能服务 / 网关认不认那个名」,配置中心下发的目录在启动预算之后才到的,启动时算不在场(KL-127)。 拼接序 —— ⑧ managed 在前时,`PreToolUse` 上排在 managed 之后的非 managed hook(设置来源与插件注册的组)能在 managed 放行之后改写输入,managed 的守卫看到的是改写前的输入(与 0.83.2 同);反过来把 managed 排到最后,会被引擎 hook 执行器的每事件墙钟预算、每事件模型条目上限与上下文总帽挤掉(不执行、调用照常)。两种次序在逐条执行的执行器上都有绕过;真正的解在引擎侧(请求体标出 managed 组、为它预留预算与上限、按最终输入执行 managed、因预算或上限没执行的同步条目按拒绝处置),本包届时按新契约标出 managed 组(KL-129)。
9733
+ ```
9734
+
9735
+ ---
9736
+
9602
9737
  ## §102 🆕 0.83.2(2026-09-26)审批卡一族三件 —— 常驻姿态下的放行谓词 `askSurvivesPosture`(CC-193)+ 卡上「强制位站在哪一个词上」`mandate` 与读口 / 措辞 + 通告码册 +2(CC-195)+ 停泊卡带出身词(CC-196)—— 与后台子代「缺席行」判定与措辞归包(CC-194)(patch;根公面 +19 名,1254 → 1273〔`askSurvivesPosture` / `readApprovalMandate` / `APPROVAL_MANDATE_WORDS` / `isApprovalMandateWord` / `approvalMandateDetail`;缺席行 3 常量 + 11 函数〕;公面类型 +13;`ApprovalCardRequest` / `ToolApprovalFrame` 各 +1 可选键 `mandate`;帧键镜像 30 → 31;`ENGINE_NOTICE_CODES` 71 → 73;开发依赖引擎 `~7.32.0`;零投影臂;peer sdk 地板 `>=11.3.0` 不动)
9603
9738
 
9604
9739
  > **patch**,四件同发(本节按 0.83.2 的读法写;若与本版发布帖不一致,以发布帖为准):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/client-core",
3
- "version": "0.83.2",
3
+ "version": "0.83.3",
4
4
  "description": "Client-side session runtime shared by every sema human client (TUI / web / desktop): sema wire frames (AgentEvent) -> CC session vocabulary (SDKMessage) with dual-plane output (transcript/chrome), deterministic transcript ids, lane discipline as a type, and the notification/dedup ledgers. Every CC-skin shape is collected here so the wire itself stays neutral. Renamed from @sema-agent/wire-cc-adapter (0.1.x).",
5
5
  "license": "MIT",
6
6
  "type": "module",