@sema-agent/client-core 0.65.1 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,11 +19,11 @@
19
19
 
20
20
  | 项 | 值 | 真源 |
21
21
  |---|---|---|
22
- | 本包 | `@sema-agent/client-core` **0.65.1**(本批发布版 = patch:内容批 6d04995,B-087 通知腿判重次序 + B-088 裸 `usageMissing` 帧发臂,test [6961] 对抗复审轨两处,零新键零 BREAKING;0.65.0 两半场十件见 §30a–§30n(🔴 0.65.0 有 BREAKING = 熔断族公面 clean-cut);`CHANGELOG.md` `## 0.65.1(2026-09-11)`;bump 与冻结账两阶段由发包批做) | `package.json` `version` |
22
+ | 本包 | `@sema-agent/client-core` **0.67.0**(本批发布版 = minor:内容批 df6b2dc,core 7.14.0→7.16.0 提货七件 F-1…F-7,🔴 七条 BREAKING(分类器卡面族 clean-cut、`unresolvable`→`ancestor_marked`、audience 换档、`classifierStatusOf` 第二参语义),详见 §32a–§32z;0.66.0 见 §31;`CHANGELOG.md` `## 0.67.0(2026-09-12)`;bump 与冻结账两阶段由发包批做) | `package.json` `version` |
23
23
  | peer:wire 契约 | `@sema-agent/sdk` **>=8.4.0**(value-level,非 type-only;**0.60.0 抬版**,四条硬理由见 §24a 与 `scripts/run-sdk-floor-test.mjs` 的 `FLOOR` 注;上一次是 0.59.0 的 `>=8.3.0`)。🔴 支持窗同批收到 **engine ≥7.64.0**:sdk 8.4.0 与 7.63.0 及以前的 wire **不同窗** | `package.json` `peerDependencies` |
24
24
  | peer:会话词汇表 | `@sema-agent/agent-types` **>=0.2.0**(type-only,零运行时) | 同上 |
25
25
  | runtime dep | `diff` ^9.0.0(**唯一**一条;portability 门按**等值**钉死) | `package.json` `dependencies` |
26
- | 公开导出面 | **928** 个运行期符号(+ 44 个测试钩;= 工作树当下的值 = **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`/`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.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` —— **别手抄进别处,以该文件为准** |
26
+ | 公开导出面 | **934** 个运行期符号(+ 44 个测试钩;= 0.67.0 发布版的值 = 相对 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`/`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.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` —— **别手抄进别处,以该文件为准** |
27
27
  | 常驻门 | 以 `scripts/gates-manifest.json` 的 `suites` 长度为准(**本档不抄这个数**) | `scripts/gates-manifest.json`;`npm test` 的名单等值门与它逐名对账 |
28
28
  | 沿革档 | 0.29.0 起建 `CHANGELOG.md`;更早批次记账在 `src/index.ts` 文件头 + `docs/REFACTOR-LEDGER.md` | — |
29
29
 
@@ -111,7 +111,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
111
111
 
112
112
  ## §2 公共导出面地图(按域)
113
113
 
114
- > 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**928** 项)。
114
+ > 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**934** 项)。
115
115
  > 本节**不逐名抄**,只给「域 → 承重导出 → 用途 → 实现锚」。承重导出 = 一个端为了让这个域干活
116
116
  > **必须**直接调到的那几个符号;其余是它们的类型、变体与辅助位。
