@sema-agent/client-core 0.65.0 → 0.66.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.0**(本批发布版;内容批 = 两车合并 commit 79610d7:① 投影臂族归层修 B-071 / B-072 / B-073 / B-074 / L-215③ ② 接入审计 B 战役包侧四件 B-070 / B-078 / L-215①② / B-080;🔴 本版有 BREAKING = 熔断族公面 clean-cut(`AUTO_MODE_BREAKER_CAUSES` / `classifierBreakerOf` / `ClassifierBreakerView` / `autoMode.breaker` / `breaker_open`),其余 additive;逐件见 §30a–§30n,`CHANGELOG.md` `## 0.65.0(2026-09-11)`;bump 与冻结账两阶段由发包批做) | `package.json` `version` |
22
+ | 本包 | `@sema-agent/client-core` **0.66.0**(本批发布版 = minor:内容批 3c0ac0e,终局真值三件 L-192① / B-068·L-198 / L-192②,全部 additive,详见 §31a–§31f;0.65.x §30;`CHANGELOG.md` `## 0.66.0(2026-09-11)`;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
+ | 公开导出面 | **929** 个运行期符号(+ 44 个测试钩;= 工作树当下的值 = 工作树里另有 **0.66.0 未发的一件 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`(**929** 项)。
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
+ 929 项的内部构成(帮助端估读表大小):**283** 项是 `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 域,逐域计数之和 = 929)
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` |
@@ -5546,6 +5546,9 @@ running 拍**逐字节同形**,面板行只能等一次**防御 sweep**(而它
5546
5546
  isError:false}` 恰一条);修前该行要等到关卡 sweep 或通知帧。
5547
5547
  - **G30-10**:子代失败时该 end 的 `isError === true`。
5548
5548
  - **G30-11**:同一 taskId 收到两拍终态(重放 / 双腿投递)⇒ `panel_task{kind:'end'}` 仍**恰一条**。
5549
+ 🔴 **0.65.0 对「终态 tick → task_notification」这个顺序不成立**(test [6961] 对抗复审轨实抓;B-087):通知腿
5550
+ `settleFromNotification` 拆分时逐字保留了「先发 end 再判重」的旧次序,判重只护着 if-started stop。**0.65.1 起**
5551
+ 判重移到该腿唯一的 yield 之前(与 tick 腿 / 关卡腿同形),两个到达顺序都恰一条;门 B5a/B5b 钉。
5549
5552
  - **G30-12**(负控):一台**只发 running、不发终态 tick** 的旧引擎上,子代行的行为与修前逐字相同。
5550
5553
  - **G30-13**(负控):workflow 子代即使带终态 `status`,前台面板**零事件**(lane 门仍在最前)。
5551
5554
 
@@ -5627,7 +5630,8 @@ settle 腿共用的 `endedPanelTasks` **只按 taskId 判重** ⇒ 第一代落
5627
5630
  | `turn_end.usageMissing === true` | **不铸**镜像,改铸 `_sema_usage_missing: true` | 同行加 `usageMissing: true` |
5628
5631
  | 真零账(没有 `usageMissing`) | 照铸镜像(全零),判别位不铸 | 不铸判别位 |
5629
5632
  | `usage` 整体缺席但有 `stopReason` | 本臂**照发**(不带 `outputTokens` 键) | 不发(那条腿的 `usage` 是必填位) |
5630
- | 两者都缺席 | 不发(既有行为一字未动) | 不发 |
5633
+ | `usageMissing: true`(无 `usage`、无 `stopReason`;core 真铸形,该轮零 usage 帧时无 `usage` 字段) | **0.65.1 起照发**:只带 `_sema_usage_missing: true`,三键(`outputTokens`/镜像/`_sema_stop_reason`)都不铸(0.65.0 整条静默 = B-088) | 不发(那条腿的 `usage` 是必填位) |
5634
+ | 三者(`usage`/`stopReason`/`usageMissing`)都缺席 | 不发(既有行为一字未动) | 不发 |
5631
5635
 
5632
5636
  - **`usageMissing`**:core 的臂注逐字「Consumers must treat the missing usage as UNKNOWN — **not
5633
5637
  zero**」,而它与 `usage` **可以同帧**。把它剥掉,这条新通道就会把「不知道」渲成一笔全零的**已知**
@@ -5654,6 +5658,9 @@ settle 腿共用的 `endedPanelTasks` **只按 taskId 判重** ⇒ 第一代落
5654
5658
  而有 `_sema_usage_missing === true`;换成同形的**真零账**则相反(两档逐字可分)。