117
117
  > 单一入口:`import { … } from '@sema-agent/client-core'`(`exports` 只有 `.` 一个;
@@ -135,16 +135,16 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
135
135
  `WorkflowsGateUnknownDenial` 四形**不在**基线里,`src/selfOrchestrationDenial.ts` 对基线贡献
136
136
  **4** 项运行期导出(三个函数 + `SELF_ORCHESTRATION_RETRY_WITHOUT`)。
137
137
 
138
- 928 项的内部构成(帮助端估读表大小):**283** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
138
+ 934 项的内部构成(帮助端估读表大小):**285** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
139
139
  (矩阵、键集、env 名、锚串)而非可调用物;**5** 项是 PascalCase 运行期值
140
140
  (`ControlRouter` / `ControlSafetyError` / `HitlBridge` / `HitlSafetyError` / `DecideTransportRetryExhaustedError`);
141
141
  **41** 项是 `*For(sessionKey, …)` 的 per-session 变体(§6;其中 `engineNamespaceKeyFor` 是命名巧合 —— 参数是 baseUrl 不是 sessionKey,见域 14)。
142
142
 
143
- ### 2b. 域图(16 域,逐域计数之和 = 928)
143
+ ### 2b. 域图(16 域,逐域计数之和 = 934)
144
144
 
145
145
  | # | 域 | 名数 | 承重导出 | 用途 | 实现锚 |
146
146
  |---|---|---|---|---|---|
147
- | 1 | **适配内核(下行主链)** | 43 | `adapt` · `createWireToCcAdapter` · `runStream` · `eventToSdkMessage` · `terminalToSdkResult` · `TERMINAL_NOT_SUCCESS_STATUSES`/`isTerminalNotSuccess`/`TERMINAL_STATUSES`/`isTerminalStatus`(L-215② 终局词汇的**单铸谓词** —— `blocked` 是 agent 自报终态,`suspended`/`needs_review` 刻意不在表里,详见 §30j) · `turnUsageToModelUsage` · `isRunStreamActive` · `ADAPTER_DIVERGENCES` · `readRunTerminal` / `runTerminalCode` / `runTerminalGateKind` / `runTerminalGateToolName` / `isReviewPark` / `REVIEW_PARK_GATE_KINDS`(0.60.0 / engine ≥7.64.0:一次 run **怎么结束的**唯一读器 —— 终局从八个平面键换成一条带标因由 `terminal`,四臂 + `unknown` 防御臂 + `plane` 两代字节标;🔴 不认识的终态词绝不折成成功、本包不提供「因由→五词 status」的兼容投影,详见 §24b)| 引擎 SSE `AgentEvent` → 端要渲的**双面输出**:transcript(`SDKMessage`)+ chrome(瞬态 `ChromeEvent`)。**本包存在的理由** | `src/adapt.ts`、`src/adapt/{arms,wireShapes,panelTasks}.ts`(经 `adapt.ts` 再导出)、`src/adapter/runStream.ts`、`src/adapter/downstream/*`、`src/adapter/types.ts`、`src/runTerminal.ts` |
147
+ | 1 | **适配内核(下行主链)** | 44 | `adapt` · `createWireToCcAdapter` · `runStream` · `eventToSdkMessage` · `terminalToSdkResult` · `readRunCostFacts`(0.66.0:终局成本事实的**唯一读器** —— `TaskStats.costBreakdown` / `nested` 逐键窄读 + 对账三段(own/nested/compaction)与两个「没定价」判别位;终帧的两个超集键与 chrome 臂 `run_cost_reconciled` **共用它**,两面不会各算各的,详见 §31c)· `TERMINAL_NOT_SUCCESS_STATUSES`/`isTerminalNotSuccess`/`TERMINAL_STATUSES`/`isTerminalStatus`(L-215② 终局词汇的**单铸谓词** —— `blocked` 是 agent 自报终态,`suspended`/`needs_review` 刻意不在表里,详见 §30j) · `turnUsageToModelUsage` · `isRunStreamActive` · `ADAPTER_DIVERGENCES` · `readRunTerminal` / `runTerminalCode` / `runTerminalGateKind` / `runTerminalGateToolName` / `isReviewPark` / `REVIEW_PARK_GATE_KINDS`(0.60.0 / engine ≥7.64.0:一次 run **怎么结束的**唯一读器 —— 终局从八个平面键换成一条带标因由 `terminal`,四臂 + `unknown` 防御臂 + `plane` 两代字节标;🔴 不认识的终态词绝不折成成功、本包不提供「因由→五词 status」的兼容投影,详见 §24b)| 引擎 SSE `AgentEvent` → 端要渲的**双面输出**:transcript(`SDKMessage`)+ chrome(瞬态 `ChromeEvent`)。**本包存在的理由** | `src/adapt.ts`、`src/adapt/{arms,wireShapes,panelTasks}.ts`(经 `adapt.ts` 再导出)、`src/adapter/runStream.ts`、`src/adapter/downstream/*`、`src/adapter/types.ts`、`src/runTerminal.ts` |
148
148
  | 2 | **seam 公共契约** | 2(其余为 type-only) | `CHROME_ARMS` · `deriveTranscriptId` | 公共词汇 + **id 确定性不变量**(同一条流重放 ⇒ 同一串 id)。`CHROME_ARMS` = 端「我要消费哪些 chrome 臂」的对照清单 | `src/seam.ts` |
149
149
  | 3 | **HITL 决断卡链**(§4/§5 主战场) | 167 | `makeHitlCanUseTool` · `HitlBridge` · `findPendingForTask` · `readDecideReceipt`/`decideAcceptedNotResolved`/`decideRefusalFromError`(B-070:`/decide` 200 = **投递受理**不是「门已解决」;`executionOutcome` 缺席 = 未知,详见 §30h) · `HitlSafetyError` · `bridgeAskUserQuestionGates` · `surfaceToolApprovalFrameAndRespond` / `surfaceFsApprovalAndDecide` · `readToolApprovalRespondAck` · `installApprovalCardPort(For)` · `installHitlHostSurface(For)` · `armPlanReviewApproval` · `reopenPlanReviewCard` · `decidePlanReview` · `startApprovalsFeed` · `pendingRowIsOwnedByThisSession` · `approvalCallKey`/`liveFrameCallKey`/`planReviewQuestionId` · `registerArmedGateFor`/`wasGateArmedFor`/`clearArmedGateFor` · `waitForGateArmed(For)`/`onGateArmed(For)`/`gateArmedWaitMs`(#244 F1 呈现回执事件源) · `planReviewArmedKey(For)`/`notePlanReviewAnswered(For)`/`notePlanReviewAnsweredIfDecisive(For)`(A-024.4 plan 呈现分代) · `toolEndOutputText` · `isAskTool` · `waitForParkRowBirth` · `classifyAskParkRows` / `askParkRowArm` / `classifyAskParkChainFailure` · `readDecisionNoteAudit` / `decisionNoteAuditLine` · `resumeRunningOptions` / `resumeChoiceFromLabels` · `persistedRulesLaneAvailable`/`persistedRulesGovernanceAvailable` · `classifyRulesFailure` · `listAllPersistedRules` · `classifySkippedReason` · `readRulePersistOutcome`(#244 F2:persist-ack 读口与 `readToolApprovalRespondAck` 合成一处) · `parseLocalAllowRule`(durable 腿本地落规则窄化骨架,谓词经 `LocalAllowRuleDeps` 注入) · `readToolApprovalRespondRefusal`(#225 件5,0.42.0:respond 抛错的结构化原文读口 —— 三位各自防御读、各自缺席不铸、**三位皆缺席时整只返 `undefined`**;原样交还零加工,UNTRUSTED-for-display)· `installEditedRuleTextPrechecker` / `hasEditedRuleTextPrechecker` / `precheckEditedRuleText`([5076] 转出口,0.42.0:core 5.57.0 `precheckEditedRuleText` 的**端口注入形** —— 类型面 + 注入口 + 诚实缺席读口。🔴 **不是** value 级 re-export,理由见 §7 缺口 **P-34**;未装 ⇒ 返 `undefined`,绝不编一个 `{ok:true}`)· `surfaceRuleArmNotSent` / `RULE_NOT_SENT_WARN_TEXT` + `surfaceRuleArmRejected` / `RULE_NOT_SENT_REJECTED_WARN_TEXT`(#334,0.43.0:人在卡上按下的「不再询问」被整条丢弃时的诚实告知——**两条刻意分开**:前者=**引擎能力位未确认**(换台引擎/等探测就好),后者=**这次选择没过包内表核/互斥核**(表外文本/坏下标/两臂同场,换引擎也不会变) —— 编辑臂 `respondFreeFormRules` 与批臂 `respondBatchRuleOffers` 两条同形存量共用一条,与 `surfaceRememberNotApplied` 同族纪律:决断照送、只是规则没存,静默丢掉用户明确意图 = 让人以为功能坏了)· `projectCrashConverged`(L-38,0.49.0:`/v1/approvals` additive 键 `crashConverged` 的分桶投影 —— 崩溃收敛的孤儿审批读面,**缺席 ≠ 空数组**、分桶恰一个合取、坏行丢弃并计数,详见 §12;同批把 `ApprovalsResourceLike.list()` 的返回位 additive 放宽成 `ApprovalsListEnvelope`,老形 `{pending}` 仍可赋值)· `readRuleOffers` / `readRuleOfferSupply`(L-103/[C228],0.57.0 additive 导出:「不再询问」候选两代 wire 键的窄读器**公面化** —— 此前只经卡端口出包,不走卡端口架构的宿主只能自己重铸一把,而它承载的是兑付安全判据(原始下标不前移/逐条丢坏/闭集 kind/两代取舍序),详见 §20)· `RULE_OFFERS_ABSENCE_REASONS` / `DENIAL_LIMIT_KINDS`(0.59.0 / sdk 8.3.0 提货:`ruleOffersAbsence` 三词与 `denialLimitFallback.limit` 二词的**运行期**闭词表再导出 —— 与 0.58.0 那三张同一条纪律:端拿它做判定别再手抄字面量。⚠️ **本包自己不拿这两张表做窄读判定**(两处都按开集透传,词表属主是 core、server 已按闭集拒过),再导出只是给端的 `switch` 一份可数的表,端仍必须带 `default` 臂,详见 §23a)· `DecideTransportRetryExhaustedError`(Inkglow-1085 P0a:decide 出站瞬断重试耗尽的 typed 判别 —— HitlBridge 内建单次退避重试,耗尽走重呈臂不判死 turn;端一般只消费行为,不需要 instanceof) · `gateOutcomeOf` / `isDeniedGate` / `gateDeniedBy` / `gateApprover` / `isApprovalWindowExpiredGate` / `isDenialLimitAutoDeniedGate` / `isParkSlaExpiredGate` / `isHumanSettledGate`(0.60.0 / engine ≥7.64.0:`tool_end.gate` 整条门记录的窄读器 + 判定谓词 —— 取代退役的四个正交词 `settledBy`/`resolution`/`autoDenied`/`approver`。🔴 **判定归包**:「是不是审批窗自己走完的拒绝」旧形上是端各自拼的两键合取,而三条窗词现在分得开、合并读回去等于把刚修好的判别力扔掉;⚠️ 公面型一律带 `View` 后缀 —— 本文件的 `GateOutcome`(决断腿结局)与 sdk 的 `GateOutcome`(引擎门记录)**同名不同义**,详见 §24c)· `isGateParkedToolEnd`(「这次调用没在这里结算」的**第二形**谓词:gate 缺席 + `errorCode:"gate.parked"`;端判这件事必须与 `isApprovalWindowExpiredGate` **两形合读**) · `readWireErrorCode`(B-037 候包件②:decide/取件失败上引擎 wire 机器码的单源读口,结构视图读不 `instanceof`;与本包铸的 `code` 是两个命名空间,详见 §24g)| suspended→decide→resume 环。🔴 **D-1 两元组 verbatim 回显**是字节级断言的安全不变量,端**不许重实现它的任何一段**。🔴 键空间边界(web [C1] d3 拦截):`gateIdentity` 四常量两函数只覆盖 HITL questionId/callKey 空间;seat 的 `TOOL_PERMISSION_REQUEST_ID_DOMAINS`(`plan:` 等)是另一键空间,**两者绝不合并**(合并=座位校验器静默拒全部 plan-review 卡) | `src/hitl/hitlBridge.ts`、`toolApprovalWire.ts`、`askGateWire.ts`、`planReviewWire.ts`、`hitlHostSurface.ts`、`gateIdentity.ts`、`armedGateRegistry.ts`、`parkOwnership.ts`、`parkResolver.ts`、`approvalsFeed.ts`、`frameRouter.ts`(**只挑名导出** `toolEndOutputText`/`ENGINE_ABORT_TOOL_RESULT`/`isAskTool`/`HITL_REJECT_MESSAGE`/`HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE`)、`parkRowBirthWait.ts`、`approvalDecisionNoteAudit.ts`、`askParkRowRouting.ts`、`resumeRunningCard.ts`(#265 上收的判定层)、`persistedRulesWire.ts`、`localAllowRule.ts`(#244 F2 规则侧)、`crashConverged.ts`(L-38 崩溃收敛读面)、`src/gateOutcome.ts` |
150
150
  | 4 | **子代 wire + 面板侧信道台账** | 87 | `tailEngineSubagent` · `installSubagentActivitySink` · `installSubagentTailMetaSink`(#280 件2:tail meta 帧发布口,`contentFrames` 判别位载体)· `stopEngineTask` + `classifyTaskStopConflict` · `fetchEngineSubagentReport` · `steerEngineSubagent`(0.32.0 未发布 #280 件A:additive 第三参 `childTaskId` —— 端有行上下文时**应当**传,传了就走「台账优先 / 缺席即诚实缺席 + `noteBgOwnerAbsence` 留痕」的 Q3 口径,与 tail·taskOutput·subagentOutput 三腿同姿势、与孪生 resume 腿共用同一个 `resolveOwnerRunId` 判据;**不传**则逐字维持旧行为=回落在飞 run)· `resumeSettledSubagent` + `resolveSubagentResumeContext` + `resolveOwnerRunId` + `classifySubagentResumeFailure` + `subagentResumeAvailable`(#242 批 2 A-028.7:resume 判定半场上收,与 steer 孪生同居;取址三态 = 台账有行用行值 / 指名了行但台账缺席则**诚实缺席绝不回落在飞 run** / 没指名行才回落。出路文案归端)· `recordSubagentOwnerFromProgress` + `getBgParentRunOwner`(A-028.6:「子代 → 宿主 run」**单表**,宿主 run 必须由持 stream-local 值的调用方显式传入,包内绝不从 `activeEngineRunId()` 推断)· `noteBgOwnerAbsence`(#242 批 3 [4000] Q3=B:tail/taskOutput·taskStop/subagentOutput 三腿台账缺席即诚实缺席**绝不回落在飞 run**,缺席 warn 留痕每 (腿,taskId) 一条)· `clearBgTerminalFacts`(#242 批 3 扫码修:复活=新周期,旧周期终态事实作废——fleetLedger 复活两腿按尾段清账,factsAccepted 方向核不再拿上周期终态当先例)· `auditRetainWithoutWake`([4000] Q5:引擎宣示 `subagentResume` + 本端在付 `retainSubagentSessions` + 端未实现 `wakeSubagent` ⇒ 响亮一条;`CLIENT_VERBS.wakeSubagent` 维持 fail-soft)· `subscribeSubagentContent` · `subscribeEngineAgentPanel` · `publishQuestionFrame` / `respondToQuestion` · `configureSubagentContentStore` / `subagentContentStoreConfig` / `SUBAGENT_CONTENT_STORE_DEFAULTS`(0.62.0:子代内容账本的**字节预算** —— 此前只有条数帽而单条无上限,一条 base64 工具结果就能让一个子代槽吃到十几 MB;越限从最早的内容开始丢并留一条可渲染的 `truncated` 记录,总帽淘汰整条最久未用的账本。配置面 fail-loud,详见 §26②)| 驱动与观测委派子代;经 module 级台账喂活体 agent/task 面板。全部**能力位 gate**(§5b) | `src/subagent/*.ts`、`src/subagentContentStore.ts`、`src/engineAgentPanelStore.ts`、`src/engineInlineTaskStats.ts`、`src/engineToolLabelStore.ts`、`src/liveQuestionStore.ts` |
@@ -159,7 +159,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
159
159
  | 13 | **座位 IPC 契约** | 34 | `LOCAL_SESSIONS_SPEC` · `SEAT_METHOD_NAMES` · `SEAT_EVENT_TYPES` · `isLocalSessionEvent` · `isToolPermissionRequest` · `toolPermissionRequestId` · `SEAT_VALIDATOR_KEY_COVERAGE` · `SEAT_SEND_MESSAGE_KEY_ORIGINS`(0.62.0:座位载荷**逐键出身**登记 —— 每个位要么写明转投哪个引擎请求位、要么写明为什么不上 wire;常驻门对**装在盘上的** sdk 型面逐名核,详见 §26③)| desktop↔web 座位 IPC 契约的**单一真源**(此前两边各一份、名字零重合 ⇒ 编译器永远不会告诉你它们漂了)。🔴 加 verb 忘了加 `LOCAL_SESSIONS_SPEC` **不报错**:preload 不注册 channel、渲染端读到 `undefined` | `src/seatContract.ts`(**零 import**,纯类型 + 常量 + 纯谓词)。🔴 **证据等级标注(0.42.0,test [5087] 的「语料**种类**缺口」/ cli [5088] 认领件)**:该文件里所有以「CC 如何如何」为形的断言(`212 methods` / `854-channel census` / 方法名逐字保留 / `fQe` 逐字段对照 / 一切 `.vite/build/index.chunk-*.js` 坐标)**证据等级 = 桌面 unpack,本地语料库不可复验** —— 本仓手边可复验的参照语料**只覆盖终端 CLI 形态**的静态产物,拿它去 grep 桌面壳里的符号只会零命中,而零命中在这里**既不证真也不证伪**。复核这些断言**不得**拿本仓语料当反证 |
160
160
  | 14 | **宿主端口与会话槽** | 26 | `installHost` · `installHostFor` · `hostPortMisses(For)` · `DEFAULT_SESSION_KEY` · `hostEnv` · `unrefTimer` · `parseLocaleTag` / `pickUiLanguage`(#244 F4 族D A-028.20:locale tag 手术单源 + UI 语言判定;与 `resolveRegionHint` 双出口成文 —— 语言偏好域 en/zh ≠ 地址可达域 cn/intl/unknown,`zh-Hant` 前者 zh 后者 intl 是设计)· `engineNamespaceKeyFor` / `mergeSessionMapRecord` / `mergeEngineEntry`(A-028.12:会话 id 映射单一键形 + merge 判定;存储经 `SessionMapStorePort` 归端 —— cli 文件锁/原子写,web localStorage)| 进程/端级装配层(settings/fs/queue/timers/session/log/probe),与 per-turn 的 `AdapterContext` **分层**。头注的判定规则:**这个能力每 turn 都会变吗?** 会 ⇒ `ctx`;不会 ⇒ `installHost` | `src/host.ts`、`src/hostEnv.ts`、`src/sessionSlot.ts`、`src/unrefTimer.ts`、`src/env/{localeGeo,localeTag,uiLanguage}.ts`、`src/sessionMap.ts` |
161
161
  | 15 | **控制面与传输** | 113 | `ControlRouter`(+ `ControlSafetyError`)· `makeEngineWireClient` + `resolveWireAuth` · `installEngineWireTarget` · `diagnoseSseIdleTear` / `isSseIdleError` · `attemptActiveRunSelfHeal` + `activeRunBusySignal` + `activeRunSelfHealRow` / `activeRunBusyHeadlessRow` · `kickEngineCapsProbe` / `engineCapTrue` / `invalidateEngineCaps(baseUrl, probe?)`(#307 S25:引擎温切后的 caps 生产失效口 —— kick 自带幂等闸,同 baseUrl 重启后不显式失效就永远读到旧引擎那一版能力位;调用方 = 壳的 respawn/restartEngine。🔴 **推荐两参形**:第二参给替代探测则「推进代际 + 注册新探测」在同一同步块内完成,失效与下一次 kick 之间那个「等待者读到未判」的窗按构造不存在;单参形保留给「只丢缓存、这一刻没有替代探测」的调用方,那种情形下读到未判是诚实结局) · `engineCapValue`(S-131,0.59.0:能力位的**四态**通用读口 `unobserved`/`not_reported`/`null`/`value` —— 既有三口把四种「读不出」全折成 fail-closed 一档,对**放行**问题是对的、对**读面/诊断**问题是错的:`null`(引擎明确说没有,正面事实)会与「老引擎不报」「还没探到」在屏上同形。`value` 位刻意不做形校验,形归各能力位自己的窄读器,详见 §23b)· `projectSqlEngineCapability` / `observedSqlEngine` / `noteEngineCapsForSqlEngine` / `forgetSqlEngineReading` / `sqlEngineDoctorDetail`(S-131,0.59.0:`Capabilities.sql`(server ≥7.60.0)的四态读面**从壳侧上收** —— 归层债,0.58.0 时它长在壳里正是因为包侧没有嵌套对象读口。🔴 **导出名与壳侧那份逐字同名 = drift-lock**;`txnMode: null` 是铸点域内的合法值不是畸形;换代失效口清成未观测而不是留旧值,详见 §23b)· `mapBrainStatusToRetry` · `waitForClaimRelease` + `CLAIM_RELEASED_STATES` / `CLAIM_HELD_STATES` · `atMostOnceFailureClass` / `readSteerDelivery` · `clearRunningChoiceOffer`(Inkglow-1085 P0b①:「Do nothing」登记的清口 —— 端的「重新打开操作菜单」入口;登记在场时 attemptActiveRunSelfHeal 不整卡重弹,not-parked 结局带 `alreadyOffered: true` 判别位,端据此降级渲一行)· `INTERACTIVE_WAY_OUT`(默认出路串单源)· `engineSessionParamFor`(design/285 批 0:`?session=` 派生的 **per-key** 形 —— `hostSessionFor(sessionKey)?.currentSessionId()` + [1501] 空串归一;零参 `engineSessionParam()` = 默认槽兼容层,取值链逐字等价)· `normalizeWirePrincipal`(A-028.10:principal 在场性 trim 原语 —— 全空白=缺席不发头,engineWireTarget 两臂/makeEngineWireClient/壳 livePrincipal 同尺)· `readSessionMemoryStatus` / `classifyMemoryStatusFailure` / `readCaptureOptOut` / `readLastCapture`(S-53 会话记忆姿态读面,0.48.0:失败分诊**码优先**——两个 404 分道 `not_found.session` / `not_found.route`,无码 404 不猜落 failed;五键逐键缺席语义两个合读器,`lastCapture` 三态的判别材料是 `committedCount` 不是本键;IO 归宿主注入 `MemoryStatusClientLike`,详见 §11) · `classifyTurnWireError` / `isWireTransportError` / `isPreStreamDrainingReject` / `isResumeAtRejection` / `drainingRetryDelayMs` / `scenarioDenyFromError` + `WIRE_NETWORK_ERROR_PATTERN`(A-028.11/.13:turn 错误分型判定半场,人话文案与渲染归端)· `resumeRetryLaterFromError`(L-102,0.57.0:resume 族**时间性拒绝**二码的判型半场 —— 这一族里唯一**带得出「等多久」**(`retryAfterSec`)的两个码。🔴 闭集**不是**「哪些码可以等」的名单:同族 `resume.row_recycling` 同样可等(窗口自清)只是没有秒数 ⇒ 本读口返回 `null` 只意味着没命中这两码,详见 §21) · `projectWriteProtectionCapability` / `observedWriteProtection` / `noteEngineCapsForWriteProtection` / `forgetWriteProtectionReading` / `writeProtectionDoctorDetail` / `projectWriteProtectionPosture` / `writeProtectionPostureDetail`(S-138,0.60.0:`Capabilities.writeProtection` (engine ≥7.63.0)的**四态**读面 + operator 面行表 —— 与上面 S-131 那一格**同构同纪律**。🔴 三位刻意不合成一个布尔;`not_reported` **不是**「这台部署没有写保护表」(座位缺席恰是缺省表在岗);逐行 name/kind 走**最小披露**只上 operator 面,详见 §24e)· `projectReadFacePosture` / `readFacePostureDetail` / `readFaceDisagreement`(S-167,0.61.0:operator 面 `diagnostics.wiring.readFace`(engine ≥7.65.0)的窄读器 —— 与上面S-138 那一格**同构同纪律**。🔴 三句「答不出来」逐字互异且没有一句等于「没有 READ 档」;`source` 按开集读;与租户面 `capabilities.readFace` 刻意不合流,只带一个纯比较函数,详见 §25)| 上行通道的**监管**半场(submit / steer / kill / 队列命令定序)+ 传输构造、caps 探测、SSE 断流分诊、**409 active-run 自愈** | `src/controlRouter.ts`、`steering.ts`、`sseIdleTriage.ts`、`retryStatus.ts`、`diagnostics.ts`、`engineWireSdk.ts`、`engineWireTarget.ts`、`src/principalWire.ts`、`src/wireErrorTriage.ts`、`engineSessionParam.ts`、`engineCapsCache.ts`、`liveInitToolFace.ts`、`adapter/activeRunSelfHeal.ts`、`src/sessionMemoryStatus.ts`、`src/writeProtectionCapability.ts`、`src/readFacePosture.ts` |
162
- | 16 | **引擎词汇表与包自检** | 73 | `CONFIG_REFUSAL_CODES` / `isConfigRefusalCode` · `DECIDE_WORKFLOW_LANE_CODES`(+ 三个具名码;`/decide` workflow 车道,三条出路刻意不合并,详见 §30h)· `STOP_CONFLICT_CODES` · `isInterruptedToolEndCode` · `isRewindFamilyCode` · `CLIENT_VERBS` · `compensationSplitViolations` · `DELEGATION_CAP_CODES` / `isDelegationCapCode` / `DELEGATION_CONCURRENCY_CAP` / `DELEGATION_SESSION_CAP`(0.38.0 #318 件④:core 5.48.0 design/323 委派席位到限**两码,处置不对称禁合并** —— 并发帽=**可等**(兄弟结束即有位)/ 会话累计帽=**等也没用**(这条会话的配额用尽))· `CONFIG_DELEGATION_ENTRY_CAPS`(同批入 `CONFIG_REFUSAL_CODES` 识别表)· `delegationCapDispositionOf` / `MCP_SERVER_REVOKED`(0.39.0 载体到货消费件:core 5.50.0 补 `{ error: code, code }` 孪生拼法后两码真上 `tool_end.errorCode`,0.38.0「先立词不落消费分支」的已知局限自此解除;处置轴 `wait-for-slot` / `reuse-existing-or-await-reap` 机器可读(累计帽=retained-window 帐,行回收配额即回,处置=SendMessage 复用,**非**「换会话/永久耗尽」——0.38.0 段该句系勘误),未知 `delegation.*` 码 ⇒ `undefined`;`mcp.server_revoked` = 操作员 mid-session 吊销 server 后的工具面本地闸(被吊销的 server **名**今天不过 wire 境:detail.server 是进程内位,抬升腿只 lift code——归因渲染候 core 补 typed detail,已点名);载体门 = engine-vocab G3 腿锚 core dist 铸点)· `CAPABILITY_SELF_ORCHESTRATION_REQUIRED`(S-81,server 7.57.0:提交面的 selfOrchestration 准入拒绝码。🔴 **复用码** —— 与其它 `capability.*` 501 同体形而处置不同,消费点必须按**恰等**判、绝不放宽成前缀判;判型与「去键重发一次」归 `src/selfOrchestrationDenial.ts`,详见 §13) · `GATE_PARKED_ERROR_CODE`(0.60.0:「门把这次调用 park 了」的机读码单源 —— `frameRouter` 的连坐/中断判据与 `gateOutcome.isGateParkedToolEnd` 读同一个常量;真机黑盒直证 park 短路帧上**没有 `gate`**,这个码是那一形唯一的信号,详见 §24c)| 三端分臂共用的**去字面化** `errorCode` 词表(病根正是三端各抄一份字面);编译期 verb 闭合门;搬迁补偿登记表 | `src/engineErrorCodes.ts`(计数以 `scripts/public-export-baseline.json` 为准,别手抄;A-028.11/.13 补 `DRAINING_ERROR_CODE`/`SCENARIO_NOT_ALLOWED_ERROR_CODE`/`RESUME_AT_ERROR_CODE_PREFIX`;#318 件④ 补 `delegation.*` 族四位 + `config.delegation_entry_caps`;0.39.0 补三新码消费件三位);S-81 补 `capability.self_orchestration_required` 一位;L-102 补 `resume.*` 时间性拒绝二码 + 闭集 `RESUME_RETRY_LATER_CODES` 三位)、`src/classifierVerdictWire.ts`、`src/compensations.ts`、`src/clientSlice.ts` |
162
+ | 16 | **引擎词汇表与包自检** | 78 | `CONFIG_REFUSAL_CODES` / `isConfigRefusalCode` · `DECIDE_WORKFLOW_LANE_CODES`(+ 三个具名码;`/decide` workflow 车道,三条出路刻意不合并,详见 §30h)· `STOP_CONFLICT_CODES` · `isInterruptedToolEndCode` · `isRewindFamilyCode` · `CLIENT_VERBS` · `compensationSplitViolations` · `DELEGATION_CAP_CODES` / `isDelegationCapCode` / `DELEGATION_CONCURRENCY_CAP` / `DELEGATION_SESSION_CAP`(0.38.0 #318 件④:core 5.48.0 design/323 委派席位到限**两码,处置不对称禁合并** —— 并发帽=**可等**(兄弟结束即有位)/ 会话累计帽=**等也没用**(这条会话的配额用尽))· `CONFIG_DELEGATION_ENTRY_CAPS`(同批入 `CONFIG_REFUSAL_CODES` 识别表)· `delegationCapDispositionOf` / `MCP_SERVER_REVOKED`(0.39.0 载体到货消费件:core 5.50.0 补 `{ error: code, code }` 孪生拼法后两码真上 `tool_end.errorCode`,0.38.0「先立词不落消费分支」的已知局限自此解除;处置轴 `wait-for-slot` / `reuse-existing-or-await-reap` 机器可读(累计帽=retained-window 帐,行回收配额即回,处置=SendMessage 复用,**非**「换会话/永久耗尽」——0.38.0 段该句系勘误),未知 `delegation.*` 码 ⇒ `undefined`;`mcp.server_revoked` = 操作员 mid-session 吊销 server 后的工具面本地闸(被吊销的 server **名**今天不过 wire 境:detail.server 是进程内位,抬升腿只 lift code——归因渲染候 core 补 typed detail,已点名);载体门 = engine-vocab G3 腿锚 core dist 铸点)· `CAPABILITY_SELF_ORCHESTRATION_REQUIRED`(S-81,server 7.57.0:提交面的 selfOrchestration 准入拒绝码。🔴 **复用码** —— 与其它 `capability.*` 501 同体形而处置不同,消费点必须按**恰等**判、绝不放宽成前缀判;判型与「去键重发一次」归 `src/selfOrchestrationDenial.ts`,详见 §13) · `GATE_PARKED_ERROR_CODE`(0.60.0:「门把这次调用 park 了」的机读码单源 —— `frameRouter` 的连坐/中断判据与 `gateOutcome.isGateParkedToolEnd` 读同一个常量;真机黑盒直证 park 短路帧上**没有 `gate`**,这个码是那一形唯一的信号,详见 §24c)| 三端分臂共用的**去字面化** `errorCode` 词表(病根正是三端各抄一份字面);编译期 verb 闭合门;搬迁补偿登记表 | `src/engineErrorCodes.ts`(计数以 `scripts/public-export-baseline.json` 为准,别手抄;A-028.11/.13 补 `DRAINING_ERROR_CODE`/`SCENARIO_NOT_ALLOWED_ERROR_CODE`/`RESUME_AT_ERROR_CODE_PREFIX`;#318 件④ 补 `delegation.*` 族四位 + `config.delegation_entry_caps`;0.39.0 补三新码消费件三位);S-81 补 `capability.self_orchestration_required` 一位;L-102 补 `resume.*` 时间性拒绝二码 + 闭集 `RESUME_RETRY_LATER_CODES` 三位)、`src/classifierVerdictWire.ts`、`src/compensations.ts`、`src/clientSlice.ts`;**0.67.0 补锚**(这三件的导出一直计在本域,而本表此前没有它们的锚行 —— 如实补上,不是搬家):`src/gateVocabulary.ts`(`GATE_DENIED_BY_WORDS`/`gateDeniedByDetail`/`ASK_ORIGIN_WORDS`/`askOriginDetail` + 🆕 `RULE_STORE_UNREADABLE_KINDS`/`isRuleStoreUnreadableKind`/`ruleStoreUnreadableDetail`,详见 §32d)、`src/autoModeUnavailable.ts`(`AUTO_MODE_UNAVAILABLE_CAUSES` + 🆕 `CLASSIFIER_DENY_CAUSES`/`isClassifierDenyCause`/`classifierDenyCauseOf`/`classifierDenyCauseDetail`;🔴 同批**删**`classifierUnavailableOf`/`classifierUnavailableDetail`,详见 §32b)、`src/classifierStatus.ts`(`CLASSIFIER_STATUS_STATES`/`classifierStatusOf`/`classifierStatusDetail`)|
163
163
 
164
164
  🔴 **`engineErrorCodes` 的开集纪律**(该文件头注逐字):这些 `ReadonlySet` / 前缀谓词一律是**识别表**,
165
165
  回答的是「我认不认得这个码」,**绝不是**「合法码只有这些」。消费点 `switch` **必须留 `default`**,
@@ -1498,8 +1498,8 @@ CHANGELOG 0.29.0「已知局限」段与相应 JSDoc 都有成文。**别在读
1498
1498
  | **P-41** | low | 🆕 **decide 的 `currentPending` 指路键今天在标准 SDK 路径上恒缺席**(0.47.0 件②,如实登记的射程边界不是缺陷):server 的 409 `approval_stale` 臂**只在调用方回显 `checkpointToken` 时触发**(engine 7.52.1 `http/server.js` 的 `resumeCheckpoint`,`if (binding?.checkpointToken && …)` 真字节),而 sdk 的 `ApprovalDecision` 自 1.0.0 起**刻意删掉**了那一位 ⇒ 经 SDK client 的 decide 拿不到这枚 409。另:ask 腿(`GateOutcome.currentPending`)**包内无消费方** —— `GateOutcome` 是包内型、决断结局不出包;它在场的理由是**同形存量清剿**(两条 decide 失败腿一次改齐) | `src/hitl/hitlBridge.ts`(`readDecideCurrentPending`)、`src/hitl/toolApprovalWire.ts`、`src/hitl/parkResolver.ts` | 按 §4f 接:读得到就一跳重定位,**缺席时退回重拉 `GET /v1/approvals`**,绝不把缺席读成「没有别的 pending 了」。自己注入传输层(非 SDK client)的宿主今天就拿得到 |
1499
1499
 
1500
1500
  | **P-43** | med(**存量、非本批引入** —— 0.42.0 基线上逐字相同) @cli @web @desktop | 🆕 **accept-session 回退臂的错误分类比它自己的注释宽**(#363 异源复审 [high] 的**未收窄那一半**,如实登记):`allowSession` 腿先发 `approve + remember:'session'`,失败时回退一发纯 approve;那条 catch 的注释写的是「**只**兜『老 server 不识别 remember ⇒ 400 未知键』这一形」,而实际形是 **catch-all 减去三条具名再抛**(`HitlSafetyError` / `DecideTransportRetryExhaustedError` / 0.47.0 新加的『拒体带 `currentPending`』)。⇒ 一个 **404 / 5xx / 宿主自抛的无 status 错误**今天仍会被当成「老 server 不识别 remember」并**自动重发**一次纯 approve。收窄成「只认 400」是**行为改动**,不属于 0.47.0 这个 additive 批的射程 | `src/hitl/toolApprovalWire.ts`(`case 'allow'` 的内层 catch) | 端今天不需要做什么(两发都是 approve,不构成跨门的 double-act);**属主批**:下一个愿意改老引擎兼容腿宽度的批把它收窄成精确的 legacy-400,并同批给回退臂补正控/负控 |
1501
- | **P-44** | 已知缺口(0.53.0 登记;正位解在**引擎侧**)@cli | 🆕 **L-93 两选卡的 cancel 是「查了再做」,不是原子条件取消**(异源对抗复审 R2 [high] 如实登记):卡后那一发 `runs.get` 状态复证 + 开枪前那一发 `listOwnedPendingApprovals` 待决行复证,把窗口从「人看卡的任意长时间」压到「两发复证到一发 cancel」的毫秒级,**但没有关死** —— 待决行若恰在这两步之间恢复(store 恢复 / 会话重新附着),那一枪仍会落在一条**其实还能被决断**的 run 上,而 `runs.cancel` 会把它终态化。**客户端关不死它**:真正的关法是引擎侧的**条件取消**(带审批快照版本 / checkpoint 标识,条件变了回 409 且不取消),那是 wire 能力,不是壳能自造的语义 | `src/adapter/activeRunSelfHeal.ts`(`staleParkArm` 开枪前那一段的头注);§16b 四道防线 | 端照旧只在用户显式选「停掉它」时才走这条路,**卡面必须说清这是放弃这条 run**;要彻底关死,按跨仓宪法向引擎提**条件取消**(`If-Match` 形)。在那之前这条路的剩余风险是**在册**的,不是未知的 |
1502
- | **P-45** | 在册局限(**存量族**,非本批引入)@cli @web @desktop | 🆕 **「run 读到终态」不等于「claim 已经落地释放」**(同上 R2 [medium]):`waitForClaimRelease` 的判据是 `runs.get` 读回 {@link CLAIM_RELEASED_STATES} 里的终态词,而本档 §12 与 `running-settled` 臂自己记着:409 报的 claim 与 poll 口径**可以短暂相左**。⇒ `running-cancelled`(0.37.0 起)与 🆕 `stale-park-cancelled`(0.53.0)两条 `resending` 结局,理论上都可能在 claim 尚未落地释放时重发一次,代价 = **再吃一个 409**(自愈树当拍再分诊)。**为什么不单修新那一条**:两条问的是同一个问题,给它们两把不同的尺 = 同一判据两份实现,必漂;正位解是一条 **session/claim 专用读面**(今天 `DurableRunVerbs` 里没有这个动词) | `src/adapter/activeRunSelfHeal.ts`(`CLAIM_RELEASED_STATES` 头注 / `waitForClaimRelease` / 两条 `resending` 结局) | 端**不要**把 `resending` 读成「会话一定空了」——它的成文含义是「引擎报那条 run 已终结」。重发撞回 409 是**已知可能**,自愈树会当拍再分诊(不是新 bug);要更强的保证,得等引擎给 claim 读面。🔴 **文案面同形存量**:0.53.0 的 `stale-park-cancelled` 行已按这条边界改写(只说「引擎报它已终结」+ 「可能要再发一次」),而 0.37.0 的 `running-cancelled` 行仍写着「The engine confirmed it is no longer holding this session」—— 同一把尺、两种说法。**属主批**:下一个愿意动那条既有产品文案的批同步收紧(本批不动,因为它是三端在跑的现产品串,改它属行为面/文案面变更,要单独走验收与端对表) |
1501
+ | **P-44** | 已知缺口(0.53.0 登记;正位解在 **server 读写面**:cancel 两臂状态 CAS 契约明写 + 可选版本前置,S-122 车 7.73.0;core 无席 [7006]/[7007])@cli | 🆕 **L-93 两选卡的 cancel 是「查了再做」,不是原子条件取消**(异源对抗复审 R2 [high] 如实登记):卡后那一发 `runs.get` 状态复证 + 开枪前那一发 `listOwnedPendingApprovals` 待决行复证,把窗口从「人看卡的任意长时间」压到「两发复证到一发 cancel」的毫秒级,**但没有关死** —— 待决行若恰在这两步之间恢复(store 恢复 / 会话重新附着),那一枪仍会落在一条**其实还能被决断**的 run 上,而 `runs.cancel` 会把它终态化。**客户端关不死它**:真正的关法是引擎侧的**条件取消**(带审批快照版本 / checkpoint 标识,条件变了回 409 且不取消),那是 wire 能力,不是壳能自造的语义 | `src/adapter/activeRunSelfHeal.ts`(`staleParkArm` 开枪前那一段的头注);§16b 四道防线 | 端照旧只在用户显式选「停掉它」时才走这条路,**卡面必须说清这是放弃这条 run**;要彻底关死,按跨仓宪法向引擎提**条件取消**(`If-Match` 形)。在那之前这条路的剩余风险是**在册**的,不是未知的 |
1502
+ | **P-45** | 在册局限(**存量族**,非本批引入)@cli @web @desktop | 🆕 **「run 读到终态」不等于「claim 已经落地释放」**(同上 R2 [medium]):`waitForClaimRelease` 的判据是 `runs.get` 读回 {@link CLAIM_RELEASED_STATES} 里的终态词,而本档 §12 与 `running-settled` 臂自己记着:409 报的 claim 与 poll 口径**可以短暂相左**。⇒ `running-cancelled`(0.37.0 起)与 🆕 `stale-park-cancelled`(0.53.0)两条 `resending` 结局,理论上都可能在 claim 尚未落地释放时重发一次,代价 = **再吃一个 409**(自愈树当拍再分诊)。**为什么不单修新那一条**:两条问的是同一个问题,给它们两把不同的尺 = 同一判据两份实现,必漂;正位解是一条 **session/claim 专用读面**(今天 `DurableRunVerbs` 里没有这个动词) | `src/adapter/activeRunSelfHeal.ts`(`CLAIM_RELEASED_STATES` 头注 / `waitForClaimRelease` / 两条 `resending` 结局) | 端**不要**把 `resending` 读成「会话一定空了」——它的成文含义是「引擎报那条 run 已终结」。重发撞回 409 是**已知可能**,自愈树会当拍再分诊(不是新 bug);要更强的保证,得等引擎给 claim 读面。🔴 **文案面同形存量**:0.53.0 的 `stale-park-cancelled` 行已按这条边界改写(只说「引擎报它已终结」+ 「可能要再发一次」),而 0.37.0 的 `running-cancelled` 行仍写着「The engine confirmed it is no longer holding this session」—— 同一把尺、两种说法。**属主批**:下一个愿意动那条既有产品文案的批同步收紧(本批不动,因为它是三端在跑的现产品串,改它属行为面/文案面变更,要单独走验收与端对表) | 正位解(core [7006]/server [7007]):server 7.73.0 `GET /v1/runs/:id` +`heldBy`(=instanceId,null=无持有)/+`cancelRequested`;契约「`heldBy` 变 null 或 status 终态 = claim 释放」,`waitForClaimRelease` 届时改读 `heldBy`。
1503
1503
 
1504
1504
  ### 7c. 多会话(sessionKey)面在册局限 —— 多会话端**接之前必读**
1505
1505
 
@@ -2602,7 +2602,8 @@ interface ActiveRunSelfHealDeps {
2602
2602
  - **不承诺「重发一定成功」**:只有 `stale-park-cancelled`(引擎报那条 run 已终结)才判 `resending`;
2603
2603
  其余形一律 `not-delivered`,端不许自作主张重投。
2604
2604
  - 🔴 **两条在册边界(第二轮对抗复审登记,详见 §7b)**:**P-44** 开枪前复证是「查了再做」不是原子
2605
- 条件取消(残留毫秒级窗口,正位解在引擎侧条件取消);**P-45** 「读到终态」≠「claim 已落地释放」
2605
+ 条件取消(残留毫秒级窗口,正位解在 server 读写面的条件取消:cancel CAS 契约明写 + 版本前置,S-122 7.73.0;core 无席 [7006]);**P-45** 「读到终态」≠「claim 已落地释放」
2606
+ (正位解 = server `GET /v1/runs/:id` +`heldBy`/+`cancelRequested` additive 读面,7.73.0 [7007];到货后 `waitForClaimRelease` 改读 `heldBy` 变 null)
2606
2607
  (存量族,与 `running-cancelled` 共用同一把尺,重发撞回 409 是已知可能)。
2607
2608
 
2608
2609
  **cli / web / desktop 认领**:cli 侧接点(置位 + 两选卡)在其下一批(表态制);web / desktop **无需动作**
@@ -4620,7 +4621,7 @@ an argument」。audience 答另一问:这条事实**说给谁听**。
4620
4621
  **签名**
4621
4622
 
4622
4623
  ```ts
4623
- ENGINE_NOTICE_CODES: readonly string[] // 50 码,顺序同源
4624
+ ENGINE_NOTICE_CODES: readonly string[] // 51 码,顺序同源
4624
4625
  ENGINE_NOTICE_AUDIENCE: Readonly<Record<string, 'user' | 'operator'>>
4625
4626
  noticeAudienceOf(code: unknown): 'user' | 'operator'
4626
4627
  engineNoticeInCatalog(code: unknown): boolean
@@ -5985,3 +5986,767 @@ server 7.70.0([6927])读面同批收窄。
5985
5986
  (源码扫描零铸点)⇒ 加词对本包**零落点**。归属登记:**候 sdk 镜像**(D1 是它的到货哨兵);
5986
5987
  哪天 sdk 镜像了,D1 红 ⇒ 那一批同时铸措辞表并把 D2 退役。
5987
5988
 
5989
+ ---
5990
+
5991
+ ## §31 🆕 0.66.0 内容批(**终局真值三件**:L-192① `permission_denials` + B-068 / L-198 成本对账 + L-192② 终帧 usage 三格)
5992
+
5993
+ ### 31a. 本节速览
5994
+
5995
+ | 件 | 一句话 | 端要做什么 |
5996
+ |---|---|---|
5997
+ | ① L-192① | 终帧拒绝清单不再硬编 `[]`:被拒行逐条进 **sema 载体** `_sema_permission_denials`,CC 数组只收**三键齐全**的记录(今天恒空,上游补齐即自动填)+ 「这条清单不可声称完整」判别位 | 渲拒绝清单的端**改读 sema 载体**(壳里本地铸 `[]` 的两处退役);CC 那条 `[]` 必须与判别位**合读** |
5998
+ | ② B-068 / L-198 | `costBreakdown` / `nested` 两段投上终帧超集键 + 新增终局 chrome 臂 `run_cost_reconciled`;`total_cost_usd` **语义零改** | 成本面接**终局对账**(own / nested / compaction 三段);不接 ⇒ 子代与压缩两笔账永远不进账 |
5999
+ | ③ L-192② | 终帧扁平 `usage`:`webSearchRequests` 从**字面量 0** 改开集宽读 + 缺席判别位;新增 cache-INCLUSIVE 总量座位 `_sema_total_input_tokens`、长 TTL 缓存写入座位 `_sema_cache_write_tokens_long`;终局 per-model 行同批补三座位(总量 / 口径标记 / 长 TTL);🔴 `inputTokens` **仍是 cache-MISS 分量**(不灌总量) | 只读现有四格的端**零改**;要「这条 run/这个模型摆了多少上下文」的端改读新座位 |
6000
+
6001
+ **共同形**:三件都是「上游把事实摆在 wire 上,而**包边界用一个字面量把它答成常数**」——
6002
+ `permission_denials: []` / `webSearchRequests: 0` / 整段 `costBreakdown` 不投,是 0.65.0 那一批
6003
+ (`toolFaces` / `model` / `cacheWriteTokens`)的同族第 N 例。**共同处置**也只有一条:
6004
+ CC 形上必填的位**值不动**(旧消费者逐字不变),把「不知道」交给同行的 `_sema_` 判别位;
6005
+ CC 形上没有的事实**另开超集座位**,绝不改 CC 同名键的语义。
6006
+
6007
+ **出处**:cli 台账 `L-192`(①②)/ `B-068` 与 `DEBTS-cli L-198`(②)。合同真源 = 实装 devDep
6008
+ `@sema-agent/core` 7.12.0 的 `dist/core/task-result.d.ts`(`humanReview` 的 gate 账本 /
6009
+ `costBreakdown` 的对账两式 / `promptTokens` 与 `totalInputTokens` 的 RB-457-a 语义翻转)、
6010
+ `dist/core/tool-spec.d.ts`(`NestedUsage`)、`@sema-agent/sdk` 8.8.0 的 `dist/types.d.ts`
6011
+ (`TaskStats.costBreakdown?: unknown` 开集透传 / `humanReview.gates` 的 live 钉死键面)与
6012
+ `@sema-agent/agent-types` 0.2.0 的 `permissions.d.ts`(CC `SDKPermissionDenial` 三键真形)。
6013
+
6014
+ ---
6015
+
6016
+ ### 31b. ① L-192① 终帧 `permission_denials`(core ≥7.12.0 `TaskStats.humanReview`)
6017
+
6018
+ **病**:CC 的 `SDKResultSuccess` / `SDKResultError` 上有一格 `permission_denials`
6019
+ (「这条 run 里有哪些工具调用被拒了」),而包边界在**两处**(成功臂 + 错误信封)硬编 `[]`。
6020
+ 代价不是少一格数据,是**两句话被折成一句**:「这条 run 一次都没被拒」与「这条帧根本没有这本账」
6021
+ (老引擎 / 409 拒绝信封 / `failed` 事件帧都不带 `stats`)在 CC 形上都是 `[]`。
6022
+
6023
+ **键名与载体**
6024
+
6025
+ | 键 | 载体 | 来源 | 缺席语义 |
6026
+ |---|---|---|---|
6027
+ | `permission_denials[]` | CC result 帧(成功臂 + 错误信封) | 上面那本账里**三键齐全**的记录 | 今天恒 `[]`(wire 给不出后两键);`[]` 本身**不是**缺席(见判别位) |
6028
+ | `_sema_permission_denials[]` | 同上(超集键) | `TaskStats.humanReview.gates[]` 里 `decision === "deny"` 的行,**逐条一记录、顺序 = wire 顺序** | 整键不铸 = 没读出任何被拒记录 |
6029
+ | `…[].tool_name` | 两条清单共用的记录形 | `gates[].toolName` | 键不铸 = 这条腿没报工具名(**绝不编一个**) |
6030
+ | `…[].tool_use_id` / `…[].tool_input` | 同上 | 开集预读 `gates[].toolCallId` / `toolInput`(**今天 wire 上没有**) | 键不铸;**绝不**铸 `""` / `{}` |
6031
+ | `…[]._sema_tool_arg` | 同上(超集键) | `gates[].toolArg` —— 引擎侧已脱敏截短的**一行入参摘要** | 键不铸 = 这条腿没串入参(同步 ask 腿有、耐久 resume 腿没有) |
6032
+ | `_sema_permission_denials_absent` | CC result 帧顶层(超集键) | 见下面四条路径 | **只在该说话时**为 `true`;绝不铸 `false` |
6033
+
6034
+ **🔴 为什么是两条清单**:CC 的 `SDKPermissionDenial` 三键 `tool_name` / `tool_use_id` / `tool_input`
6035
+ **全是必填**(`agent-types` 与本包对照的会话词汇 zod 皆然),而 wire 上这本账的真形是 core 的 gate
6036
+ 记录 —— 只有 `kind` / `waitMs` / `decision?` / `toolName?` / `toolArg?` **五格**,既没有 `toolCallId`、
6037
+ 也没有被拒时的入参对象(core 逐字:「a durable-resume gate carries `toolName` only (its input is not
6038
+ threaded onto the persisted gate — a documented follow-on)」;sdk 的同一格亦逐字记着 `tool_input` /
6039
+ `toolInput` **不在** gate ledger 上)。两条路都不能走:**补零补空 = 编造**;**把半条记录塞进 CC 数组
6040
+ = 破坏元素契约** —— 严格消费方 `safeParse` 会把**整条 result 帧**判非法(丢一格 vs 丢整帧,后者严重
6041
+ 得多)。⇒ CC 数组只收三键齐全的记录,wire 上真有的每一条走 sema 载体。
6042
+ **自动升级腿**:上游哪天把两格串上账本,CC 数组**自己**就开始填(包侧一行不用改),判别位随之退场;
6043
+ 常驻门里有那一条的正控 + 今天的**缺席证据**(锚 core 的 `gates` 声明块),上游一动当天红。
6044
+
6045
+ **🔴 两键合读**(判别位 = 「CC 那条清单**不可声称完整**」,四条路径:①账本整个读不出 ②有读不出的行
6046
+ ③有**认不出的判词**(两张判词表之外的词 / 判词缺席)④有被拒记录没能铸成 CC 形)
6047
+
6048
+ | `permission_denials` | `_sema_permission_denials_absent` | 含义 | 端该渲什么 |
6049
+ |---|---|---|---|
6050
+ | `[]` | 缺席 | 账读得出且逐行判得出,**零拒绝** | 「本次无拒绝」(一句正面事实) |
6051
+ | `[]` | `true` | 清单不完整(没有账 / 有读不出的行 / 有认不出的判词 / 有记录只在 sema 载体上) | 不渲肯定句;改读 `_sema_permission_denials` |
6052
+ | 非空 | 缺席 | 有 N 次拒绝且每条都齐全 | 逐条渲 |
6053
+
6054
+ **🔴 开集判词**:只有 `deny` 被读成「工具调用被拒」;`allow` / `approve` / `edit` / `reject` 是
6055
+ **认得出的非拒绝**(计划复核的否决是「人否了一份**计划**」,不是 CC 说的 "One auto-denied **tool
6056
+ call**")—— 这两张表之外的词、以及**缺判词的行**(耐久 wake 腿真会这样)一律**不猜**:不铸 denial,
6057
+ 但让这份清单失去「完整」资格(判别位立起来)。坏行(非对象)**只丢自己**,不丢整本账;而键都读不出
6058
+ 的被拒行**仍然占一条** ——「被拒了几次」是这本账最要紧的事实。
6059
+
6060
+ **黑盒判据(test 视角可执行)**
6061
+
6062
+ - **G31-1**:一条 run 里让审批人**拒**掉一次工具调用(如 `Bash`),`-p --output-format json` 的
6063
+ `_sema_permission_denials` **恰有一条**,`tool_name === "Bash"`,且该条**没有** `tool_use_id` /
6064
+ `tool_input` 两键(修前这条记录整个不存在);同帧 `permission_denials === []` 且
6065
+ `_sema_permission_denials_absent === true`。
6066
+ - **G31-2**:同一条 run,若拒的是**同步 ask** 腿,该条带 `_sema_tool_arg`(非空串、与引擎账本一致);
6067
+ 若拒的是**耐久 resume** 腿,该键不出现。
6068
+ - **G31-3**:一条**全程无人工门**的 run:`permission_denials === []`、**没有** `_sema_permission_denials` 键、
6069
+ **`_sema_permission_denials_absent === true`(键在场)**。理由:core 只在 `count > 0` 时才铸 `stats.humanReview`
6070
+ (`run-settle-and-teardown.js:71-76`),零人工门的 run 上**整本账不存在** ⇒ 按上面两键合读表落「账本整个读不出」那一档;
6071
+ 「账在、零拒绝」(`humanReview:{count:0,gates:[]}` ⇒ 三键皆缺席)是 core 今天**不会铸**的形,只在白盒喂入时可达。
6072
+ (0.66.0 首版判据把这一格写成「没有判别位」,test [7000] 三层证据证伪;订正于发布后当拍,行为零改。)
6073
+ - **G31-4**:一条被 409 拒绝(或以 `failed` 事件终止)的 run:`permission_denials === []` 且
6074
+ `_sema_permission_denials_absent === true`。
6075
+ - **G31-5**(负控):任一情形下 `_sema_permission_denials_absent` **都不会是 `false`**;
6076
+ 任一情形下 `permission_denials` 里的元素**要么三键齐全、要么这个数组是空的**(半条记录永不进 CC 面)。
6077
+
6078
+ ---
6079
+
6080
+ ### 31c. ② B-068 / L-198 终局成本对账(core ≥7.12.0 `costBreakdown` / `nested`)
6081
+
6082
+ **病**:core 把一条 run 的花费**拆开**摆在 wire 上并给了两条对账式(`task-result.d.ts` 逐字):
6083
+
6084
+ - `llmRootMicroUsd + compactionMicroUsd === costMicroUsd` —— **压缩花费在 own 里面**;
6085
+ - fully-reconciled spend = `costMicroUsd + nested.costMicroUsd` —— **子代花费在 own 外面**
6086
+ (core 逐字:`costMicroUsd` deliberately EXCLUDES nested)。
6087
+
6088
+ 而包边界**一格都不投**:`costBreakdown` 与 `nested` 整段被剥,终帧只剩一个 `total_cost_usd`,
6089
+ 于是成本面永远看不见子代与压缩两笔账(`/cost` 与 `-p` 低报)。
6090
+
6091
+ **键名与载体**
6092
+
6093
+ | 键 | 载体 | 来源 | 缺席语义 |
6094
+ |---|---|---|---|
6095
+ | `_sema_cost_breakdown` | CC result 帧顶层(超集键) | `TaskStats.costBreakdown`,**micro-USD 原值**(键名即单位,包不折 USD) | 整键不铸 = 这条 run 没有明细(core 在 unpriced 时与 `costMicroUsd` 一起省略);单键不铸 = 那一类读不出 |
6096
+ | `_sema_nested_usage` | 同上 | `TaskStats.nested`(`tokens`/`turns`/`tasks`/`costMicroUsd`) | 整键不铸 = **没委派过**(判据是**原始载体**在不在,不是过滤产物空不空);键在场而其 `costMicroUsd` 不铸 = 委派过但那本账**没定价/读不出**(core 逐字 `never a fabricated 0`)—— 键在场但值为空对象是合法的一句话 |
6097
+ | chrome 臂 `run_cost_reconciled` | `ChromeEvent`(新臂,`required: false`) | 与上面两键**同一个读器**(`readRunCostFacts`) | 整条不发 = 这条终帧没有 `stats`(409 / park 体 / `failed` 事件帧) |
6098
+ | `total_cost_usd` | CC result 帧(**CC 同名键**) | `TaskStats.costMicroUsd / 1e6` | **语义一字未改**(见下) |
6099
+
6100
+ **臂载荷**:`{ ownMicroUsd?, nestedMicroUsd?, compactionMicroUsd?, llmRootMicroUsd?,
6101
+ reconciledMicroUsd?, costAbsent?, nestedCostAbsent? }`。
6102
+ `reconciledMicroUsd = own + nested` **只在两边都知道、且和本身是有限数时才铸**;own 没定价 ⇒
6103
+ `costAbsent: true`,委派过但那本账没定价/读不出 ⇒ `nestedCostAbsent: true`,两种情形下对账值
6104
+ **都不铸**(不知道就是不知道)。🔴 「委派过」这件事的判据是 `stats.nested` **这个载体在不在**,
6105
+ 不是它里面有没有读得出的数 —— 否则一条 `nested: {}` 会被当成「没委派」,于是 own 被铸成一个
6106
+ **确定的总额**,而真相是「委派过、花了多少不知道」。
6107
+
6108
+ **🔴 `total_cost_usd` 为什么不把 nested 折进去**:它是 **CC 同名键**,生态里读它的人默认它是
6109
+ CC 那个语义;把子代花费折进去 = 在一个已有的位上塞我们自己的口径(超集键纪律明令禁止),
6110
+ 而且会让「own 花费」这个量在整条链上再也说不清。⇒ 包给的是**可对账的事实**,不是一个改了口径的
6111
+ 数:要 fully-reconciled spend 的端**自己加**(`own + nested`),而且加之前要先看两个判别位。
6112
+
6113
+ **🔴 为什么另起一条 chrome 臂而不是扩 `last_turn_usage`**:那条臂的宿主义务逐字是「落**最近一次
6114
+ turn** 的真 usage」——它回答「这一轮」,本臂回答「**这条 run 一共**」。两个量同臂,宿主就得在同一
6115
+ 载荷上分辨「这是 turn 还是 run」(同名不同义那一族病);且那条臂是 `required: true` 的既有义务面,
6116
+ 往上加语义会改已接宿主的读法。
6117
+
6118
+ **🔴 子流断闸不动**:`isSubFlow` 的 `turn_end` 仍然**不发** `last_turn_usage`(§E2 判据一字未动),
6119
+ 子代花费**只**经终局 `nested` 到账。⇒ 端**绝不能**把流中增量与本臂的终局总账相加 —— 那是重复计账。
6120
+
6121
+ **端怎么接**
6122
+
6123
+ ```ts
6124
+ // 终局那一拍(chrome 臂);不接这条臂的端改从终帧两个超集键读同一份事实
6125
+ case 'run_cost_reconciled': {
6126
+ if (ev.costAbsent) showOwn('未定价') // 🔴 别渲 $0.00
6127
+ else showOwn(ev.ownMicroUsd! / 1e6)
6128
+ if (ev.nestedCostAbsent) showNested('未定价') // 委派过,但那本账没有价
6129
+ else if (ev.nestedMicroUsd !== undefined) showNested(ev.nestedMicroUsd / 1e6)
6130
+ if (ev.compactionMicroUsd !== undefined) showCompaction(ev.compactionMicroUsd / 1e6)
6131
+ if (ev.reconciledMicroUsd !== undefined) showTotal(ev.reconciledMicroUsd / 1e6)
6132
+ break
6133
+ }
6134
+ ```
6135
+
6136
+ **黑盒判据**
6137
+
6138
+ - **G31-6**:一条**委派过子代**且**发生过压缩**的 run:终帧 `_sema_cost_breakdown.compactionMicroUsd`
6139
+ 与 `_sema_nested_usage.costMicroUsd` 都是有限数,且
6140
+ `llmRootMicroUsd + compactionMicroUsd === ` 该 run 的 `costMicroUsd`(core 的第一条对账式,
6141
+ 由 wire 值自身成立 —— 包不改数)。
6142
+ - **G31-7**:同一条 run 的 `total_cost_usd` **等于 own**(`costMicroUsd / 1e6`),**不等于**
6143
+ `own + nested`(修前后都不变 —— 这是一条防回归的反钉)。
6144
+ - **G31-8**:同一条 run **恰有一条** `run_cost_reconciled` chrome 事件,
6145
+ `reconciledMicroUsd === ownMicroUsd + nestedMicroUsd`。
6146
+ - **G31-9**:一台**没有价表**的 worker 上跑同一条 run:臂上 `costAbsent === true`,
6147
+ **没有** `ownMicroUsd`、**没有** `reconciledMicroUsd`;终帧上 `_sema_cost_breakdown` 键**不出现**
6148
+ (core 在 unpriced 时整段省略)。
6149
+ - **G31-10**:一条**没委派**的 run:臂上没有 `nestedMicroUsd` 且 `reconciledMicroUsd === ownMicroUsd`;
6150
+ 终帧上 `_sema_nested_usage` 键不出现。
6151
+ - **G31-10b**:一条**委派过但子代账读不出**的 run(`nested` 在场、其 `costMicroUsd` 缺席):
6152
+ 臂上 `nestedCostAbsent === true` 且**没有** `reconciledMicroUsd`(修前会铸出一个只含 own 的
6153
+ 「确定总额」);终帧上 `_sema_nested_usage` 键**在场**(委派这件事不丢)。
6154
+ - **G31-11**:一条被 409 拒绝的 turn:`run_cost_reconciled` 事件 **0 条**(没有账就不说话);
6155
+ `stats` 是畸形载体(数组/标量)时同样 0 条。
6156
+ - **G31-12**(负控):一条**子流** `turn_end` 不产生 `last_turn_usage` chrome 事件(既有断闸未被本批改动)。
6157
+
6158
+ ---
6159
+
6160
+ ### 31d. ③ L-192② 终帧扁平 `usage` 三格(core ≥7.12.0 usage 语义)
6161
+
6162
+ **键名与载体**
6163
+
6164
+ | 键 | 载体 | 来源 | 缺席语义 |
6165
+ |---|---|---|---|
6166
+ | `usage.webSearchRequests` | CC result 帧的扁平 usage | 按 CC 的名字**开集宽读**(`TaskStats` 是开集索引) | 读不出 ⇒ 值仍 `0`(CC 形必填 number)**+ 判别位** |
6167
+ | `usage._sema_web_search_requests_absent` | 同上(超集键) | 上一格读不读得出 | 只在读不出时 `true`;绝不铸 `false` |
6168
+ | `usage._sema_total_input_tokens` | 同上(超集键) | `TaskStats.totalInputTokens`(**cache-INCLUSIVE** 总量) | 键不铸 = wire 没报;显式 `0` 是事实 |
6169
+ | `usage._sema_cache_write_tokens_long` | 同上(超集键) | `TaskStats.cacheWriteTokensLong`(**1 小时 TTL** 那一档的缓存写入) | 键不铸 = wire 没报;显式 `0` 是读数(core 逐字「0 unless 1h caching is in use」) |
6170
+ | `ModelUsage._sema_web_search_requests_absent` | 每一行 CC `ModelUsage` 镜像(超集键) | 同上(同形第二处,两个 mint 点一个规矩) | 同上 |
6171
+ | **终局** per-model 行的 `_sema_total_input_tokens` / `_sema_usage_basis` / `_sema_cache_write_tokens_long` | 终帧 `modelUsage[*]`(超集键;**只有终局这一面**) | 行上的 `totalInputTokens` / `usageBasis` / `cacheWriteTokensLong` | 逐键不铸 = 这一行没报;`usageBasis` 是**开集串**,🔴 **缺席不许倒推口径** |
6172
+
6173
+ **🔴 `inputTokens` 为什么**不**改读 `totalInputTokens`**(本批唯一一处「台账写法 vs 合同」的分歧,
6174
+ 处置写明在此):台账原句是「input 用旧键 `promptTokens` 未读 `totalInputTokens`」。核合同后**不采**
6175
+ 那个写法 —— core 的 RB-457-a(3.0.0 BREAKING)把 `promptTokens` 的语义**翻**成了 cache-**MISS**
6176
+ 分量,而 CC / Anthropic 的 `input_tokens` 本义正是 MISS;同一个 `usage` 对象上已经另有
6177
+ `cacheReadInputTokens` 与 `cacheCreationInputTokens` 两格,把 cache-INCLUSIVE 总量灌进 `inputTokens`
6178
+ 就是 core 逐字点名的那笔**双算**(逐字:「a consumer computing `cachedTokens / (promptTokens +
6179
+ cachedTokens)` double-counted the cache subset and reported `h/(1+h)` (a 98% hit rate surfaced as
6180
+ 49.5%)」)。那等于**改 CC 同名键的语义**,不是超集。⇒ `inputTokens` 逐字不动(MISS 分量),
6181
+ 总量**另开超集座位**。这也与本包既有纪律一致:CC `ModelUsage` 镜像上同样没有总量座位。
6182
+
6183
+ **🔴 那为什么终帧要开座位、而 per-turn 那一面不开**:per-turn 有**逐字通道**
6184
+ (`EngineTurnUsage` / chrome `last_turn_usage.engineUsage`,整对象原形过境),要总量的消费面去那儿取;
6185
+ 而**终帧这一面没有任何别的载体** —— 不开座位,「这条 run 一共摆了多少上下文」在终帧上就问不出来。
6186
+ **同一条理由**把三个座位一并给了**终局的 per-model 行**(一个全局总量答不了「哪个模型摆了多少」,
6187
+ 而那张分表同样没有逐字通道):加挂只发生在两条**终局**腿上,per-turn 与终局共用的那个 mint 点
6188
+ (`toCcModelUsage`)一个字不动 —— 门里有一条反向钉盯着 per-turn 镜像不长这些座位。
6189
+
6190
+ **🔴 长 TTL 缓存写入为什么只「另给」不「相加」**:core 对两格的说法互相矛盾 ——
6191
+ `cacheWriteTokens` 自述是「Anthropic `cache_creation_input_tokens`」(协议侧那个量本就含 1h 子项),
6192
+ 而 `totalInputTokens` 的求和式又把 `cacheWriteTokens` 与 `cacheWriteTokensLong` **并列相加**
6193
+ (那要求二者互不重叠)。相加与不加**各有一种错法**,证据不足**不猜**:CC 的
6194
+ `cacheCreationInputTokens` 逐字保持 `cacheWriteTokens`(既有值一字不动),长 TTL 分量原样另给,
6195
+ 对账由消费方按两个数自己做;候上游澄清后再定。
6196
+
6197
+ **本批刻意不投的位(登记在案,不是漏)**
6198
+
6199
+ | 位 | 为什么不投 | 端要它时去哪儿取 |
6200
+ |---|---|---|
6201
+ | `ModelUsage.contextWindow` / `maxOutputTokens` | 它们是**模型的静态元数据**,不是这一轮的账;给它们立「缺席判别位」会把「去目录里取」误导成「等 usage 面补上」 | 模型目录(`/v1/models[].contextWindow`),本包 `resolveModelCatalog` 一侧 |
6202
+ | `TaskStats.cacheHitRate` / `toolCalls` / `mechanisms` / `memory` / `suggestions` | 都是**可观测面**而非 CC 形上的位,今天无端消费;投影它们等于先造一堆没人读的超集键 | 需要时按 `L-211` 一并立项(该票本就是「终局回执未消费族」) |
6203
+ | `humanReview.count` / `totalWaitMs` | 人工复核**耗时轴**(core 明记它**永不**折进成本/预算),与本批的拒绝清单是两件事;要它的是运维面不是会话面 | 同上,候 `L-211` |
6204
+
6205
+ **黑盒判据**
6206
+
6207
+ - **G31-13**:任一条 run 的终帧:`usage.webSearchRequests === 0` 且
6208
+ `usage._sema_web_search_requests_absent === true`(今天 wire 上没有这本账);
6209
+ 每一行 `modelUsage[*]` 上同样带这一位。
6210
+ - **G31-14**:一条 prompt 命中过缓存的 run:`usage.inputTokens` **小于**
6211
+ `usage._sema_total_input_tokens`(前者是 MISS 分量、后者是含 cache 的总量),且
6212
+ `usage.inputTokens` 与该 run 的 `promptTokens` **逐字相等**。
6213
+ - **G31-15**:一台不报 usage 的网关上的 run:`usage._sema_total_input_tokens` 键**不出现**
6214
+ (不拿 `promptTokens` 冒充总量),四个既有 token 格仍是 `0`。
6215
+ - **G31-16**(负控):三个超集位**都不会**出现 `false` / `null` 形态。
6216
+ - **G31-17**:一条在**多模型**部署上跑完的 run:终帧 `modelUsage[<每个模型>]` 各自带
6217
+ `_sema_total_input_tokens`(该模型那一行的 cache-INCLUSIVE 总量);行上报了口径标记时
6218
+ `_sema_usage_basis` 逐字过境(修前两键都被剥)。
6219
+ - **G31-18**:一条用了 **1 小时 TTL 缓存**的 run:`usage._sema_cache_write_tokens_long > 0`,
6220
+ 而 `usage.cacheCreationInputTokens` **逐字等于** wire 的 `cacheWriteTokens`(包不替引擎求和)。
6221
+
6222
+ ---
6223
+
6224
+ ### 31e. 消费方待办(三端逐条)
6225
+
6226
+ **cli(壳)**
6227
+
6228
+ 1. 壳仓的成本账本(`cost-tracker.ts`)的终局对账:接 chrome 臂 `run_cost_reconciled`(或读终帧两个超集键),
6229
+ `/cost` 面把 **own / nested / compaction** 三段各渲一行;🔴 两个判别位在场时渲「未定价」而**不是**
6230
+ `$0.00`;🔴 **不要**把流中 `last_turn_usage` 的增量与本臂的终局总账相加(子代花费只经终局到账)。
6231
+ 2. 壳仓里**本地铸** `permission_denials: []` 的两处(`sema/bridgeMessaging.ts` 与
6232
+ `sema/bootSignalTail.ts`):退役,改读投影;🔴 那两处自己合成的终帧同样只该在**账真的读得出且
6233
+ 逐行判得出**时给 `[]`,否则要带上判别位 —— 本地铸一个裸 `[]` 就是把「没有账」说成「零拒绝」。
6234
+ 3. 要「这条 run 摆了多少上下文」的读点(`/context` 与终帧 usage 面):改读
6235
+ `usage._sema_total_input_tokens`;🔴 **不要**把 `usage.inputTokens` 当总量(它是 MISS 分量)。
6236
+ 4. 网搜计数面(若有):`webSearchRequests === 0` 从此要与判别位合读,别渲成「本次未使用网搜」。
6237
+ 5. 拒绝清单的读点改吃 `_sema_permission_denials`(CC 的 `permission_denials` 今天恒 `[]`,
6238
+ 要等上游把 `toolCallId`/`toolInput` 串上 gate 账本才会自动填);渲之前先看判别位。
6239
+ 6. 缓存成本面若按 `cacheCreationInputTokens` 算钱:1 小时 TTL 那一档在
6240
+ `_sema_cache_write_tokens_long` 上单列,**别自己相加**(两格关系上游尚未澄清,见 §31d)。
6241
+
6242
+ **desktop**
6243
+
6244
+ 1. 走包管线的成本面同 cli 第 1 条:`run_cost_reconciled` 是 `required: false`,**不接不会哑**,
6245
+ 但不接就必须自己按终帧两个超集键对账,否则子代与压缩两笔账永远不进面板。
6246
+ 2. 自查点:有没有自己铸过 `permission_denials`(座位 IPC 侧的结果帧转投)——有则改读投影。
6247
+
6248
+ **web**
6249
+
6250
+ 1. 同上第 1 条;另:web 的账单/用量面若按 `usage.inputTokens` 求和估算上下文占用,按 §31d 改读
6251
+ `_sema_total_input_tokens`(否则命中率高的会话会被低估)。
6252
+ 2. 判别位一律按「不渲肯定句」处理:本批四个判别位(`_sema_permission_denials_absent` /
6253
+ `_sema_web_search_requests_absent` / 臂上的 `costAbsent`·`nestedCostAbsent`)都**只在该说话时在场**,
6254
+ 从不铸 `false`。
6255
+
6256
+ ---
6257
+
6258
+ ### 31f. 本批的门(新增两道 + 扩一道)
6259
+
6260
+ | 门 | 守什么 |
6261
+ |---|---|
6262
+ | `scripts/run-permission-denial-projection-test.mjs` | 🆕(L-192①):deny 行逐条铸(条数/顺序/`tool_name`)· `tool_use_id` 与 `tool_input` **键缺席**且缺席证据锚在 core 的 gate 声明块上(上游补上即红)· `_sema_tool_arg` 承载已脱敏摘要 · 「零拒绝」与「没有账」两键合读且判别位绝不铸 `false` · 成功臂与错误信封**单一 mint 点** · 非 deny 判词不猜 · 坏行逐行独立 |
6263
+ | `scripts/run-cost-reconcile-projection-test.mjs` | 🆕(B-068 / L-198):两段逐键窄读(micro-USD 原值、坏键剥掉不连坐、整段读不出不铸空对象、开集新键过境)· nested 花费未定价**键缺席绝不铸 0** · 🔴 `total_cost_usd` 语义零改的反钉 · chrome 臂三段与对账值 · `stats` 缺席一条不发 · 非成功终局照发 · §E2 子流断闸反钉 |
6264
+ | `scripts/run-cost-absence-projection-test.mjs` | 🔁(L-192②):新增 E/F/G/H 四段 —— `webSearchRequests` 开集宽读 + 判别位(两个 mint 点同扫)· `_sema_total_input_tokens` 有座位而 `inputTokens` **仍是 MISS 分量**(灌总量即红)· core 逐字(MISS / cache-INCLUSIVE / 双算警告)· 长 TTL 分量另给不相加 · 终局 per-model 三座位 + **per-turn 镜像不长座位**的反向钉 |
6265
+
6266
+ ---
6267
+
6268
+ ## §32 🆕 0.67.0 提货批(core **7.14.0 → 7.16.0**:分类器卡面退役 / ask 出身换词 / 规则店机制位 / auto 拒绝来源 / usage 下界位 / per-subagent 分表)
6269
+
6270
+ ### 32a. 本节速览
6271
+
6272
+ | 件 | 一句话 | 端要做什么 |
6273
+ |---|---|---|
6274
+ | F-1 | 卡上那格 `classifierUnavailable` **整族退役**(core 从六个载体上删掉,ask 那几处自 #661 起就没写过);事实位改挂**拒绝面** `tool_end.gate.disposition.cause`(闭二词) | 渲「问你是因为分类器跑不了」的端**改读门记录**;`classifierUnavailableOf` / `classifierUnavailableDetail` 两个导出**没了**(BREAKING) |
6275
+ | F-2 | `ASK_ORIGINS` 的 `unresolvable` **BREAKING 换成** `ancestor_marked`(无 alias) | 端的 origin `switch` 改词;旧耐久行带旧词 ⇒ 非成员 ⇒ **省略那一格**(照旧渲兜底句,不抛) |
6276
+ | F-3 | 新增 `ruleStoreUnreadable ∈ {store,call}` —— `origin: "rule_store_unavailable"` 底下的**机制位**(店读不出来 / 这条命令对不上规则行) | 卡面在 origin 句旁**再渲一句**(唯一铸点 `ruleStoreUnreadableDetail`);两句的下一步**相反** |
6277
+ | F-4 | `wiring_manifest.autoMode.deniedSource`(哪一层设置面关掉了 auto)+ `memory.consolidation_withheld` audience **user → operator** + 码册 **+1** `task.interrupt_unconsumed` | /doctor 的 auto 行多渲一句「被谁关的」;按 audience 分发的端**自动跟着走**,但为 withheld 写过「告诉用户」专属行的端要把那一行挪到运维面 |
6278
+ | F-5 | `TaskResult.stats.usageMissing` ⇒ 终帧新增 `_sema_usage_lower_bound`(CC 同名键**语义零改**) | 成本/用量面在这一位在场时渲「≥」或「至少」,**绝不**渲成一笔已知的账 |
6279
+ | F-6 | **per-subagent usage 分表**:新 chrome 臂 `subagent_turn_usage` + 终帧 `_sema_nested_usage_by_task`(+ 诚实位 `…_partial`)。⚠️ **供给面未端到端实证**,见 §32g 的射程边界段 | 子代详情面**在子流 `turn_end` 到得了这条流时**接得上「这只子代花了多少」;两个键缺席时**不许**渲成「没委派子代」;🔴 **绝不**把它加进主会话用量 |
6280
+
6281
+ **共同形**:这一批有两条线。一条是**退役**(F-1 / F-2)——上游把一格/一个词删了,本包按 clean-cut
6282
+ 删码、删词、删导出,**不留别名**(留一条就是让三端继续为一件上游不发的事实写渲染分支,而那条分支
6283
+ 永远走不到)。另一条是**继任与补位**(F-3 ~ F-6)——事实没有消失,只是换了载体,或者本来就在 wire 上
6284
+ 而包边界没投。**共同处置**仍然只有一条:CC 形上已有的位**值不动**(旧消费者逐字不变),新事实一律
6285
+ `_sema_` 前缀超集键或 additive chrome 臂;「不知道」只以判别位在场,永不铸 `0`/`false`/`[]`。
6286
+
6287
+ **出处**:core core 仓 docs/wire-consumption/7.14.0.md(9 新增/变更 + 8 退役)、`7.15.0.md`(4 行语义变更、
6288
+ 0 退役)、`7.16.0.md`(包表面 4 + 盘面 7 + 通告码 2 + `Model.cost`/`isModelPriced`)。型面真源 = 实装
6289
+ devDep `@sema-agent/core` 7.16.0 的 `dist/core/*.d.ts`:`gate-outcome.d.ts:168`
6290
+ (`CLASSIFIER_DENY_CAUSES`)、`ask-origin.d.ts:73`(`ASK_ORIGINS` 十一词)与 `:116`
6291
+ (`RULE_STORE_UNREADABLE_KINDS`)、`tool-policy.d.ts:308` / `checkpoint-store.d.ts:818`·`:1924`
6292
+ (`ruleStoreUnreadable` 三处载体)、`wiring-manifest.d.ts:84-88`(`AutoModeArmFact`)、
6293
+ `task-result.d.ts:609-615`(`stats.usageMissing`)与 `:594-660`(`stats.nested` **只有合计**)、
6294
+ `governance-codes.js:146`·`:151-204`(码册与 audience 表)。
6295
+
6296
+ **🔴 逐键处置表见 §32z** —— 那张表是三份合同的**每一行**在本包的落点(consumed 坐标 / n-a 理由 /
6297
+ pending 票),下游抄 manifest 时以它为母本。
6298
+
6299
+ ---
6300
+
6301
+ ### 32b. F-1 分类器卡面退役 / 拒绝面继任(core 7.14.0 退役表 + `GateDisposition.denied.cause`)
6302
+
6303
+ **病**:0.64.2 起本包在**审批卡**上投一格 `classifierUnavailable: { cause }`(「问你是因为分类器
6304
+ 这一轮跑不了」)。core 7.14.0 的 Retired keys 表把这一格**从六个载体上整族删掉**
6305
+ (`PermissionDeniedPayload` / `PermissionResult` 的 deny 与 ask 两臂 / `AskRequest` /
6306
+ `AskCarry`·`AskRequestCarry` / `PendingAction.tool_approval`·`CheckpointSummary`),其中 **ask 那几处
6307
+ 自 #661 起引擎就没写过**(退役表逐字 "never engine-written since #661" / "dead since #661")。
6308
+ ⇒ 本包那条腿从那天起**恒零命中**,而它的读器、措辞、视图型、卡位仍然在公面上承诺着一件上游不发的事实。
6309
+
6310
+ **继任者是一个结构位**,不是散文:
6311
+
6312
+ | 键 | 载体 | 形 | 缺席语义 |
6313
+ |---|---|---|---|
6314
+ | `gate.disposition.cause` | `tool_end` 帧的 `gate` / `PermissionDeniedPayload.gate` / 耐久行的 resolved outcome(**三面同一个对象图**) | `"unavailable"`(分类器跑不了,**可以稍后重试**)/ `"parse_error"`(跑了并且答了,只是答在裁决契约之外 ⇒ 为安全起见拦下,重试解决不了) | 在 `deniedBy: "classifier"` 旁缺席 = 分类器**自己的裁决**(一次 `<block>yes`);在别的层旁缺席 = 这次不是分类器轮。**三形不可分**,端禁读成「分类器好着呢」 |
6315
+
6316
+ **本包给的三件**(全部 additive,除两个导出减员外零 BREAKING):
6317
+
6318
+ 1. `GateDispositionView.cause?: string` —— `gateOutcomeOf(frame)` 的 denied 臂上多一格,**开集透传**
6319
+ (非空串即收),与同文件 `deniedBy` / `settlement.kind` / `origin` 三处逐字同规;
6320
+ 2. `classifierDenyCauseOf(gate)` —— **闭集**判成员的公面读器,一只吃三处载体(wire 原始 `gate` /
6321
+ 带 `gate` 的整只帧 / 本包投出的 `GateOutcomeView`,三者键路同形);
6322
+ 3. `classifierDenyCauseDetail(cause)` —— 两句人话的唯一铸点(表外词走兜底、原样带词)。
6323
+
6324
+ **🔴 为什么这一格按闭集、而 `origin` 按开集**(两条纪律不矛盾,差别在**上游的形**上):
6325
+ core 的 `screenGateOutcome` 把「出集的 `cause`」列为**记录缺陷**(不变量 I5),而有缺陷的门记录
6326
+ server **整条不上帧** ⇒ 一个表外的 cause **结构上到不了消费端**,它到达的形式是 `gate` 整键缺席。
6327
+ 所以在这一格上按闭集判**不会**「把一个合法的新词吞成缺席」;而 `origin` 在 server 侧只判非空串,
6328
+ core 加词的当天一个**合法**的帧就会带着新词到达 —— 两格的处置因此必须不同。
6329
+
6330
+ **🔴 分工两层**:`gateOutcomeOf` 答「这条事实到不到得了消费端」(过境,开集);`classifierDenyCauseOf`
6331
+ 答「拿不拿它渲一句话」(判成员,闭集)。这与退役前 `classifierUnavailable` 的「过境 / 显示」两层
6332
+ **逐字同形**,端不必学新的读法。
6333
+
6334
+ **🔴 状态面的事实源同批改道,判据句一个字没改**:`classifierStatusOf(autoMode, observed?)` 的
6335
+ `unavailable_this_round` 从「ask 上盖了没跑成的章」改读「**本轮观测到的门记录**上那一格 deny 成因」。
6336
+ `parse_error` 仍然**落到下一条臂**(它是「答了」不是「没跑成」),行为与 0.66.0 **逐字节相同** ——
6337
+ 变的只是这条排除的归属地(从铸点那一侧搬到状态面这一问上)。**turn 边界怎么重置**:读器是纯函数,
6338
+ 第二参就是「本轮那一次观测」,上一 turn 的事实**结构上**到不了这一次调用;包内**刻意不持有**跨 turn
6339
+ 的闩(会话级闩在重连 / durable 重放上会把一条陈旧的成因渲成「现在」)。
6340
+
6341
+ **消费方该做什么**
6342
+
6343
+ - **cli(1.0.109)**:①壳侧 `approvalStreamWire.ts` 的 `readClassifierUnavailableStamp` 那条本地窄读
6344
+ **整只退役**(卡上不再有那一格);②「分类器跑不了」那一行改从 `tool_end.gate` 渲 ——
6345
+ `classifierDenyCauseOf(frame)` + `classifierDenyCauseDetail(cause)`;③ `/doctor` 的 Auto classifier 行
6346
+ 零改(状态读器签名与三态词表未动),但喂给它的第二参要换成**本 turn 的门记录观测座**。
6347
+ - **desktop / web**:同 ①②;若从未消费过那一格,则**零改**(缺席臂那天就是正解)。
6348
+ - **三端共同**:`classifierUnavailableOf` / `classifierUnavailableDetail` 两个导入会**编译期红** ——
6349
+ 那正是这次 BREAKING 想要的效果(静默改行为比编译红坏得多)。
6350
+
6351
+ **黑盒判据(test 视角可执行)**
6352
+
6353
+ - **G32-01**:一条 `tool_end` 帧带 `gate.disposition = {kind:"denied", deniedBy:"classifier",
6354
+ cause:"unavailable"}` ⇒ 包投出的内部臂上 `gate.disposition.cause === "unavailable"`,且
6355
+ `classifierDenyCauseOf(帧)` 返回同一个词。
6356
+ - **G32-02**:同一条帧把 `cause` 换成 `"brand_new_word"` ⇒ **投影臂上照旧原样在场**(过境开集),
6357
+ 而 `classifierDenyCauseOf` 返回 `undefined`(显示层闭集)。两层分工可观察。
6358
+ - **G32-03**:`disposition.kind === "allowed"` 且顺手挂了 `cause` ⇒ `classifierDenyCauseOf` 返
6359
+ `undefined`(那一臂上不存在这一位)。
6360
+ - **G32-04**:两句人话逐字互异,且 `unavailable` 那句含「可以稍后重试」的意思、`parse_error` 那句
6361
+ **不含**(两条相反的下一步不许合并成一句)。
6362
+ - **G32-05**:一张 `tool_approval` 帧上带 `classifierUnavailable: {cause:"timeout"}`(旧引擎形)
6363
+ ⇒ 卡入参上**那一格不在场**、也**不**被顺手读成别的键,且**不抛**(旧行忽略,投影按新形办)。
6364
+ - **G32-06**:`classifierUnavailableOf` / `classifierUnavailableDetail` 在包的运行期导出上
6365
+ **查不到**(公面减员是这次 BREAKING 的一半)。
6366
+
6367
+ ---
6368
+
6369
+ ### 32c. F-2 `ASK_ORIGINS`:`unresolvable` → `ancestor_marked`(**BREAKING**,无 alias)
6370
+
6371
+ **形**:core 7.14.0 把出身词表的第二员换名(同一条 ladder 臂、同一张资格表,**只换词**)。
6372
+ 7.16.0 的全表(`ask-origin.d.ts:73`,十一词,顺序即契约):
6373
+ `content_question, ancestor_marked, org_unavailable, org_rule, rule_store_unavailable, hook, ask_rule,
6374
+ denial_limit_fallback, shell_gate_tighten, safety_tighten, policy`。
6375
+
6376
+ **缺席 / 旧值语义**:一条 pre-7.14 的耐久行带 `"unresolvable"` ⇒ 它在每一道 `isAskOrigin` 筛上都是
6377
+ **非成员** ⇒ 投影**省略**该 origin(不渲那句定义句、不抛、不折成十一词里的任何一个);本包的措辞铸点
6378
+ `askOriginDetail` 对它走**开集兜底句**(原样带词 + 「这个词比这一端新」),行的 `org` 事实仍然照常管事。
6379
+
6380
+ **🔴 对账基准同批从 sdk 换成 core**:sdk 8.8.0 的 `AskOrigin` 联合**还写着旧词**,而词表的属主是 core。
6381
+ 修前 `run-gate-vocabulary-test.mjs` 拿 sdk 当基准,于是「本包跟着 core 换词」的那一刻它会红,而红的
6382
+ **是对的那一侧**;更坏的是本包若跟着 sdk 不换,门会**一声不响**。⇒ 基准改锚 core 的 `ask-origin.js`
6383
+ 真字节,sdk 的滞后改成一条**带退出条件的登记**(sdk 追平那天自红逼删)。
6384
+ 同批**退役**了一条恒真的型面钉 `_askOriginWordsPin`(`readonly AskOrigin[]`,而 sdk 的 `AskOrigin` 带
6385
+ `(string & {})` 逃生口 ⇒ 任何字符串都满足它;亲验:换词后 `tsc --noEmit` 0 红)。
6386
+
6387
+ **消费方该做什么**
6388
+
6389
+ - **cli / desktop / web**:origin 的 `switch`/映射表把 `unresolvable` 改成 `ancestor_marked`;
6390
+ **`default` 臂必须在**(开集 + 旧行);为旧词写过专属文案的端把那一条删掉(它今天走兜底句)。
6391
+ - 端**不要**自己保留一张 `unresolvable → ancestor_marked` 的别名表:那会让一个上游已经不发的词
6392
+ 在端上继续活着,而下一次上游换词时两份表各漂各的。
6393
+
6394
+ **黑盒判据**
6395
+
6396
+ - **G32-07**:`ASK_ORIGIN_WORDS` 与实装 core 的 `ASK_ORIGINS` **逐词逐序相等**(缺一词红、多一词红、
6397
+ 顺序不同也红);表里**没有** `unresolvable`。
6398
+ - **G32-08**:`askOriginDetail("ancestor_marked")` 交出「祖先标记 + 必须到达 park」那一句;
6399
+ `askOriginDetail("unresolvable")` 走**兜底句**、原样带词,且**不等于**前者。
6400
+ - **G32-09**:`askOriginDetail("unresolvable", "<引擎散文>")` 与不带第二参**逐字相同**(让位集是闭集,
6401
+ 不因为有 message 就放宽)。
6402
+
6403
+ ---
6404
+
6405
+ ### 32d. F-3 `ruleStoreUnreadable ∈ {"store","call"}`(core 7.14.0 #688 C3;**ADDITIVE**)
6406
+
6407
+ **病**:`origin: "rule_store_unavailable"` 这**一个词**盖了**两种机制** —— 那个人的持久规则店整体
6408
+ 读不出来(读失败 / 超时 / 适配器抛了),**或者**店读到了但**这一次调用**对不上他的 deny/ask 规则行
6409
+ (收紧 lexer 的 `unreadable`:展开里有读不懂的词 / 引号未闭合 / 语法错)。两种机制对人的**下一步相反**:
6410
+ 一个去找部署的人修规则店,一个去改自己那条规则 / 这条命令。core 逐字点名了这件事:
6411
+ 「a consumer that renders "the store is down" for a call the lexer could not read is telling the person
6412
+ to fix the wrong thing」。
6413
+
6414
+ **键名与载体**
6415
+
6416
+ | 键 | 载体 | 形 | 缺席语义 |
6417
+ |---|---|---|---|
6418
+ | `ruleStoreUnreadable` | 活卡帧 `ToolApprovalFrame`(`tool_approval` only)/ durable park 行的 `PendingAction.tool_approval` 孪生位 / `CheckpointSummary` 摘要行 —— **三处键名同形** | 闭二词裸串 `"store"` / `"call"` | **在场 ⇔ `origin === "rule_store_unavailable"`**;缺席 = 这条腿把店和这次调用**都读通了**,**或**本部署压根没接规则店 —— 两形不可分,端禁读成「你的规则都好着呢」 |
6419
+ | `ApprovalCardRequest.ruleStoreUnreadable` | 本包投到卡口的那一格(**双源合流**:活卡帧腿 + durable 腿,同一把窄读器) | 同上 | 键不铸(绝不折成空串) |
6420
+
6421
+ **🔴 闭二词按闭集判**(与卡上 `origin` / `ruleOffersAbsence` 的开集纪律刻意不同):core 在**唯一 stamp
6422
+ 点**(`gate-lanes.ts` 的 `ruleStoreUnreadableOf`)把**政策自报的值剥掉**之后才盖章(合同逐字
6423
+ 「A policy's self-declared value is removed at the stamp」)⇒ 一个表外值**结构上**到不了消费端;
6424
+ 真读到就是坏形,而把坏形渲成一句机制解释会把人指到错的地方。
6425
+
6426
+ **措辞**:`ruleStoreUnreadableDetail(kind)` 是三端共用的唯一铸点(两句逐字互异、表外词走兜底带词)。
6427
+ 🔴 它与 `askOriginDetail(origin, message)` **并列不互替**:那一句答「谁问的」,本句答「读不出来的是
6428
+ **哪一头**」;引擎在 `message` 上给的**这一次**的散文(lexer 那句话)由 0.65.0 已有的让位臂渲出。
6429
+ 一只 `rule_store_unavailable` 的 ask 上**三句都该在**,渲一句丢两句就等于把人指去错的地方。
6430
+
6431
+ **消费方该做什么**
6432
+
6433
+ - **cli(1.0.109)**:审批卡在 origin 句旁**加渲一句** `ruleStoreUnreadableDetail(req.ruleStoreUnreadable)`;
6434
+ 缺席时**什么都不加**(不要渲「你的规则没问题」)。
6435
+ - **desktop / web**:同上;`switch` 不必带 `default` 分支渲文案(闭集 + 唯一铸点已兜底),但**必须**
6436
+ 处理键缺席这一形。
6437
+ - **三端共同**:别在自己那侧再抄一张 `{store,call}` 表 —— 判据口 `isRuleStoreUnreadableKind` 与词表
6438
+ `RULE_STORE_UNREADABLE_KINDS` 都在包的公面上,抄一份就是 B-025 的同款根因。
6439
+
6440
+ **黑盒判据**
6441
+
6442
+ - **G32-10**:活卡帧带 `ruleStoreUnreadable: "store"` ⇒ 卡入参上逐字在场;换成 `"call"` 同理。
6443
+ - **G32-11**:durable park 行上同名键 ⇒ 卡入参上**逐字相同**(两条腿一把读器的可观察后果)。
6444
+ - **G32-12**:表外词 / 空串 / 非串 / 对象(上一代那一格的形)⇒ 卡上**键缺席**,绝不折成空串。
6445
+ - **G32-13**:`ruleStoreUnreadableDetail("store")` 与 `("call")` **逐字互异**,且都**不等于**
6446
+ `askOriginDetail("rule_store_unavailable")`(三句答三个问题)。
6447
+ - **G32-14**:`RULE_STORE_UNREADABLE_KINDS` 与实装 core 的同名表**逐词逐序相等**。
6448
+
6449
+ ---
6450
+
6451
+ ### 32e. F-4 三件小的:`autoMode.deniedSource` / audience 换档 / 码册 +1
6452
+
6453
+ #### ① `WiringManifest.autoMode.deniedSource`(core 7.14.0 `AutoModeArmFact`;**ADDITIVE**)
6454
+
6455
+ | 键 | 载体 | 形 | 缺席语义 |
6456
+ |---|---|---|---|
6457
+ | `deniedSource` | chrome 臂 `wiring_manifest` 的 `autoMode` 段(本包投影为 `_sema_autoMode`) | `"org"` / `"local"` / `"settings"`(**开集读**,`switch` 必带 `default`) | **只在 `reason === "denied"` 旁在场**;`denied` 却没有它 = 那个解析器**不记来源**(一句正面事实,不是「不知道」的同义词);`resolver_fault` / `armed` / `no_intent` / `no_face` 上**恒不在场** |
6458
+
6459
+ 🔴 本包**只在 `reason === "denied"` 上收**:core 的段内规矩是它只站在 `denied` 旁边,而这一条与本段
6460
+ 既有的 `armed === (reason === 'armed')` 互证判据**同族** —— 非投影口(宿主自建管线 / 重放存量转录)
6461
+ 喂进来的帧不过 server,一个 `{reason:'armed', deniedSource:'org'}` 会让消费端同时读到「武装了」和
6462
+ 「被 org 关掉了」。⚠️ 与 `errorCode` / `origin` 的「不校配对」不同裁:那些是**跨系统的不变量**
6463
+ (server 已按它铸),本条是**同一条帧上的段内自洽**。
6464
+ 🔴 缺席不铸:绝不折成空串,更不折成 `"settings"` 这种看起来最像的默认值 —— 那是替引擎指认一个它没
6465
+ 点名的设置面,而用户会照着去改错的那一层。
6466
+
6467
+ #### ② `memory.consolidation_withheld` audience:`user` → `operator`(**value-domain BREAKING**)
6468
+
6469
+ core 的理由逐字:这条通告**没有 `sessionId`**(一次固化跑在任何会话之外)⇒ 一个按会话路由 `user` 行的
6470
+ 消费方**必须停止**在那里等它;面向读者的那一半骑在回执上(`withheldFromCleanArm` / `withheldNeverSent`)。
6471
+ **本包落点** = `ENGINE_NOTICE_AUDIENCE` 那一行改字(抄件,不是意见;门对实装 core 逐行双向对账)。
6472
+
6473
+ #### ③ 码册 **+1**:`task.interrupt_unconsumed`(audience `user`)
6474
+
6475
+ ⚠️ **合同外加员**:它**不在** core 7.14.0 / 7.15.0 / 7.16.0 任何一份 core 仓 docs/wire-consumption 逐键表里,
6476
+ 是本批由 `run-engine-notice-catalog-test.mjs` 的 A1 段(码数双向等值)**当天红抓出**的 —— 不是人眼发现的。
6477
+ 如实登记在 §32z。五十码 ⇒ **五十一码**。
6478
+
6479
+ #### ④ 7.16.0 的两个 memory 布局码**刻意不进本册**
6480
+
6481
+ `memory.layout_migrated` / `memory.layout_unowned_root_content` 在 core 里属
6482
+ `NON_GOVERNANCE_MEMORY_CODES`(`governance-codes.js:11-27` 真字节),**不在** `ENGINE_NOTICE_CODES` /
6483
+ `NOTICE_AUDIENCE` 上。本包对非治理码的既有路由**不变**:码册外 ⇒ 呈现面 fail-closed(只落 debug)。
6484
+ 把它们抄进本册会让码册的双向对账当天红 —— 那正是这张表是**抄件**而不是意见的意思。
6485
+
6486
+ **消费方该做什么**
6487
+
6488
+ - **cli / desktop / web**:①/doctor 的 auto 行在 `reason === "denied"` 时多渲一句「被 `<deniedSource>`
6489
+ 这一层关掉的」,缺席时**什么都不多说**;②按 audience 分发的面**零改**(分发读的就是本包这张表),
6490
+ 但若为 `memory.consolidation_withheld` 写过「告诉用户」的专属文案行,那一行要跟着挪到运维面;
6491
+ ③`task.interrupt_unconsumed` 今天走**通用行**(本包无专属文案),端可按需补。
6492
+
6493
+ **黑盒判据**
6494
+
6495
+ - **G32-15**:`autoMode = {armed:false, reason:"denied", deniedSource:"org"}` ⇒ chrome 臂上三位并存;
6496
+ 换成 `{armed:true, reason:"armed", deniedSource:"org"}` ⇒ 那一位**不在场**(整段仍在)。
6497
+ - **G32-16**:`deniedSource` 为空串 / 非串 ⇒ 键不铸;为一个陌生词 ⇒ **原样过境**(开集)。
6498
+ - **G32-17**:`noticeAudienceOf("memory.consolidation_withheld") === "operator"`,而邻行
6499
+ `noticeAudienceOf("memory.hold_opened") === "user"`(整表没被读成一个值)。
6500
+ - **G32-18**:`engineNoticeInCatalog("task.interrupt_unconsumed") === true` 且 audience 为 `user`;
6501
+ `engineNoticeInCatalog("memory.layout_migrated") === false` 且其 audience 走保守缺省 `operator`。
6502
+
6503
+ ---
6504
+
6505
+ ### 32f. F-5 `TaskResult.stats.usageMissing` ⇒ 终帧 `_sema_usage_lower_bound`(**ADDITIVE**)
6506
+
6507
+ **形**(core `task-result.d.ts:609-615` 逐字):在场(`true`)= 这一面的 usage 数字是**下界**而不是一次
6508
+ 测量 —— 至少有一轮模型回合没报 usage 帧,或者这条结果是宿主 / 编排车道铸的(被拒的 spawn 的日志条目 /
6509
+ prepare 期拒绝 / 合成 abort)。**数字位仍是必填、仍是数到的那些**:`tokens: 0` 在这一位旁读作
6510
+ **unknown**,永远不是 **free**。缺席 ⇔ 每一轮都报了 usage。**Never false**。
6511
+
6512
+ **本包落点**
6513
+
6514
+ | 键 | 载体 | 缺席语义 |
6515
+ |---|---|---|
6516
+ | `_sema_usage_lower_bound: true` | CC result 帧顶层(成功臂 + 错误信封,**同一个 mint 点**) | 键不在场 ⇔ 每一轮都报了 usage;**绝不铸 `false`** |
6517
+
6518
+ **🔴 两个来源取并,不是只读 `stats`**(异源对抗复审实抓的一条真路径):`stats.usageMissing` 只在带得出
6519
+ `TaskResult` 的终帧上有,而 **`failed` 事件帧 / 409 拒绝信封 / park 体根本没有 `stats`**。只读 stats
6520
+ 的话,一条**已经**在流里报过 `turn_end{usageMissing:true}` 的 run 会在终帧上落成**判别位缺席** ——
6521
+ 按本节的合同那读作「每一轮都报了 usage」,而那种终帧的 `usage` 恰恰是全零:**「不知道」被渲成了精确零**,
6522
+ 正是本位要修的病的另一条路径。⇒ 本包在流内记下「这条流观测到过缺口」(单调布尔,只置 `true`),
6523
+ 终帧那一拍与 `stats` 的读数**取并**;主流与子流的缺口**同样算数**(下界是这条流的性质)。
6524
+ | `RunCostReconcile.usageLowerBound: true` | chrome 臂 `run_cost_reconciled` 的载荷(与终帧超集键**同一只读器** `readRunCostFacts`) | 同上 |
6525
+
6526
+ 🔴 **CC 同名键语义零改**:`usage` / `modelUsage` / `total_cost_usd` 的字节一个不动。把「不知道」折进
6527
+ 数字里(比如把 tokens 抹成 null)会让每一个既有消费者当场坏掉,而它们今天读到的是一笔**看起来已知**
6528
+ 的账 —— 那正是本位要修的病。
6529
+ 🔴 它与成本判别位 **正交**:`costAbsent` 说的是「这一段没定价」,本位说的是「数得不全」——
6530
+ 一笔定了价、但少数了几轮的账,两位可以同时在场,渲染面要**分别说**。
6531
+ 🔴 与 §31d 的 `usage._sema_total_input_tokens` **同帧不同问**:那一位答「这一行报了多少总输入」,
6532
+ 本位答「这一整条 run 的账数全了没有」。
6533
+
6534
+ **消费方该做什么**
6535
+
6536
+ - **cli(1.0.109)**:`/cost` 与 `-p --output-format json` 的用量/成本面在这一位在场时渲「≥」/「至少」
6537
+ (或一个明示的「下界」标注);**绝不**在它在场时把 `tokens: 0` 渲成「免费」。
6538
+ - **desktop / web**:同上;接 `run_cost_reconciled` 臂的端读 `usageLowerBound`,不接的端读终帧那一位。
6539
+
6540
+ **黑盒判据**
6541
+
6542
+ - **G32-19**:`done.result.stats.usageMissing === true` ⇒ 终帧上 `_sema_usage_lower_bound === true`,
6543
+ 且 `usage` / `modelUsage` / `total_cost_usd` 与不带这一位时**逐位相同**。
6544
+ - **G32-20**:`usageMissing` 为 `false` / `null` / `0` / `"true"` / `1` ⇒ 键**不铸**(严格 true 才认)。
6545
+ - **G32-21**:缺席时终帧上**没有**这个键(never false),chrome 臂上同律。
6546
+
6547
+ ---
6548
+
6549
+ ### 32g. F-6(L-228)per-subagent usage 分表(**ADDITIVE**:新 chrome 臂 + 两个终帧超集键)
6550
+
6551
+ **病**:一条 run 委派出去的那本账,core 终局**只有合计**(`stats.nested` 的
6552
+ `{tokens, turns, tasks, costMicroUsd}`,`task-result.d.ts:594-660`)——**没有 per-task 分项**。而流里
6553
+ 每一条子流的 `turn_end` 都带着它自己那一轮的 usage,本包此前在 §E2 断闸处**折而未读**(两处
6554
+ `!isSubFlow` 只让主流的 usage 出臂)⇒ 端的子代详情面只渲得出「这个子代的 usage 不知道」。
6555
+ ⇒ 分表**只能**由流内子流累加得出。
6556
+
6557
+ **🔴 主臂两处断闸一个字节不动**:子流 `turn_end` 仍然**不发** `last_turn_usage`、**不 yield**
6558
+ `turn_usage`(§E2:子代的 outputTokens 拿去对账 leader 的 responseLength 就是 token-jump 那个病)。
6559
+ 本件是**additive 的第三条腿**。
6560
+
6561
+ | 键 | 载体 | 形 | 缺席语义 |
6562
+ |---|---|---|---|
6563
+ | chrome 臂 `subagent_turn_usage` | 每条**子流** `turn_end` 一条(`required: false`) | `{ taskId, parentToolCallId, usage, engineUsage?, usageMissing?, stopReason? }`;`laneProof` 恒是 `{lane:'subagent', parentToolCallId}` | 不接本臂 = 子代用量面在那个宿主上看不见(不是报错) |
6564
+ | `_sema_nested_usage_by_task` | CC result 帧顶层(成功臂 + 错误信封) | `Record<taskId, { turns, inputTokens, outputTokens, cacheReadTokens?, usageMissing? }>` | **一行都没有 ⇒ 整键不铸** —— 空表会被读成「一个子代都没委派」,而真相可能是「委派了但这条流没看见任何一轮」 |
6565
+ | `_sema_nested_usage_by_task_partial: true` | 同上 | 判别位 | 见下;**never false** |
6566
+
6567
+ **🔴 供给面的射程边界(如实记,异源对抗复审逼出)**:core 里子代事件有**两条**外送腿,而它们
6568
+ **不等价** ——
6569
+ - **工具 ctx 的 `forwardEvent` 白名单**(`prepare-run-refs.js` 的 `forwardEvent`,`tool-spec.d.ts`
6570
+ 的同名位逐字):无条件过 `task_progress`,`forwardSubagentEvents: true` 时再加
6571
+ `text_delta` / `text_end` / `reasoning_delta` / `tool_start` / `tool_end` —— **`turn_end` 不在其中**
6572
+ (「other event types never cross it」)。⇒ 只走这条腿的部署,分表**恒零行**,而两个键按设计
6573
+ **整键不铸**(不铸空表冒充「没委派」),端读到的就是「说不出来」,不是一个假的零。
6574
+ - **委派车道自己的 tap**(同一段顶注逐字:「The delegation lane's OWN tap is trusted and forwards
6575
+ the child's FULL event stream」):子流 `turn_end` 从这条腿到达 —— 它正是 §E2 断闸当初要防的那条
6576
+ (壳实测的 token-jump:子代的 `outputTokens` 去对账 leader 的 `responseLength`)。本件消费的就是它。
6577
+
6578
+ ⇒ 本件的承诺是**包边界的**:子流 `turn_end` 到得了这条流,分表就有行;它到不了,两个键就都不在场。
6579
+ 端**不许**把「键不在场」渲成「这条 run 没委派子代」。
6580
+
6581
+ **归属钥匙**:**`sourceTaskId`** 优先,wire 缺席时回落 `parentToolCallId`;两个都读不出 ⇒ **整条不入表**
6582
+ (编一个 `"unknown"` 行会把几只子代的账混成一只)。
6583
+ 🔴 **身份位是 `sourceTaskId` 不是 `taskId`**(异源对抗复审 [high] 实抓):core 的 `TaskEventIdentity`
6584
+ 顶注逐字「the `WorkflowRun.sourceTaskId` family, **NOT a second `taskId`** — that field already exists on
6585
+ `task_progress` and a duplicate would bite consumers」⇒ 子代内容事件上**根本没有** `taskId` 这一位
6586
+ (sdk 的 `turn_end` 臂也没有声明任何身份位,两条腿都得 cast 着读)。读错的后果不是少一格:它恒缺席、
6587
+ 恒回落到父调用 id,于是**同一个父调用下的多只子任务并成一行**,而单子任务场景 turns/tasks 恰好相等、
6588
+ `partial` 甚至不铸 —— **错误归属被标成完整**。
6589
+ ⚠️ 回落本身**有损**且如实承认:真回落到父调用 id 时,若那个父调用下不止一只子任务,它们会并成一行 ——
6590
+ 那时 `partial` 会因行数对不上 `nested.tasks` 而立起来(诚实缺席优先于假装分得开)。
6591
+ **chrome 臂上两位并列**:`taskId`(行键,与终帧分表**同键** = join 键)+ `sourceTaskId?`(wire 原值,
6592
+ 缺席 = 引擎没报)。
6593
+
6594
+ **🔴 `usage` 在本臂上是可选的**(异源对抗复审 [medium] 实抓,与主臂 0.65.1 / B-088 **逐字同族**的病形):
6595
+ core 真会发**裸** `{type:'turn_end', usageMissing:true}`(无 usage、无 stopReason)。「有 usage 才发臂」
6596
+ 会让**最诚实的那一帧**整条静默 —— 实时消费者收不到缺口与停因,而终帧还没到 / 连接断了的时候,上一轮的账
6597
+ 看起来仍然完整。⇒ **三者任一在场即发**(usage / usageMissing / stopReason),三者皆缺席仍不发。
6598
+ **`cacheReadTokens`** 读的是**引擎原形** `turn_end.usage`,不是 CC 镜像 —— 镜像的
6599
+ `cacheReadInputTokens` 是**必填** number,缺席在那儿已被折成 0,从它读就再也分不出「没报」与
6600
+ 「零命中」。一轮都没报过 ⇒ 键**不铸**;报过之后再加 0 的那些轮是真的零命中。
6601
+ **`usageMissing`** 与数字**并存**:core 明说那一轮的 usage 是 UNKNOWN 不是 0 ⇒ 数字照累加(它是
6602
+ **下界**),判别位在行上立起来;把那一轮整个丢掉会让下界更假。
6603
+
6604
+ **🔴 `partial` 怎么判(设计定谳,如实写下与初版设想的差别)**:初版的形是「本条流不是从 run 起点
6605
+ 观测 ⇒ 恒铸 partial」。而本层**没有**「从不从起点观测」这个读数:`runStream` 手上只有**同一条流内**
6606
+ 的事件序号去重表,它答的是「这一帧重放过没有」,答不了「这条流之前还有没有别的帧」;`--resume` /
6607
+ 重连开出来的流与首开的流在本层**逐位不可分**。按一个读不出来的量铸判别位 = 编一件事实。
6608
+ ⇒ 判据改锚在**真正决定结果的量**上:拿引擎自己的**权威合计** `stats.nested` 对账 —— 分表的 `turns`
6609
+ 之和等于 `nested.turns` **且**行数等于 `nested.tasks` 时,这张表**可证**覆盖整条 run ⇒ 不铸 partial;
6610
+ 任何一边对不上、或 `stats.nested` 读不出来 ⇒ **铸 partial**。
6611
+ 🔴 失效方向是安全的那一侧:上游哪天让某类嵌套轮不上子流 `turn_end`,本判据只会**多**铸 partial
6612
+ (把一张其实完整的表说成不完整),**永远不会**把一张残表说成完整。
6613
+ 🔴 **两个键不互证、也不相加**:`_sema_nested_usage`(合计,引擎报的)与本表(流内看见的)是两份独立
6614
+ 的账;`partial` 在场时两者**本来就该不等**,消费方不许拿其中一份去「修正」另一份。
6615
+
6616
+ **消费方该做什么**
6617
+
6618
+ - **cli(1.0.109)**:`engineAgentView` 的子代详情面改读 `_sema_nested_usage_by_task[taskId]`
6619
+ (此前只能渲 `_sema_usage_absent`);流内实时面可接 `subagent_turn_usage` 臂。
6620
+ 🔴 `partial` 在场时那一行要明示「至少」;🔴 **绝不**把这些数加进主会话的 turn 用量 / statusline
6621
+ 窗口占用(那是 §E2 断闸要防的 token-jump)。
6622
+ - **desktop / web**:同上;不接 = 子代用量面看不见(一个可选披露面)。
6623
+ - **三端共同**:本臂(增量)与终帧分表(收口快照)是**同一份账的两个时刻**,**不相加**。
6624
+
6625
+ **黑盒判据**
6626
+
6627
+ - **G32-22**:两只 taskId 各两轮子流 `turn_end` ⇒ 终帧分表**两行**、各 `turns === 2`、token 逐轮累加;
6628
+ 同一条流上的**主流** `turn_end` **不入表**。
6629
+ - **G32-23**:同一条流上子流 `turn_end` **不产生** `last_turn_usage` chrome 臂、**不产生** `turn_usage`
6630
+ 消息臂;而主流那一拍两者**照产**(判别力自证)。
6631
+ - **G32-24**:某只子代有一轮带 `usageMissing: true` ⇒ 该行 `usageMissing === true` **且**数字仍累加了
6632
+ 那一轮;没报过的行上该键**不在场**(never false)。
6633
+ - **G32-25**:`stats.nested = {turns: N, tasks: M}` 与分表的 turns 之和 / 行数**都相等** ⇒ 终帧上
6634
+ **没有** `_sema_nested_usage_by_task_partial`;任一边不等、或 `nested` 读不出来 ⇒ 该键 `=== true`。
6635
+ - **G32-26**:零子流的一条 run ⇒ 终帧上**两个键都不在场**(不铸空对象)。
6636
+ - **G32-28**:同一个父调用下的**两只子任务**(`sourceTaskId` 不同、`parentToolCallId` 相同)⇒ 分表
6637
+ **两行**、各自的数是各自的;与权威合计对得上时**不铸** `partial`。反向:帧上挂一个 `taskId` 字段
6638
+ **不**参与归属(core 明说子代内容事件上没有这一位)。
6639
+ - **G32-29**:一条**裸** `turn_end{usageMissing:true}`(无 usage、无 stopReason)的子流轮 ⇒ 照发
6640
+ `subagent_turn_usage` 臂,臂上 `usage` 键**不在场**、判别位在场;三者皆缺席的轮**不发**。
6641
+ - **G32-30**:流里出现过 `turn_end{usageMissing:true}` 之后走 `failed`(**无 `stats`**)终帧 ⇒
6642
+ `_sema_usage_lower_bound === true`;同一条路上没出现过缺口的 run ⇒ 那一位**不在场**(never false)。
6643
+ - **G32-27**:两条并发的流各自的分表**互不串账**(分表是每条流一张,不是模块级单例);
6644
+ 🔴 **最坏的那一形也要成立**:宿主把**同一个 `EmitContext` 对象**复用给两条并发的流(`startedAtMs`
6645
+ 本来就是这么被复用的)时,两条终帧仍各报自己那一只子代 —— 包侧把「挂表」放在**终帧那一拍**、
6646
+ 与终帧铸点在同一个同步步里,先开的那条不会被后开的那条顶掉。
6647
+
6648
+ ---
6649
+
6650
+ ### 32h. 7.15.0 / 7.16.0 的其余各行(逐行理由在 §32z;这里只写**两条例外**)
6651
+
6652
+ - **7.15.0 的 `TaskSpec.deferTools` 不是「零读者」——本包是它的写者**:`src/request/taskRequest.ts`
6653
+ 的请求白名单与 `src/ultracodeWireCaps.ts` 的 `deferToolsForRequest` 铸它。7.15.0 把「它**不**被新的阈值门
6654
+ 计量」写成了明文契约,而本包的 `Workflow` 字面延迟正是靠这一条不受新阈值影响 ⇒ **零码改,但要登记**。
6655
+ - **7.15.0 的首请求 `tools[]` 形对本包有一处影响,立案未修**:自报表
6656
+ `src/liveInitToolFace.ts` 的 `ENGINE_RUNNER_FACE` 把 `ToolSearch` 写成**无条件**成员(注释逐字「引擎对模型
6657
+ 的真实请求恒声明它」),而 7.15.0 之后它**有条件**了(延迟集为空 ⇒ 无 `ToolSearch`)。阈值只有引擎
6658
+ 算得出,所以正解是让自报面改读引擎的 roster 面,不是在这里加一个猜出来的条件 ⇒ `pending`。
6659
+ - **其余 7.15.0 两行**(`RunnerDeps.deferMode` 语义 / `alwaysLoad` 族)—— **引擎构造面**,本包不铸也不读。
6660
+ `n-a`,grep 证在 §32z。
6661
+ - **7.16.0 包表面 4 + 盘面 7** —— memory engine 的目录布局是**引擎内 / 盘面**的事;本包不 import
6662
+ `@sema-agent/core`(既非 peer 也非 runtime dep)、更不碰它的盘。`n-a`,grep 证在 §32z。
6663
+ - **`Model.cost` 可选 / `isModelPriced`** —— 本包不读 core 的 `Model` 型;成本面**早就**按「缺席 =
6664
+ 未定价」办(§31c 的 `costAbsent` / `nestedCostAbsent` 两个判别位就是这条),上游把 `cost` 改成可选
6665
+ **正好印证**那条处置。`n-a`。
6666
+ - **`HoldRow.rel`(原 `relPath`)** —— 本包不读 `MemoryEngine.listHolds` 类的返回。`n-a`。
6667
+
6668
+ ---
6669
+
6670
+ ### §32z 逐键处置表(三份合同的**每一行**在本包的落点)
6671
+
6672
+ > 口径与 core 仓 docs/wire-consumption/*.md 的列一致:`consumed`(+ `路径:行` 坐标)/ `declined`(+ 理由)/
6673
+ > `n-a`(+ 理由)/ `pending`(+ 票)。**这张表是下游抄 `wire-consumption-manifest` 的母本** —— 行号会随
6674
+ > 施工漂,但 `文件#符号` 不会;有疑问以 `git show` 当时那份为准。
6675
+ > 🔴 **`n-a` 的每一行都带 grep 证**,不是「看起来没关系」。
6676
+
6677
+ #### ① core 7.14.0 —— 新增 / 变更 9 行
6678
+
6679
+ | # | 键 | 处置 | 坐标 / 理由 |
6680
+ |---|---|---|---|
6681
+ | 1 | `GateDisposition.denied.cause`(`CLASSIFIER_DENY_CAUSES` / `isClassifierDenyCause` / `DENIED_BY_MAY_CARRY_CAUSE`) | **consumed** | 过境(开集透传)`src/gateOutcome.ts` 的 `GateDispositionView.cause` + `#gateOutcomeOf`;判成员(闭集)`src/autoModeUnavailable.ts` 的 `CLASSIFIER_DENY_CAUSES` / `#isClassifierDenyCause` / `#classifierDenyCauseOf`;措辞 `#classifierDenyCauseDetail`;状态面事实源 `src/classifierStatus.ts` 的 `classifierStatusOf`。门:`run-auto-mode-unavailable-test.mjs`(A/B/C/D 段)、`run-classifier-status-test.mjs`(B/D/E 段)、`run-hitl-gate-honesty-test.mjs`(F16 继任面两格) |
6682
+ | 2 | `ASK_ORIGINS` 成员 `ancestor_marked`(**BREAKING**,替 `unresolvable`,无 alias) | **consumed** | `src/gateVocabulary.ts` 的 `ASK_ORIGIN_WORDS` + `#ASK_ORIGIN_SENTENCES`;对账基准同批从 sdk 换成 core 真字节 + sdk 滞后登记,`run-gate-vocabulary-test.mjs` B / B-lag 段 |
6683
+ | 3 | `ruleStoreUnreadable`(`AskRequest` / `PermissionResult(ask)`+`PreToolUseResult` / `AskCarry` / `PendingAction.tool_approval` / `CheckpointSummary`)∈ `store\|call` | **consumed** | 词表与措辞 `src/gateVocabulary.ts` 的 `RULE_STORE_UNREADABLE_KINDS` / `#isRuleStoreUnreadableKind` / `#ruleStoreUnreadableDetail`;卡面两腿 `src/hitl/toolApprovalWire.ts` 的 `ApprovalCardRequest.ruleStoreUnreadable`(活卡帧腿 `#ToolApprovalFrame.ruleStoreUnreadable` + durable 腿 `#readRuleStoreUnreadable`,**同一把窄读器**)。门:`run-gate-vocabulary-test.mjs` R 段、`run-durable-card-display-keys-test.mjs` (12) 段、`run-hitl-gate-honesty-test.mjs` F16 段、`run-approval-frame-keys-test.mjs` 的 AHEAD_OF_ANCHOR 登记。⚠️ `AskCarry` / `PermissionResult` 两处载体本包**不读**(它们是引擎内 carry / 策略回值面),消费的是 ask 帧与 park 行两处 |
6684
+ | 4 | `WorkflowRun.errorCode?: string`(`workflow.agent_parked` 等) | **pending**(cli L-235;core #724 [7043] additive 补 run 级 errorCode 后本包补投影) | 🔴 **本包今天到不了它**,两条腿逐字节核过:① 本包投影的 TaskOutput 文本腿吃的是 core `formatWorkflowRun`(`dist/core/task-registry-shared.js#formatWorkflowRun`)的 JSON,那只函数**不发 run 级 `errorCode`**(只发 `agent_runs[].errorCode`);② 列表行腿 `dist/core/workflow-run-store.js#summarizeWorkflowRun` 同样没有。第三条腿 `GET /v1/workflows/:id` 的 sdk 型面(`@sema-agent/sdk/dist/types.d.ts#WorkflowRun`)**无此声明**,且本树未装 server fixture ⇒ 证不出 service 有没有转投。按本仓「core 定型 ≠ 壳可消费,先核 core→service→壳全链放行」办:**不猜载体**(猜对了是白写,猜错了是拿另一个量冒充),立案跟 server/sdk 补投。⚠️ 顺带登记一条**存量**:`agent_runs[].errorCode` 今天**在** JSON 上而本包的 `projectWorkflowTaskOutput` 只渲 `error` 首行不渲码 —— 那是 0.2.0 起的既有决定(`run-client-core-pure-test.mjs` 有一条具名钉),不属本合同行,另议 |
6685
+ | 5 | `memory.consolidation_withheld` audience `user` → `operator`(**value-domain**) | **consumed** | `src/engineNoticeCodes.ts` 的 `ENGINE_NOTICE_AUDIENCE`(那一行改字);门 `run-engine-notice-catalog-test.mjs` A/B 段双向对账 + E1 具名钉 + E1-neg 判别力自证 |
6686
+ | 6 | `TaskResult.stats.usageMissing?: true` | **consumed** | `src/adapter/downstream/terminalToSdkResult.ts` 的 `RunCostReconcile.usageLowerBound`(读点在 `#readRunCostFacts`)+ 终帧超集键 `#_sema_usage_lower_bound`(成功臂与错误信封**同一个 mint 点**)+ chrome 臂 `run_cost_reconciled` 同源;🔴 **两个来源取并**:`stats.usageMissing` 只在带得出 `TaskResult` 的终帧上有,而 `failed`/409/park 体没有 stats ⇒ 流内观测到的 `turn_end{usageMissing:true}` 同样立位(否则那种终帧的全零 usage 会被读成精确零)。门 `run-cost-reconcile-projection-test.mjs` F 段 + `run-subagent-usage-projection-test.mjs` I4 段 |
6687
+ | 7 | `reasoningEffortLevelsOf(model)`(export) | **n-a** | 引擎 brain 面的解析口(core 仓 src/brain/reasoning.ts),本包不 import `@sema-agent/core`、也不在任何请求面消费 tier 集合。grep 证:`src/` 全树 `reasoningEffortLevelsOf` **0 命中** |
6688
+ | 8 | `RuntimeCaps.autoModeDenySource`(resolver **INPUT**) | **n-a** | 它是引擎 resolver 的**输入**位(`RuntimeCaps` 由部署侧喂给引擎),本包是响应面客户端库,不铸 `RuntimeCaps`。grep 证:`src/` 全树 `autoModeDenySource` **0 命中**。⚠️ 它的**输出**对偶(`WiringManifest.autoMode.deniedSource`)是下一行,已 consumed |
6689
+ | 9 | `WiringManifest.autoMode.deniedSource`(`AutoModeArmFact`) | **consumed** | `src/adapter/downstream/eventToSdkMessage.ts` 的 `WiringManifestAutoMode.deniedSource` + `#projectAutoModeSection`(只在 `reason === "denied"` 上收的段内自洽判据);门 `run-wiring-manifest-projection-test.mjs` P4-ds 段(含上游逐字出处三格) |
6690
+
6691
+ #### ② core 7.14.0 —— 退役 8 行(**BREAKING**;下游门 grep 零命中)
6692
+
6693
+ | # | 退役键 | 处置 | 坐标 / 理由 |
6694
+ |---|---|---|---|
6695
+ | 1 | `PermissionDeniedPayload.classifierUnavailable` | **n-a** | 本包**从不读** `PermissionDeniedPayload`(那是引擎的观察者载荷;本包读的是 `tool_end.gate`)。grep 证:`src/` 全树 `permissionDenied` 仅 1 处**注释**命中(`src/classifierVerdictWire.ts` 的沿革说明),零代码位置 |
6696
+ | 2 | `PermissionResult(deny).classifierUnavailable`(含 alias 面 `PreToolUseResult`) | **n-a** | 同上:`PermissionResult` / `PreToolUseResult` 是**策略回值**面(引擎内),本包零读点。grep 证:`src/` 全树 `PreToolUseResult` **0 命中**;`PermissionResult` 仅 2 处**注释**命中(两处沿革说明),零代码位置 |
6697
+ | 3 | `PermissionResult(ask).classifierUnavailable` | **n-a** | 同上 |
6698
+ | 4 | `AskRequest.classifierUnavailable`(tool_approval 卡 / inbox 行) | **consumed(retired)** | 本包**读过**这一格 ⇒ 按 clean-cut 删码:卡位 / 帧位 / 窄读器 / 公面读器与措辞四处全删,继任者见 ①-1。登记在 `run-retired-vocabulary-census-test.mjs`(上游真没了 + src 代码位置零命中 + 公面零导出三向),反钉在 `run-auto-mode-unavailable-test.mjs` 的公面反钉段与 `run-durable-card-display-keys-test.mjs` (12) 的退役反钉三格 |
6699
+ | 5 | `AskCarry.classifierUnavailable` / `AskRequestCarry.classifierUnavailable` | **n-a** | carry 是**引擎内**的 park / request 携带面,本包零读点。grep 证:`src/` 全树两名各仅 1 处**注释**命中(`src/autoModeUnavailable.ts` 的退役沿革段),零代码位置 |
6700
+ | 6 | `PendingAction.tool_approval.classifierUnavailable` / `CheckpointSummary.classifierUnavailable` | **consumed(retired)** | 本包的 durable 腿读过它 ⇒ 同 ②-4 一并 clean-cut;旧耐久行带旧键时投影**忽略**(不读不渲不崩),门 `run-durable-card-display-keys-test.mjs` (12) 段三格 |
6701
+ | 7 | `ASK_ORIGINS` 成员 `unresolvable` | **consumed(retired)** | `src/gateVocabulary.ts` 的词表与句表各删一员,**无 alias**;非成员的旧值走开集兜底句。登记在 census 表(判据锚**带引号的字面量**,避开 `delegation.ask_unresolvable` / `rewind_snapshot.unresolvable` 两个**不相干**的码) |
6702
+ | 8 | `AskOriginFacts.ruleStore: "unavailable"`(型面**输入**词) | **n-a** | `AskOriginFacts` 是引擎门的**派生输入**(只有门自己持有),本包零读点。grep 证:`src/` 全树 `AskOriginFacts` **0 命中**;它的**输出**对偶已 consumed(见 ①-3) |
6703
+
6704
+ #### ③ core 7.15.0 —— 语义变更 4 行、退役 0 行
6705
+
6706
+ | # | 键 | 处置 | 坐标 / 理由 |
6707
+ |---|---|---|---|
6708
+ | 1 | `RunnerDeps.deferMode` 语义变更(阈值门;非 `"auto"` 值在 prepare 期 refuse) | **n-a** | `RunnerDeps` 是**引擎构造面**,本包不铸它。grep 证:`src/` 全树 `deferMode` **0 命中** |
6709
+ | 2 | 首请求 `tools[]` 形:占位符 ⇔ 延迟集非空;`ToolSearch` 在场 ⇔ 延迟集非空(**新输入**) | **pending**(cli L-236;core [7043] 判对:自报面改读 tool_roster 快照/delta) | 🔴 **不是零影响,如实登记**:本包的「引擎 runner 恒挂工具面」自报表把 `ToolSearch` 写成**无条件**成员(`src/liveInitToolFace.ts` 的 `ENGINE_RUNNER_FACE` 的 `'ToolSearch'` 行,注释逐字「引擎对模型的真实请求恒声明它」)。7.15.0 之后这句话**有条件**了:小 MCP roster 在阈值以下 ⇒ 延迟集为空 ⇒ 无 `ToolSearch`。今天多数请求仍带本包显式铸的 `deferTools`(见下一行)⇒ 延迟集非空 ⇒ 自报仍然对;但命中激活源、且 roster 在阈值以下的那一形自报会偏。**正解不是在这里加条件**(阈值只有引擎算得出),而是让自报面改读引擎的 roster 面 —— 立案另批 |
6710
+ | 3 | `TaskSpec.deferTools` 语义**不变**(字面延迟,现明说**不**被阈值门计量) | **consumed(写面)** | 🔴 与本合同其余行不同:这一键是本包**铸**的,不是读的 —— `src/request/taskRequest.ts` 的 `TaskRequestInput.deferTools`(白名单 `:67` 行)与 `src/ultracodeWireCaps.ts` 的 `deferToolsForRequest`。语义不变 ⇒ **零码改**;登记在册是因为 7.15.0 把「它不被阈值门计量」写成了明文契约,而本包正是靠这一条让 `Workflow` 的字面延迟不受新阈值影响 |
6711
+ | 4 | `TaskSpec.alwaysLoadTools` / `ToolSpec.alwaysLoad` / MCP `_meta["anthropic/alwaysLoad"]` 语义不变(现明说**不**被计量) | **n-a** | 本包不铸也不读这三处任何一处。grep 证:`src/` 全树 `alwaysLoad` **0 命中** |
6712
+
6713
+ #### ④ core 7.16.0 —— 包表面 4 / 盘面 7 / 通告码 2 / `Model.cost` 2
6714
+
6715
+ | # | 键 | 处置 | 坐标 / 理由 |
6716
+ |---|---|---|---|
6717
+ | 1 | `MemorySessionHandle.writableRoot: string \| null`(**BREAKING**) | **n-a** | memory engine 的**包表面**;本包不 import `@sema-agent/core`(既非 peer 也非 runtime dep)。grep 证:`src/` 全树 `writableRoot` **0 命中** |
6718
+ | 2 | `MemoryEngine.readonlyDirNamesUnderRoot(handle)` 移除 | **n-a** | 同上。grep 证:全树 **0 命中** |
6719
+ | 3 | `scanEntryFiles(dir, { exclude })` 的 `exclude` 移除 | **n-a** | 同上。grep 证:全树 `scanEntryFiles` **0 命中** |
6720
+ | 4 | `writableRootOf(handle)`(新 export) | **n-a** | 同上。grep 证:全树 **0 命中** |
6721
+ | 5 | `scopes.json` `{v:2,…}` | **n-a** | 盘面控制平面,本包不碰引擎的盘。grep 证:全树 `scopes.json` **0 命中** |
6722
+ | 6 | `projection-debts.json` v2 行形 | **n-a** | 同上。grep 证:全树 **0 命中** |
6723
+ | 7 | `holds.json` v2(`rel` 替 `relPath`;`HoldRow.rel`) | **n-a** | 同上;本包也不读 `listHolds` 类返回。grep 证:全树 `holds.json` / `relPath` 各 **0 命中** |
6724
+ | 8 | `session-accounts.json` v2 | **n-a** | 同上。grep 证:全树 **0 命中** |
6725
+ | 9 | `scan-fuse.json` v2 | **n-a** | 同上。grep 证:全树 **0 命中** |
6726
+ | 10 | `index-revs.json` 被 adoption 清空 | **n-a** | 同上。grep 证:全树 **0 命中** |
6727
+ | 11 | `<memoryDir>/<label>/…` 每个 scope 多一级目录 | **n-a** | 用户可见**路径值**变化,而本包不渲 memory 条目路径、也不按路径记账(`HarvestReport` 的按 `code` 计数在 server 侧)。grep 证:全树 `memoryDir` **0 命中** |
6728
+ | 12 | 通告码 `memory.layout_migrated` | **n-a(路由不变)** | 它属 core 的 `NON_GOVERNANCE_MEMORY_CODES`(`governance-codes.js:11-27` 真字节),**不在** `ENGINE_NOTICE_CODES` / `NOTICE_AUDIENCE` 上 ⇒ 本包对非治理码的既有路由不变(码册外 ⇒ 呈现面 fail-closed 只落 debug)。抄进码册会让双向对账当天红;反钉在 `run-engine-notice-catalog-test.mjs` E3 段 |
6729
+ | 13 | 通告码 `memory.layout_unowned_root_content` | **n-a(路由不变)** | 同上 |
6730
+ | 14 | `Model.cost?: {...}`(由必填改可选) | **n-a** | 本包不读 core 的 `Model` 型(模型面走 sdk / 本包自己的目录形)。成本面**早就**按「缺席 = 未定价」办(§31c 的 `costAbsent` / `nestedCostAbsent` 两个判别位),上游这次改动**正好印证**那条处置 |
6731
+ | 15 | `isModelPriced(model, pricing)`(新 export) | **n-a** | 同上:本包不做定价判定,只透传引擎报的 micro-USD 与两个缺席判别位。grep 证:全树 `isModelPriced` **0 命中** |
6732
+ | 16 | `HarvestReport.*.path` / `MEMORY_INSTRUCTION_TEMPLATE` / 可写目录准入(**声明为非 wire 改动**) | **n-a** | 三者本包皆零读点(前者在 server 侧按 `code` 计数,后两者是引擎内)。grep 证:全树 `HarvestReport` / `MEMORY_INSTRUCTION_TEMPLATE` 各 **0 命中** |
6733
+
6734
+ #### ⑤ 合同外加员(本批由门当天红抓出,不在任何一份逐键表里)
6735
+
6736
+ | # | 键 | 处置 | 坐标 / 理由 |
6737
+ |---|---|---|---|
6738
+ | 1 | `ENGINE_NOTICE_CODES` 加员 `task.interrupt_unconsumed`(audience `user`) | **consumed** | `src/engineNoticeCodes.ts` 的 `ENGINE_NOTICE_CODES` + `#ENGINE_NOTICE_AUDIENCE`;由 `run-engine-notice-catalog-test.mjs` A1 段(码数 51 vs 50)当天红抓出,**不是人眼发现的**。已如实登记为合同外加员 —— 上游下一批若把它补进逐键表,本行可并入 |
6739
+
6740
+ #### ⑥ 本批的 BREAKING 清单(下游必读)
6741
+
6742
+ | # | 面 | 变更 | 下游动作 |
6743
+ |---|---|---|---|
6744
+ | 1 | 包公面导出 | **删** `classifierUnavailableOf` | 改调 `classifierDenyCauseOf(门记录)`(编译期红) |
6745
+ | 2 | 包公面导出 | **删** `classifierUnavailableDetail` | 改调 `classifierDenyCauseDetail(cause)`(编译期红) |
6746
+ | 3 | 包公面类型 | **删** `ClassifierUnavailableView` | 该读数形随卡位一并退役 |
6747
+ | 4 | 卡面 / 帧面键 | `ApprovalCardRequest.classifierUnavailable` 与 `ToolApprovalFrame.classifierUnavailable` **删**,同位换成 `ruleStoreUnreadable` | 读旧键的端改读门记录;渲规则店机制的端读新键 |
6748
+ | 5 | 词表值域 | `ASK_ORIGIN_WORDS`:`unresolvable` → `ancestor_marked`(无 alias) | origin 的 `switch` / 映射表改词,`default` 臂必须在 |
6749
+ | 6 | audience 值域 | `memory.consolidation_withheld`:`user` → `operator` | 按 audience 分发的面自动跟随;为它写过「告诉用户」专属行的端把那一行挪去运维面 |
6750
+ | 7 | 状态面事实源 | `classifierStatusOf` 第二参从「一只 ask」变成「本轮那一次观测(ask / 耐久行 / 带 `gate` 的 `tool_end` 帧 / 门记录本体)」 | 签名与三态词表**未改**(不是编译期 BREAKING),但**喂什么**变了:端要把本 turn 的门记录喂进去,否则那一态恒不出现 |
6751
+
6752
+ ---