5655
5659
  - **G30-24**:`turn_end{usageMissing:true, stopReason:"error"}` 产出恰一条 `turn_usage`,带
5656
5660
  `_sema_stop_reason === "error"` 且**没有** `outputTokens` 键。
5661
+ - **G30-24b**(0.65.1 / B-088):裸 `turn_end{usageMissing:true}`(无 `usage`、无 `stopReason`)产出**恰一条**
5662
+ `turn_usage`,只带 `_sema_usage_missing === true`;`outputTokens` / `_sema_last_assistant_usage` / `_sema_stop_reason`
5663
+ 三键都不在场。`turn_end{}`(三者皆缺席)仍不发。
5657
5664
  - **G30-25**:一条 durable run 的每条 assistant 转录行都带 `message.id`/`message.model`;live 分段腿
5658
5665
  上 `model` 来自宿主钉的值而 `id` **不出现**。
5659
5666
 
@@ -5978,3 +5985,276 @@ server 7.70.0([6927])读面同批收窄。
5978
5985
  (源码扫描零铸点)⇒ 加词对本包**零落点**。归属登记:**候 sdk 镜像**(D1 是它的到货哨兵);
5979
5986
  哪天 sdk 镜像了,D1 红 ⇒ 那一批同时铸措辞表并把 D2 退役。
5980
5987
 
5988
+ ---
5989
+
5990
+ ## §31 🆕 0.66.0 内容批(**终局真值三件**:L-192① `permission_denials` + B-068 / L-198 成本对账 + L-192② 终帧 usage 三格)
5991
+
5992
+ ### 31a. 本节速览
5993
+
5994
+ | 件 | 一句话 | 端要做什么 |
5995
+ |---|---|---|
5996
+ | ① L-192① | 终帧拒绝清单不再硬编 `[]`:被拒行逐条进 **sema 载体** `_sema_permission_denials`,CC 数组只收**三键齐全**的记录(今天恒空,上游补齐即自动填)+ 「这条清单不可声称完整」判别位 | 渲拒绝清单的端**改读 sema 载体**(壳里本地铸 `[]` 的两处退役);CC 那条 `[]` 必须与判别位**合读** |
5997
+ | ② B-068 / L-198 | `costBreakdown` / `nested` 两段投上终帧超集键 + 新增终局 chrome 臂 `run_cost_reconciled`;`total_cost_usd` **语义零改** | 成本面接**终局对账**(own / nested / compaction 三段);不接 ⇒ 子代与压缩两笔账永远不进账 |
5998
+ | ③ L-192② | 终帧扁平 `usage`:`webSearchRequests` 从**字面量 0** 改开集宽读 + 缺席判别位;新增 cache-INCLUSIVE 总量座位 `_sema_total_input_tokens`、长 TTL 缓存写入座位 `_sema_cache_write_tokens_long`;终局 per-model 行同批补三座位(总量 / 口径标记 / 长 TTL);🔴 `inputTokens` **仍是 cache-MISS 分量**(不灌总量) | 只读现有四格的端**零改**;要「这条 run/这个模型摆了多少上下文」的端改读新座位 |
5999
+
6000
+ **共同形**:三件都是「上游把事实摆在 wire 上,而**包边界用一个字面量把它答成常数**」——
6001
+ `permission_denials: []` / `webSearchRequests: 0` / 整段 `costBreakdown` 不投,是 0.65.0 那一批
6002
+ (`toolFaces` / `model` / `cacheWriteTokens`)的同族第 N 例。**共同处置**也只有一条:
6003
+ CC 形上必填的位**值不动**(旧消费者逐字不变),把「不知道」交给同行的 `_sema_` 判别位;
6004
+ CC 形上没有的事实**另开超集座位**,绝不改 CC 同名键的语义。
6005
+
6006
+ **出处**:cli 台账 `L-192`(①②)/ `B-068` 与 `DEBTS-cli L-198`(②)。合同真源 = 实装 devDep
6007
+ `@sema-agent/core` 7.12.0 的 `dist/core/task-result.d.ts`(`humanReview` 的 gate 账本 /
6008
+ `costBreakdown` 的对账两式 / `promptTokens` 与 `totalInputTokens` 的 RB-457-a 语义翻转)、
6009
+ `dist/core/tool-spec.d.ts`(`NestedUsage`)、`@sema-agent/sdk` 8.8.0 的 `dist/types.d.ts`
6010
+ (`TaskStats.costBreakdown?: unknown` 开集透传 / `humanReview.gates` 的 live 钉死键面)与
6011
+ `@sema-agent/agent-types` 0.2.0 的 `permissions.d.ts`(CC `SDKPermissionDenial` 三键真形)。
6012
+
6013
+ ---
6014
+
6015
+ ### 31b. ① L-192① 终帧 `permission_denials`(core ≥7.12.0 `TaskStats.humanReview`)
6016
+
6017
+ **病**:CC 的 `SDKResultSuccess` / `SDKResultError` 上有一格 `permission_denials`
6018
+ (「这条 run 里有哪些工具调用被拒了」),而包边界在**两处**(成功臂 + 错误信封)硬编 `[]`。
6019
+ 代价不是少一格数据,是**两句话被折成一句**:「这条 run 一次都没被拒」与「这条帧根本没有这本账」
6020
+ (老引擎 / 409 拒绝信封 / `failed` 事件帧都不带 `stats`)在 CC 形上都是 `[]`。
6021
+
6022
+ **键名与载体**
6023
+
6024
+ | 键 | 载体 | 来源 | 缺席语义 |
6025
+ |---|---|---|---|
6026
+ | `permission_denials[]` | CC result 帧(成功臂 + 错误信封) | 上面那本账里**三键齐全**的记录 | 今天恒 `[]`(wire 给不出后两键);`[]` 本身**不是**缺席(见判别位) |
6027
+ | `_sema_permission_denials[]` | 同上(超集键) | `TaskStats.humanReview.gates[]` 里 `decision === "deny"` 的行,**逐条一记录、顺序 = wire 顺序** | 整键不铸 = 没读出任何被拒记录 |
6028
+ | `…[].tool_name` | 两条清单共用的记录形 | `gates[].toolName` | 键不铸 = 这条腿没报工具名(**绝不编一个**) |
6029
+ | `…[].tool_use_id` / `…[].tool_input` | 同上 | 开集预读 `gates[].toolCallId` / `toolInput`(**今天 wire 上没有**) | 键不铸;**绝不**铸 `""` / `{}` |
6030
+ | `…[]._sema_tool_arg` | 同上(超集键) | `gates[].toolArg` —— 引擎侧已脱敏截短的**一行入参摘要** | 键不铸 = 这条腿没串入参(同步 ask 腿有、耐久 resume 腿没有) |
6031
+ | `_sema_permission_denials_absent` | CC result 帧顶层(超集键) | 见下面四条路径 | **只在该说话时**为 `true`;绝不铸 `false` |
6032
+
6033
+ **🔴 为什么是两条清单**:CC 的 `SDKPermissionDenial` 三键 `tool_name` / `tool_use_id` / `tool_input`
6034
+ **全是必填**(`agent-types` 与本包对照的会话词汇 zod 皆然),而 wire 上这本账的真形是 core 的 gate
6035
+ 记录 —— 只有 `kind` / `waitMs` / `decision?` / `toolName?` / `toolArg?` **五格**,既没有 `toolCallId`、
6036
+ 也没有被拒时的入参对象(core 逐字:「a durable-resume gate carries `toolName` only (its input is not
6037
+ threaded onto the persisted gate — a documented follow-on)」;sdk 的同一格亦逐字记着 `tool_input` /
6038
+ `toolInput` **不在** gate ledger 上)。两条路都不能走:**补零补空 = 编造**;**把半条记录塞进 CC 数组
6039
+ = 破坏元素契约** —— 严格消费方 `safeParse` 会把**整条 result 帧**判非法(丢一格 vs 丢整帧,后者严重
6040
+ 得多)。⇒ CC 数组只收三键齐全的记录,wire 上真有的每一条走 sema 载体。
6041
+ **自动升级腿**:上游哪天把两格串上账本,CC 数组**自己**就开始填(包侧一行不用改),判别位随之退场;
6042
+ 常驻门里有那一条的正控 + 今天的**缺席证据**(锚 core 的 `gates` 声明块),上游一动当天红。
6043
+
6044
+ **🔴 两键合读**(判别位 = 「CC 那条清单**不可声称完整**」,四条路径:①账本整个读不出 ②有读不出的行
6045
+ ③有**认不出的判词**(两张判词表之外的词 / 判词缺席)④有被拒记录没能铸成 CC 形)
6046
+
6047
+ | `permission_denials` | `_sema_permission_denials_absent` | 含义 | 端该渲什么 |
6048
+ |---|---|---|---|
6049
+ | `[]` | 缺席 | 账读得出且逐行判得出,**零拒绝** | 「本次无拒绝」(一句正面事实) |
6050
+ | `[]` | `true` | 清单不完整(没有账 / 有读不出的行 / 有认不出的判词 / 有记录只在 sema 载体上) | 不渲肯定句;改读 `_sema_permission_denials` |
6051
+ | 非空 | 缺席 | 有 N 次拒绝且每条都齐全 | 逐条渲 |
6052
+
6053
+ **🔴 开集判词**:只有 `deny` 被读成「工具调用被拒」;`allow` / `approve` / `edit` / `reject` 是
6054
+ **认得出的非拒绝**(计划复核的否决是「人否了一份**计划**」,不是 CC 说的 "One auto-denied **tool
6055
+ call**")—— 这两张表之外的词、以及**缺判词的行**(耐久 wake 腿真会这样)一律**不猜**:不铸 denial,
6056
+ 但让这份清单失去「完整」资格(判别位立起来)。坏行(非对象)**只丢自己**,不丢整本账;而键都读不出
6057
+ 的被拒行**仍然占一条** ——「被拒了几次」是这本账最要紧的事实。
6058
+
6059
+ **黑盒判据(test 视角可执行)**
6060
+
6061
+ - **G31-1**:一条 run 里让审批人**拒**掉一次工具调用(如 `Bash`),`-p --output-format json` 的
6062
+ `_sema_permission_denials` **恰有一条**,`tool_name === "Bash"`,且该条**没有** `tool_use_id` /
6063
+ `tool_input` 两键(修前这条记录整个不存在);同帧 `permission_denials === []` 且
6064
+ `_sema_permission_denials_absent === true`。
6065
+ - **G31-2**:同一条 run,若拒的是**同步 ask** 腿,该条带 `_sema_tool_arg`(非空串、与引擎账本一致);
6066
+ 若拒的是**耐久 resume** 腿,该键不出现。
6067
+ - **G31-3**:一条**全程无人工门**的 run:`permission_denials === []`、**没有**
6068
+ `_sema_permission_denials` 键、**没有** `_sema_permission_denials_absent` 键。
6069
+ - **G31-4**:一条被 409 拒绝(或以 `failed` 事件终止)的 run:`permission_denials === []` 且
6070
+ `_sema_permission_denials_absent === true`。
6071
+ - **G31-5**(负控):任一情形下 `_sema_permission_denials_absent` **都不会是 `false`**;
6072
+ 任一情形下 `permission_denials` 里的元素**要么三键齐全、要么这个数组是空的**(半条记录永不进 CC 面)。
6073
+
6074
+ ---
6075
+
6076
+ ### 31c. ② B-068 / L-198 终局成本对账(core ≥7.12.0 `costBreakdown` / `nested`)
6077
+
6078
+ **病**:core 把一条 run 的花费**拆开**摆在 wire 上并给了两条对账式(`task-result.d.ts` 逐字):
6079
+
6080
+ - `llmRootMicroUsd + compactionMicroUsd === costMicroUsd` —— **压缩花费在 own 里面**;
6081
+ - fully-reconciled spend = `costMicroUsd + nested.costMicroUsd` —— **子代花费在 own 外面**
6082
+ (core 逐字:`costMicroUsd` deliberately EXCLUDES nested)。
6083
+
6084
+ 而包边界**一格都不投**:`costBreakdown` 与 `nested` 整段被剥,终帧只剩一个 `total_cost_usd`,
6085
+ 于是成本面永远看不见子代与压缩两笔账(`/cost` 与 `-p` 低报)。
6086
+
6087
+ **键名与载体**
6088
+
6089
+ | 键 | 载体 | 来源 | 缺席语义 |
6090
+ |---|---|---|---|
6091
+ | `_sema_cost_breakdown` | CC result 帧顶层(超集键) | `TaskStats.costBreakdown`,**micro-USD 原值**(键名即单位,包不折 USD) | 整键不铸 = 这条 run 没有明细(core 在 unpriced 时与 `costMicroUsd` 一起省略);单键不铸 = 那一类读不出 |
6092
+ | `_sema_nested_usage` | 同上 | `TaskStats.nested`(`tokens`/`turns`/`tasks`/`costMicroUsd`) | 整键不铸 = **没委派过**(判据是**原始载体**在不在,不是过滤产物空不空);键在场而其 `costMicroUsd` 不铸 = 委派过但那本账**没定价/读不出**(core 逐字 `never a fabricated 0`)—— 键在场但值为空对象是合法的一句话 |
6093
+ | chrome 臂 `run_cost_reconciled` | `ChromeEvent`(新臂,`required: false`) | 与上面两键**同一个读器**(`readRunCostFacts`) | 整条不发 = 这条终帧没有 `stats`(409 / park 体 / `failed` 事件帧) |
6094
+ | `total_cost_usd` | CC result 帧(**CC 同名键**) | `TaskStats.costMicroUsd / 1e6` | **语义一字未改**(见下) |
6095
+
6096
+ **臂载荷**:`{ ownMicroUsd?, nestedMicroUsd?, compactionMicroUsd?, llmRootMicroUsd?,
6097
+ reconciledMicroUsd?, costAbsent?, nestedCostAbsent? }`。
6098
+ `reconciledMicroUsd = own + nested` **只在两边都知道、且和本身是有限数时才铸**;own 没定价 ⇒
6099
+ `costAbsent: true`,委派过但那本账没定价/读不出 ⇒ `nestedCostAbsent: true`,两种情形下对账值
6100
+ **都不铸**(不知道就是不知道)。🔴 「委派过」这件事的判据是 `stats.nested` **这个载体在不在**,
6101
+ 不是它里面有没有读得出的数 —— 否则一条 `nested: {}` 会被当成「没委派」,于是 own 被铸成一个
6102
+ **确定的总额**,而真相是「委派过、花了多少不知道」。
6103
+
6104
+ **🔴 `total_cost_usd` 为什么不把 nested 折进去**:它是 **CC 同名键**,生态里读它的人默认它是
6105
+ CC 那个语义;把子代花费折进去 = 在一个已有的位上塞我们自己的口径(超集键纪律明令禁止),
6106
+ 而且会让「own 花费」这个量在整条链上再也说不清。⇒ 包给的是**可对账的事实**,不是一个改了口径的
6107
+ 数:要 fully-reconciled spend 的端**自己加**(`own + nested`),而且加之前要先看两个判别位。
6108
+
6109
+ **🔴 为什么另起一条 chrome 臂而不是扩 `last_turn_usage`**:那条臂的宿主义务逐字是「落**最近一次
6110
+ turn** 的真 usage」——它回答「这一轮」,本臂回答「**这条 run 一共**」。两个量同臂,宿主就得在同一
6111
+ 载荷上分辨「这是 turn 还是 run」(同名不同义那一族病);且那条臂是 `required: true` 的既有义务面,
6112
+ 往上加语义会改已接宿主的读法。
6113
+
6114
+ **🔴 子流断闸不动**:`isSubFlow` 的 `turn_end` 仍然**不发** `last_turn_usage`(§E2 判据一字未动),
6115
+ 子代花费**只**经终局 `nested` 到账。⇒ 端**绝不能**把流中增量与本臂的终局总账相加 —— 那是重复计账。
6116
+
6117
+ **端怎么接**
6118
+
6119
+ ```ts
6120
+ // 终局那一拍(chrome 臂);不接这条臂的端改从终帧两个超集键读同一份事实
6121
+ case 'run_cost_reconciled': {
6122
+ if (ev.costAbsent) showOwn('未定价') // 🔴 别渲 $0.00
6123
+ else showOwn(ev.ownMicroUsd! / 1e6)
6124
+ if (ev.nestedCostAbsent) showNested('未定价') // 委派过,但那本账没有价
6125
+ else if (ev.nestedMicroUsd !== undefined) showNested(ev.nestedMicroUsd / 1e6)
6126
+ if (ev.compactionMicroUsd !== undefined) showCompaction(ev.compactionMicroUsd / 1e6)
6127
+ if (ev.reconciledMicroUsd !== undefined) showTotal(ev.reconciledMicroUsd / 1e6)
6128
+ break
6129
+ }
6130
+ ```
6131
+
6132
+ **黑盒判据**
6133
+
6134
+ - **G31-6**:一条**委派过子代**且**发生过压缩**的 run:终帧 `_sema_cost_breakdown.compactionMicroUsd`
6135
+ 与 `_sema_nested_usage.costMicroUsd` 都是有限数,且
6136
+ `llmRootMicroUsd + compactionMicroUsd === ` 该 run 的 `costMicroUsd`(core 的第一条对账式,
6137
+ 由 wire 值自身成立 —— 包不改数)。
6138
+ - **G31-7**:同一条 run 的 `total_cost_usd` **等于 own**(`costMicroUsd / 1e6`),**不等于**
6139
+ `own + nested`(修前后都不变 —— 这是一条防回归的反钉)。
6140
+ - **G31-8**:同一条 run **恰有一条** `run_cost_reconciled` chrome 事件,
6141
+ `reconciledMicroUsd === ownMicroUsd + nestedMicroUsd`。
6142
+ - **G31-9**:一台**没有价表**的 worker 上跑同一条 run:臂上 `costAbsent === true`,
6143
+ **没有** `ownMicroUsd`、**没有** `reconciledMicroUsd`;终帧上 `_sema_cost_breakdown` 键**不出现**
6144
+ (core 在 unpriced 时整段省略)。
6145
+ - **G31-10**:一条**没委派**的 run:臂上没有 `nestedMicroUsd` 且 `reconciledMicroUsd === ownMicroUsd`;
6146
+ 终帧上 `_sema_nested_usage` 键不出现。
6147
+ - **G31-10b**:一条**委派过但子代账读不出**的 run(`nested` 在场、其 `costMicroUsd` 缺席):
6148
+ 臂上 `nestedCostAbsent === true` 且**没有** `reconciledMicroUsd`(修前会铸出一个只含 own 的
6149
+ 「确定总额」);终帧上 `_sema_nested_usage` 键**在场**(委派这件事不丢)。
6150
+ - **G31-11**:一条被 409 拒绝的 turn:`run_cost_reconciled` 事件 **0 条**(没有账就不说话);
6151
+ `stats` 是畸形载体(数组/标量)时同样 0 条。
6152
+ - **G31-12**(负控):一条**子流** `turn_end` 不产生 `last_turn_usage` chrome 事件(既有断闸未被本批改动)。
6153
+
6154
+ ---
6155
+
6156
+ ### 31d. ③ L-192② 终帧扁平 `usage` 三格(core ≥7.12.0 usage 语义)
6157
+
6158
+ **键名与载体**
6159
+
6160
+ | 键 | 载体 | 来源 | 缺席语义 |
6161
+ |---|---|---|---|
6162
+ | `usage.webSearchRequests` | CC result 帧的扁平 usage | 按 CC 的名字**开集宽读**(`TaskStats` 是开集索引) | 读不出 ⇒ 值仍 `0`(CC 形必填 number)**+ 判别位** |
6163
+ | `usage._sema_web_search_requests_absent` | 同上(超集键) | 上一格读不读得出 | 只在读不出时 `true`;绝不铸 `false` |
6164
+ | `usage._sema_total_input_tokens` | 同上(超集键) | `TaskStats.totalInputTokens`(**cache-INCLUSIVE** 总量) | 键不铸 = wire 没报;显式 `0` 是事实 |
6165
+ | `usage._sema_cache_write_tokens_long` | 同上(超集键) | `TaskStats.cacheWriteTokensLong`(**1 小时 TTL** 那一档的缓存写入) | 键不铸 = wire 没报;显式 `0` 是读数(core 逐字「0 unless 1h caching is in use」) |
6166
+ | `ModelUsage._sema_web_search_requests_absent` | 每一行 CC `ModelUsage` 镜像(超集键) | 同上(同形第二处,两个 mint 点一个规矩) | 同上 |
6167
+ | **终局** per-model 行的 `_sema_total_input_tokens` / `_sema_usage_basis` / `_sema_cache_write_tokens_long` | 终帧 `modelUsage[*]`(超集键;**只有终局这一面**) | 行上的 `totalInputTokens` / `usageBasis` / `cacheWriteTokensLong` | 逐键不铸 = 这一行没报;`usageBasis` 是**开集串**,🔴 **缺席不许倒推口径** |
6168
+
6169
+ **🔴 `inputTokens` 为什么**不**改读 `totalInputTokens`**(本批唯一一处「台账写法 vs 合同」的分歧,
6170
+ 处置写明在此):台账原句是「input 用旧键 `promptTokens` 未读 `totalInputTokens`」。核合同后**不采**
6171
+ 那个写法 —— core 的 RB-457-a(3.0.0 BREAKING)把 `promptTokens` 的语义**翻**成了 cache-**MISS**
6172
+ 分量,而 CC / Anthropic 的 `input_tokens` 本义正是 MISS;同一个 `usage` 对象上已经另有
6173
+ `cacheReadInputTokens` 与 `cacheCreationInputTokens` 两格,把 cache-INCLUSIVE 总量灌进 `inputTokens`
6174
+ 就是 core 逐字点名的那笔**双算**(逐字:「a consumer computing `cachedTokens / (promptTokens +
6175
+ cachedTokens)` double-counted the cache subset and reported `h/(1+h)` (a 98% hit rate surfaced as
6176
+ 49.5%)」)。那等于**改 CC 同名键的语义**,不是超集。⇒ `inputTokens` 逐字不动(MISS 分量),
6177
+ 总量**另开超集座位**。这也与本包既有纪律一致:CC `ModelUsage` 镜像上同样没有总量座位。
6178
+
6179
+ **🔴 那为什么终帧要开座位、而 per-turn 那一面不开**:per-turn 有**逐字通道**
6180
+ (`EngineTurnUsage` / chrome `last_turn_usage.engineUsage`,整对象原形过境),要总量的消费面去那儿取;
6181
+ 而**终帧这一面没有任何别的载体** —— 不开座位,「这条 run 一共摆了多少上下文」在终帧上就问不出来。
6182
+ **同一条理由**把三个座位一并给了**终局的 per-model 行**(一个全局总量答不了「哪个模型摆了多少」,
6183
+ 而那张分表同样没有逐字通道):加挂只发生在两条**终局**腿上,per-turn 与终局共用的那个 mint 点
6184
+ (`toCcModelUsage`)一个字不动 —— 门里有一条反向钉盯着 per-turn 镜像不长这些座位。
6185
+
6186
+ **🔴 长 TTL 缓存写入为什么只「另给」不「相加」**:core 对两格的说法互相矛盾 ——
6187
+ `cacheWriteTokens` 自述是「Anthropic `cache_creation_input_tokens`」(协议侧那个量本就含 1h 子项),
6188
+ 而 `totalInputTokens` 的求和式又把 `cacheWriteTokens` 与 `cacheWriteTokensLong` **并列相加**
6189
+ (那要求二者互不重叠)。相加与不加**各有一种错法**,证据不足**不猜**:CC 的
6190
+ `cacheCreationInputTokens` 逐字保持 `cacheWriteTokens`(既有值一字不动),长 TTL 分量原样另给,
6191
+ 对账由消费方按两个数自己做;候上游澄清后再定。
6192
+
6193
+ **本批刻意不投的位(登记在案,不是漏)**
6194
+
6195
+ | 位 | 为什么不投 | 端要它时去哪儿取 |
6196
+ |---|---|---|
6197
+ | `ModelUsage.contextWindow` / `maxOutputTokens` | 它们是**模型的静态元数据**,不是这一轮的账;给它们立「缺席判别位」会把「去目录里取」误导成「等 usage 面补上」 | 模型目录(`/v1/models[].contextWindow`),本包 `resolveModelCatalog` 一侧 |
6198
+ | `TaskStats.cacheHitRate` / `toolCalls` / `mechanisms` / `memory` / `suggestions` | 都是**可观测面**而非 CC 形上的位,今天无端消费;投影它们等于先造一堆没人读的超集键 | 需要时按 `L-211` 一并立项(该票本就是「终局回执未消费族」) |
6199
+ | `humanReview.count` / `totalWaitMs` | 人工复核**耗时轴**(core 明记它**永不**折进成本/预算),与本批的拒绝清单是两件事;要它的是运维面不是会话面 | 同上,候 `L-211` |
6200
+
6201
+ **黑盒判据**
6202
+
6203
+ - **G31-13**:任一条 run 的终帧:`usage.webSearchRequests === 0` 且
6204
+ `usage._sema_web_search_requests_absent === true`(今天 wire 上没有这本账);
6205
+ 每一行 `modelUsage[*]` 上同样带这一位。
6206
+ - **G31-14**:一条 prompt 命中过缓存的 run:`usage.inputTokens` **小于**
6207
+ `usage._sema_total_input_tokens`(前者是 MISS 分量、后者是含 cache 的总量),且
6208
+ `usage.inputTokens` 与该 run 的 `promptTokens` **逐字相等**。
6209
+ - **G31-15**:一台不报 usage 的网关上的 run:`usage._sema_total_input_tokens` 键**不出现**
6210
+ (不拿 `promptTokens` 冒充总量),四个既有 token 格仍是 `0`。
6211
+ - **G31-16**(负控):三个超集位**都不会**出现 `false` / `null` 形态。
6212
+ - **G31-17**:一条在**多模型**部署上跑完的 run:终帧 `modelUsage[<每个模型>]` 各自带
6213
+ `_sema_total_input_tokens`(该模型那一行的 cache-INCLUSIVE 总量);行上报了口径标记时
6214
+ `_sema_usage_basis` 逐字过境(修前两键都被剥)。
6215
+ - **G31-18**:一条用了 **1 小时 TTL 缓存**的 run:`usage._sema_cache_write_tokens_long > 0`,
6216
+ 而 `usage.cacheCreationInputTokens` **逐字等于** wire 的 `cacheWriteTokens`(包不替引擎求和)。
6217
+
6218
+ ---
6219
+
6220
+ ### 31e. 消费方待办(三端逐条)
6221
+
6222
+ **cli(壳)**
6223
+
6224
+ 1. 壳仓的成本账本(`cost-tracker.ts`)的终局对账:接 chrome 臂 `run_cost_reconciled`(或读终帧两个超集键),
6225
+ `/cost` 面把 **own / nested / compaction** 三段各渲一行;🔴 两个判别位在场时渲「未定价」而**不是**
6226
+ `$0.00`;🔴 **不要**把流中 `last_turn_usage` 的增量与本臂的终局总账相加(子代花费只经终局到账)。
6227
+ 2. 壳仓里**本地铸** `permission_denials: []` 的两处(`sema/bridgeMessaging.ts` 与
6228
+ `sema/bootSignalTail.ts`):退役,改读投影;🔴 那两处自己合成的终帧同样只该在**账真的读得出且
6229
+ 逐行判得出**时给 `[]`,否则要带上判别位 —— 本地铸一个裸 `[]` 就是把「没有账」说成「零拒绝」。
6230
+ 3. 要「这条 run 摆了多少上下文」的读点(`/context` 与终帧 usage 面):改读
6231
+ `usage._sema_total_input_tokens`;🔴 **不要**把 `usage.inputTokens` 当总量(它是 MISS 分量)。
6232
+ 4. 网搜计数面(若有):`webSearchRequests === 0` 从此要与判别位合读,别渲成「本次未使用网搜」。
6233
+ 5. 拒绝清单的读点改吃 `_sema_permission_denials`(CC 的 `permission_denials` 今天恒 `[]`,
6234
+ 要等上游把 `toolCallId`/`toolInput` 串上 gate 账本才会自动填);渲之前先看判别位。
6235
+ 6. 缓存成本面若按 `cacheCreationInputTokens` 算钱:1 小时 TTL 那一档在
6236
+ `_sema_cache_write_tokens_long` 上单列,**别自己相加**(两格关系上游尚未澄清,见 §31d)。
6237
+
6238
+ **desktop**
6239
+
6240
+ 1. 走包管线的成本面同 cli 第 1 条:`run_cost_reconciled` 是 `required: false`,**不接不会哑**,
6241
+ 但不接就必须自己按终帧两个超集键对账,否则子代与压缩两笔账永远不进面板。
6242
+ 2. 自查点:有没有自己铸过 `permission_denials`(座位 IPC 侧的结果帧转投)——有则改读投影。
6243
+
6244
+ **web**
6245
+
6246
+ 1. 同上第 1 条;另:web 的账单/用量面若按 `usage.inputTokens` 求和估算上下文占用,按 §31d 改读
6247
+ `_sema_total_input_tokens`(否则命中率高的会话会被低估)。
6248
+ 2. 判别位一律按「不渲肯定句」处理:本批四个判别位(`_sema_permission_denials_absent` /
6249
+ `_sema_web_search_requests_absent` / 臂上的 `costAbsent`·`nestedCostAbsent`)都**只在该说话时在场**,
6250
+ 从不铸 `false`。
6251
+
6252
+ ---
6253
+
6254
+ ### 31f. 本批的门(新增两道 + 扩一道)
6255
+
6256
+ | 门 | 守什么 |
6257
+ |---|---|
6258
+ | `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 判词不猜 · 坏行逐行独立 |
6259
+ | `scripts/run-cost-reconcile-projection-test.mjs` | 🆕(B-068 / L-198):两段逐键窄读(micro-USD 原值、坏键剥掉不连坐、整段读不出不铸空对象、开集新键过境)· nested 花费未定价**键缺席绝不铸 0** · 🔴 `total_cost_usd` 语义零改的反钉 · chrome 臂三段与对账值 · `stats` 缺席一条不发 · 非成功终局照发 · §E2 子流断闸反钉 |
6260
+ | `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 镜像不长座位**的反向钉 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/client-core",
3
- "version": "0.65.0",
3
+ "version": "0.66.0",
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",