@sema-agent/client-core 0.57.0 → 0.59.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.
@@ -15,15 +15,15 @@
15
15
 
16
16
  ## §0 版本锚与重扫纪律
17
17
 
18
- ### 0a. 版本锚(2026-09-05)
18
+ ### 0a. 版本锚(2026-09-06)
19
19
 
20
20
  | 项 | 值 | 真源 |
21
21
  |---|---|---|
22
- | 本包 | `@sema-agent/client-core` **0.55.0**(工作树**未发**;npm 最新 = **0.54.0**。B-003 `waiting_first_token` 那一批进 `CHANGELOG.md` 的 `## 0.55.0(2026-09-05)` 段,冻结账已按两阶段协议插 `pending` 行) | `package.json` `version` |
23
- | peer:wire 契约 | `@sema-agent/sdk` **>=7.4.0**(value-level,非 type-only;0.48.0 抬版,四条硬理由见 `CHANGELOG.md` 0.48.0 段末的地板影响面账) | `package.json` `peerDependencies` |
22
+ | 本包 | `@sema-agent/client-core` **0.58.0**(= npm 最新;`package.json` `version` 未动)。**工作树另有一批未发内容** = 0.59.0(sdk 8.3.0 提货 / S-131 SQL 姿态读面上收 / S-124·S-114·S-125③⑧ 候件投影),进 `CHANGELOG.md` 的 `## 0.59.0(未发布)` 段;bump 与冻结账两阶段由发包批做,本内容批**不 bump** | `package.json` `version` |
23
+ | peer:wire 契约 | `@sema-agent/sdk` **>=8.3.0**(value-level,非 type-only;**0.59.0 抬版**,三条硬理由见 §23a 与 `scripts/run-sdk-floor-test.mjs` 的 `FLOOR` 注;上一次是 0.58.0 的 `>=8.2.0`) | `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
- | 公开导出面 | **821** 个运行期符号(+ 41 个测试钩;= 工作树当下的值 = 0.57.0 内容批 D 三件 additive;`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
+ | 公开导出面 | **836** 个运行期符号(+ 42 个测试钩;= 工作树当下的值 = 0.59.0 八件 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`(**821** 项)。
114
+ > 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**836** 项)。
115
115
  > 本节**不逐名抄**,只给「域 → 承重导出 → 用途 → 实现锚」。承重导出 = 一个端为了让这个域干活
116
116
  > **必须**直接调到的那几个符号;其余是它们的类型、变体与辅助位。
117
117
  > 单一入口:`import { … } from '@sema-agent/client-core'`(`exports` 只有 `.` 一个;
@@ -135,18 +135,18 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
135
135
  `WorkflowsGateUnknownDenial` 四形**不在**基线里,`src/selfOrchestrationDenial.ts` 对基线贡献
136
136
  **4** 项运行期导出(三个函数 + `SELF_ORCHESTRATION_RETRY_WITHOUT`)。
137
137
 
138
- 821 项的内部构成(帮助端估读表大小):**247** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
138
+ 836 项的内部构成(帮助端估读表大小):**254** 项是 `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 域,逐域计数之和 = 821)
143
+ ### 2b. 域图(16 域,逐域计数之和 = 836)
144
144
 
145
145
  | # | 域 | 名数 | 承重导出 | 用途 | 实现锚 |
146
146
  |---|---|---|---|---|---|
147
147
  | 1 | **适配内核(下行主链)** | 33 | `adapt` · `createWireToCcAdapter` · `runStream` · `eventToSdkMessage` · `terminalToSdkResult` · `turnUsageToModelUsage` · `isRunStreamActive` · `ADAPTER_DIVERGENCES` | 引擎 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` |
148
148
  | 2 | **seam 公共契约** | 2(其余为 type-only) | `CHROME_ARMS` · `deriveTranscriptId` | 公共词汇 + **id 确定性不变量**(同一条流重放 ⇒ 同一串 id)。`CHROME_ARMS` = 端「我要消费哪些 chrome 臂」的对照清单 | `src/seam.ts` |
149
- | 3 | **HITL 决断卡链**(§4/§5 主战场) | 138 | `makeHitlCanUseTool` · `HitlBridge` · `findPendingForTask` · `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)· `DecideTransportRetryExhaustedError`(Inkglow-1085 P0a:decide 出站瞬断重试耗尽的 typed 判别 —— HitlBridge 内建单次退避重试,耗尽走重呈臂不判死 turn;端一般只消费行为,不需要 instanceof) | 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 崩溃收敛读面) |
149
+ | 3 | **HITL 决断卡链**(§4/§5 主战场) | 143 | `makeHitlCanUseTool` · `HitlBridge` · `findPendingForTask` · `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) | 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 崩溃收敛读面) |
150
150
  | 4 | **子代 wire + 面板侧信道台账** | 84 | `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` | 驱动与观测委派子代;经 module 级台账喂活体 agent/task 面板。全部**能力位 gate**(§5b) | `src/subagent/*.ts`、`src/subagentContentStore.ts`、`src/engineAgentPanelStore.ts`、`src/engineInlineTaskStats.ts`、`src/engineToolLabelStore.ts`、`src/liveQuestionStore.ts` |
151
151
  | 5 | **fleet 投影** | 46 | `createFleetLedger` · `projectTasks` · `projectWorkflows` · `projectFleetAgentRows` · `readEngineActiveBgTasks` · `FLEET_TASK_VIEW_KEYS` · `escapeDisplayControlChars`(不可见字符可见化,行标签/描述消毒的共享底座)· `wireCycleSeq` / `wireRetiredBy`(0.38.0 提货补投的 #261 §2 两位:代际号 = SendMessage 复活即 +1,**缺席 ≠ 第一代**;`retiredBy` 在场 = 这条终态是对账腿从 durable run 行投影出来的、**不是**发布方亲报 —— 幽灵行与正常收尾唯一的 wire 判据。两位都只在场才落键) | 老 `fleetClient` 那一刀的成品:**帧体归库、连接归端** —— 端持 SSE 连接,库做行投影 + 保留台账 | `src/fleet/fleetProjection.ts`、`src/fleet/fleetLedger.ts`、`src/fleetAgentPanelProjection.ts`、`src/fleetTaskDesc.ts` |
152
152
  | 6 | **请求装配(上行唯一构造口)** | 8 | `buildTaskRequest` · `REQUEST_FIELD_MATRIX` · `unregisteredRequestKeys` · `applyLiveRequestDefaults` · `taskNotificationToPrintFrame` | 两条车道(`interactive`/`print`)出站请求的**唯一**构造器;`unregisteredRequestKeys` 是可执行门 —— 端偷带一个未登记键上 wire 就红 | `src/request/taskRequest.ts`、`src/request/printNotification.ts` |
@@ -158,8 +158,8 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
158
158
  | 12 | **workflow 与后台工作视图** | 19 | `projectWorkflowRun` · `createLiveWorkflowSource` · `ensureWorkflowActivityLedger` · `readWorkflowActivityLedger` · `stopWorkflowActivityLedger` · `resetWorkflowActivityLedgers` · `createBackgroundView` · `projectBackgroundView` · `recordWorkflowAgentTaskId` · `agentDisplayStatus` | 活过一个 turn 的长任务读面:workflow run + 跨 session 后台任务归一表(`assistant.tasks` 与 fleet SSE **两源独立降级**) | `src/workflow.ts`、`src/workflowClient.ts`、`src/workflowMonitor.ts`、`src/agentSession/backgroundView.ts`(+ 纯类型 `src/agentSession/contract.ts`) |
159
159
  | 13 | **座位 IPC 契约** | 33 | `LOCAL_SESSIONS_SPEC` · `SEAT_METHOD_NAMES` · `SEAT_EVENT_TYPES` · `isLocalSessionEvent` · `isToolPermissionRequest` · `toolPermissionRequestId` · `SEAT_VALIDATOR_KEY_COVERAGE` | 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
- | 15 | **控制面与传输** | 83 | `ControlRouter`(+ `ControlSafetyError`)· `makeEngineWireClient` + `resolveWireAuth` · `installEngineWireTarget` · `diagnoseSseIdleTear` / `isSseIdleError` · `attemptActiveRunSelfHeal` + `activeRunBusySignal` + `activeRunSelfHealRow` / `activeRunBusyHeadlessRow` · `kickEngineCapsProbe` / `engineCapTrue` / `invalidateEngineCaps(baseUrl, probe?)`(#307 S25:引擎温切后的 caps 生产失效口 —— kick 自带幂等闸,同 baseUrl 重启后不显式失效就永远读到旧引擎那一版能力位;调用方 = 壳的 respawn/restartEngine。🔴 **推荐两参形**:第二参给替代探测则「推进代际 + 注册新探测」在同一同步块内完成,失效与下一次 kick 之间那个「等待者读到未判」的窗按构造不存在;单参形保留给「只丢缓存、这一刻没有替代探测」的调用方,那种情形下读到未判是诚实结局) · `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) | 上行通道的**监管**半场(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` |
162
- | 16 | **引擎词汇表与包自检** | 54 | `CONFIG_REFUSAL_CODES` / `isConfigRefusalCode` · `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) | 三端分臂共用的**去字面化** `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` |
161
+ | 15 | **控制面与传输** | 89 | `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) | 上行通道的**监管**半场(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` |
162
+ | 16 | **引擎词汇表与包自检** | 58 | `CONFIG_REFUSAL_CODES` / `isConfigRefusalCode` · `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) | 三端分臂共用的**去字面化** `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` |
163
163
 
164
164
  🔴 **`engineErrorCodes` 的开集纪律**(该文件头注逐字):这些 `ReadonlySet` / 前缀谓词一律是**识别表**,
165
165
  回答的是「我认不认得这个码」,**绝不是**「合法码只有这些」。消费点 `switch` **必须留 `default`**,
@@ -1527,7 +1527,7 @@ CHANGELOG 0.29.0「已知局限」段与相应 JSDoc 都有成文。**别在读
1527
1527
 
1528
1528
  | **P-43** | med(治理面)@cli @web @desktop | 🆕 **`hooksForWire()` 只守住了本地执行器四条治理腿里的三条**(0.52.0 L-67④ 补了第三条,第四条**在册未修**):cli 仓那份本地执行器(`utils/hooks/hooksConfigSnapshot.ts` 的 `getHooksFromAllowedSources`,**cli 仓坐标不是本仓坐标**)的第四条腿 = `disableAllHooks` 出现在**非** managed 来源(user/project/local)时按 CC 语义降级成「只跑 managed hooks」。本包今天**只读** `policySettings.disableAllHooks` ⇒ 该形在引擎腿上**不成立**(用户把自己的 hooks 关了,引擎照投照跑)。**为什么不做单边近似**:cli 那条腿读的是**合并后**的标量(四源按 policy→user→project→local 后写覆盖前写),而本包 `SettingsPort` 只有 per-source 读口 —— 拿「任一来源为 true」去近似会在「user 写 `true`、local 写 `false`」这一形上**判反**(cli 那边是**不**限制)。忠实复刻要给 `SettingsPort` 加一个合并读口 = **公面改动**(端要跟车实现),属另一批 | `src/hooksWireCaps.ts`(头注「在册缺口」段);§15b/§15d | 端**不要**假定「用户 settings 里的 `disableAllHooks` 会挡住引擎腿的 hooks」——今天只有 **managed(policySettings)** 那一份挡得住。要它落地按 [C162] 令④ 回 C 板提(正位解在包侧:`SettingsPort` 补合并读口 + 本函数补第四条腿) |
1529
1529
 
1530
- | **P-44** | low(型面)@sdk @cli @web @desktop | 🆕 **SDK 8.1.0 的 `ToolApprovalsResource.respond` 体型只锚到 `persistRule: { rule: string }`,server ≥7.46.0 已发的两位没跟**([C233]①,0.57.0 登记):①`persistRule.edited?: true`(编辑臂,server #340 / [5071]);②`persistRule.batchOfferIndex?: number`(批臂,server ≥7.46.0 / design/377)。同一族锚滞后还有三处:`ToolApprovalFrame.ruleOffers` `PendingCheckpoint.ruleOffers`(server ≥7.46.0 的判别联合;SDK 8.1.0 全树 `ruleOffers`/`RuleOffer` **零命中**,亲验)、`ToolApprovalRespondAck` `persistedRule`/`persistedRules`/`persistedRuleAnchors`(server ≥7.44 / ≥7.46.0 / ≥7.48.0)。🔴 **本包侧零 cast、也不需要 cast**:本包**不铸 respond 的 wire 体** —— `RespondToolApprovalFn` 是**宿主注入**的函数型,包只把扁平兄弟位(`persistRule: string` / `persistRuleEdited?: true` / `persistRuleBatchOfferIndex?: number`)交给注入面,由注入面按 `RespondToolApprovalOpts.persistRuleBatchOfferIndex` 头注写的那段优先序合成嵌套体。所以**吃这个型面缺口的是三端的注入面**(它们直接调 `client.toolApprovals.respond`),不是本包。帧侧那一半本包自铸归一形 `RuleOffer` 并在 `scripts/run-approval-frame-keys-test.mjs` `AHEAD_OF_ANCHOR` 带退出条件登记(SDK 补上当天自红逼删),0.57.0 起窄读器 additive 上公面20) | `src/hitl/toolApprovalWire.ts`(`RespondToolApprovalOpts.persistRuleBatchOfferIndex` / `ToolApprovalRespondAckView` 两处头注已写清「候 sdk 补锚」)· `scripts/run-approval-frame-keys-test.mjs` `AHEAD_OF_ANCHOR` 登记 | 端的注入面今天要合成那个嵌套体:**用宽形声明自己的 respond 包装**(或就地 `as`),并在**改动处写清锚到哪个 sdk 版本**、SDK 补锚当天回收。🔴 **别为了绕过型面缺口去改本包的扁平位**(那是既有 `persistRule: string` 消费者的 BREAKING,而这一批的纲领是 additive);也别在端侧自铸一个同名 `RuleOffer` —— 归一形与它的伴生类型自 0.57.0 起都在本包公面上。正位解在 sdk(补型),按 [C162] 令④ 回 C 板提 |
1530
+ | **P-44** | ✅ **已收**(0.58.0,sdk 8.2.0 提货)@cli @web @desktop | **上游已补齐,本条转已收** —— sdk **8.2.0**(S-134 五锚)把这一族型面缺口一次补完:①`respond` `persistRule` 由单臂 `{rule}` 换成具名**两臂互斥**联合 `PersistRuleSelection`(`{rule, edited?}` `{batchOfferIndex}`,互斥用 `?: never` 钉在编译期 server 那句 `PERSIST_RULE_BATCH_EXCLUSIVE_ERROR` 400 永远打不到线上);②`ToolApprovalFrame` / `ApprovalCard` / `PendingCheckpoint` 三腿同一个 `RuleOffer` 判别联合(含 `match` 四员闭词表、成员 `command`/`directoryRead` 两臂、additive `uncoveredDetail`);③`ToolApprovalRespondAck` `persistedRule` / `persistedRules` / `persistedRuleAnchors` 三位。🔴 **本包侧本来就零 cast、也不需要 cast**(0.57.0 原文,逐字仍成立):本包**不铸 respond 的 wire 体** —— `RespondToolApprovalFn` 是**宿主注入**的函数型,包只把扁平兄弟位(`persistRule: string` / `persistRuleEdited?: true` / `persistRuleBatchOfferIndex?: number`)交给注入面。⇒ 吃这个缺口的一直是**三端的注入面**。本包 0.58.0 这一侧的动作是:归一形 `RuleOffer` 一族改由 sdk 派生、`ToolApprovalRespondAckView` 与 `PersistedRuleAnchor` 两个包内自铸形按各自写下的退役条款回收成 sdk 形的别名、`AHEAD_OF_ANCHOR` 里那条 `ruleOffers` 领先登记到期自红删除(详见 **§22a**)。🔴 **三端还要做的那一半(本条转已收之后的剩余动作)**:注入面那处宽 `cast`(或自铸的 respond 包装形)现在可以删掉,改直接用 sdk 8.2.0 的 `PersistRuleSelection` —— 两臂互斥由编译期钉,`{rule, batchOfferIndex}` 同场会**编译红**(这正是要的);`batchOfferIndex: 0` 逐字进 body(`0` 不被 falsy 吞)。同样别再在端侧自铸同名 `RuleOffer` 形:归一形与它的伴生类型自 0.57.0 起在本包公面上,三张闭词表自 0.58.0 起也在22b) | `src/hitl/toolApprovalWire.ts`(两处「候 sdk 补锚」头注已随本批锚到 8.2.0 / 回收)· `scripts/run-approval-frame-keys-test.mjs`(该条 `AHEAD_OF_ANCHOR` 登记已删)· `scripts/run-sdk-floor-test.mjs`(地板 8.2.0) | 端按上一栏「剩余动作」删自己的宽 cast;peer 地板随本包抬到 `>=8.2.0`,提货前先抬依赖 |
1531
1531
 
1532
1532
  ### 7e. 缺口的共同形状(值得单独说)
1533
1533
 
@@ -2912,8 +2912,11 @@ CC 2.1.250 语料**无同形提示行** —— `first token` / `firstToken` / `f
2912
2912
  那一位只是展示/对账座,**禁**当选择键。
2913
2913
  2. **逐条丢坏,不整只拒**:一条坏 offer 不该让另一条真 offer 消失(与 server 侧同向)。
2914
2914
  但**留下来的每一条都带原始下标**——压紧下标是本节表里第一行那条失效形。
2915
- 3. **batch 的成员不逐条丢**:合取批是「对全体成员一次说是」,任一成员不合形 **整条 batch 丢**
2916
- (兄弟 offer 不连坐)。渲一个缺了成员的批 = 人点的与引擎兑的不是同一批规则。
2915
+ 3. **batch 的成员不逐条丢**:合取批是「对全体成员一次说是」,任一成员不合形(含 `kind` 不识)
2916
+ ⇒ **整条 batch 丢**(兄弟 offer 不连坐,也**不**整卡丢)。渲一个缺了成员的批 = 人点的与引擎
2917
+ 兑的不是同一批规则。⚠️ 这条**不是本包的保守选择,是上游的规范性条款**:core design/382 §2.3
2918
+ 逐字 "drops the WHOLE batch offer — never the single member ... and never the whole card"
2919
+ (sdk 8.2.0 `RULE_OFFER_BATCH_MEMBER_KINDS` 顶注同文)—— 端**不许**自行改成丢单个成员。
2917
2920
  4. **`uncoveredSegments` 是诚实余量披露,不是装饰位**:非「有限非负整数」⇒ 整条 batch 丢。
2918
2921
  渲一个编出来的 `0` 等于对用户说「兑完这批就全覆盖了」,而那句话没有证据。
2919
2922
  `0` 本身是**合法读数**。
@@ -2922,8 +2925,12 @@ CC 2.1.250 语料**无同形提示行** —— `first token` / `firstToken` / `f
2922
2925
 
2923
2926
  ### 20d. 形校验(包侧已做,端不必重做)
2924
2927
 
2925
- - 一条 offer / 一个 batch 成员共用三位窄化:`rule` 非空串 ∧ `match` ∈ {`exact`,`prefix`} ∧
2926
- `command` 非空串;batch 成员另加 `segment` 非空串(渲染座,**永不参与裁决**)。
2928
+ - 一条 `single` offer / 一个 `command` 成员共用三位窄化:`rule` 非空串 ∧ `match` ∈ **闭词表**
2929
+ (⚠️ **0.58.0 起是四员** `exact` / `prefix` / `wildcard` / `subpath`,由 sdk 8.2.0
2930
+ `RULE_OFFER_MATCHES` 单源派生;0.43.0–0.57.0 这里手抄成两员,合法的 `wildcard` 候选被整条丢掉
2931
+ —— B-025,详见 §22)∧ `command` 非空串;成员另加 `segment` 非空串(渲染座,**永不参与裁决**)。
2932
+ - ⚠️ **0.58.0 起 batch 成员是判别联合**(`kind: 'command' | 'directoryRead'`,§22b):
2933
+ `directoryRead` 臂**没有** `match`/`command` 两座,渲之前先读 `kind`。
2927
2934
  - `rule` / `command` / `segment` 三位都是 **UNTRUSTED-for-display**(原始 post-rewrite 命令字节)——
2928
2935
  包不消毒(消毒单源在端的展示层),端渲之前照自己那套控制字符/长度纪律处理。
2929
2936
  - 空数组 / 非数组 / `null` / 全条坏形 / 超帽 ⇒ `undefined`。
@@ -2935,7 +2942,9 @@ CC 2.1.250 语料**无同形提示行** —— `first token` / `firstToken` / `f
2935
2942
  第二个观察面。常驻门 ⑦ 段把两者对同一份素材逐字对账 —— 哪天有人在其中一条腿上就地改窄读,当场红。
2936
2943
 
2937
2944
  **实现锚**:`src/hitl/toolApprovalWire.ts`(`readRuleOffers` / `readRuleOfferSupply` 两个 `export`;
2938
- 归一形 `RuleOffer` / `RuleOfferMatch` / `RuleOfferBatchMember` 与入参形 `WireRuleOffer` 照旧导出)。
2945
+ 归一形 `RuleOffer` / `RuleOfferMatch` / `RuleOfferBatchMember` 与入参形 `WireRuleOffer` 照旧导出。
2946
+ 🆕 0.58.0 起 `RuleOfferMatch` / `RuleOfferBatchMember` / `RuleOfferUncoveredDetail` /
2947
+ `RuleOfferUncoveredReason` 四形**由 sdk 8.2.0 派生**,三张闭词表随之公面再导出,见 §22)。
2939
2948
  **常驻门**:`scripts/run-rule-offers-reader-test.mjs`(公面在场 + 两代正控 + 下标不前移 +
2940
2949
  batch 语义 + 坏形处置 + 取舍序 + 与两条卡端口腿的单一铸点对账)。
2941
2950
 
@@ -3038,3 +3047,386 @@ batch 语义 + 坏形处置 + 取舍序 + 与两条卡端口腿的单一铸点
3038
3047
  - **`refused-preflight` 这一格今天在多数部署上结构性不可达**:`resume.preflight_rejected` 要有
3039
3048
  部署自己的 resume 预检座才发得出来。它是**预置臂**,不是当版可触发的行为面 —— 端接上去是为了
3040
3049
  「码到货那天不至于只会印一行裸码」,不要据此推断本部署已经在用预检。
3050
+
3051
+ ---
3052
+
3053
+ ## §22 🆕 sdk 8.2.0 提货 · 规则报价窄读器修根(B-025)· resume 拒绝文案铸点上收(0.58.0)
3054
+
3055
+ 本节三件同一批,分三段。**共同的形**都是「上游已经把单源摆出来了,而消费侧还留着一份自己的抄本」。
3056
+
3057
+ ### 22a. sdk 8.2.0 提货:peer 地板 `>=7.4.0` → `>=8.2.0`(本版唯一的非 additive 面)
3058
+
3059
+ | 面 | 0.57.0 | 0.58.0 | 端要做什么 |
3060
+ |---|---|---|---|
3061
+ | peer 地板 | `@sema-agent/sdk >=7.4.0` | **`>=8.2.0`** | 提货前先抬自己的 sdk 依赖;装 <8.2.0 会看到 peer 警告,且本包**运行期真的需要** 8.2.0(见下) |
3062
+ | sdk 消费姿势 | 值级 5 个符号 | 值级 **8** 个(新增三张 `as const` 闭词表) | 无(本包内部) |
3063
+ | `RuleOfferMatch` | 本包手抄 `'exact' \| 'prefix'` | **sdk 派生**,四员 | 🔴 对它写穷尽 `switch` 的端**会编译红** —— 那正是要显形的东西(见 22b) |
3064
+ | `RuleOfferBatchMember` | 本包自铸 interface(四座) | **sdk 派生**判别联合 | 🔴 渲成员前先读 `kind`(见 22b) |
3065
+ | `ToolApprovalRespondAckView` | sdk 形的 additive 超集 | **= sdk `ToolApprovalRespondAck` 本身**(别名) | 无(名字保留,读法逐字不变) |
3066
+ | `PersistedRuleAnchor` | 本包自铸(三位 `readonly`) | **sdk 派生**(同三位,跟随 sdk 的可变性声明) | 无(读方源码兼容) |
3067
+
3068
+ 🔴 **地板抬升的四条硬理由**(不是顺手跟版本;逐条写在 `scripts/run-sdk-floor-test.mjs` 的 `FLOOR` 注里):
3069
+ ① 三张闭词表是**运行期**判据 ⇒ 值级 import,<8.2.0 上这三个名字不存在,整包编译不过;
3070
+ ② `RuleOffer` 一族五个类型面(本包归一形由它们派生);
3071
+ ③ `ToolApprovalRespondAck` 上的 `persistedRule` / `persistedRules` / `persistedRuleAnchors` 三位
3072
+ (0.43.0 起的包内超集按它自己写下的退役条款回收);
3073
+ ④ `AgentEvent` 新增 `approval_revoke` 臂 —— 臂一进 union,下行投影的编译期穷举断言当场红。
3074
+
3075
+ **同批退役的两笔记账**(都是「带退出条件的登记到期自红」,不是清理):
3076
+ - `run-approval-frame-keys-test.mjs` 的 `AHEAD_OF_ANCHOR` 里那条 `ruleOffers` 领先登记 ——
3077
+ sdk 8.2.0 的运行期锚 `TOOL_APPROVAL_FRAME_KEYS` 已含该键(18 项),门先自红一次再删;
3078
+ ⚠️ 同表其余 6 条(`requiresRealApproval` / 窗三键 / `inputHasBidi` / `parked`)**仍在**,
3079
+ 锚上依旧没有它们 —— 退出条件是**逐条**的,不是整表的。
3080
+ - §7d **P-44 转「已收」**:sdk 8.1.0 那一族型面缺口(respond 体 `persistRule` 单臂、帧/行的
3081
+ `ruleOffers`、ack 三位)在 8.2.0 全部补齐。🔴 **本包侧本来就零 cast**(P-44 原文已写清:本包不铸
3082
+ respond 的 wire 体,吃这个缺口的是三端**注入面**)⇒ 本包这一侧的动作只是把归一形改成派生 +
3083
+ 回收超集;**三端注入面**现在可以删掉自己那处宽 `cast`,改用 sdk 8.2.0 的
3084
+ `PersistRuleSelection`(两臂互斥 `{rule, edited?}` ∣ `{batchOfferIndex}`,互斥用 `?: never` 钉在编译期)。
3085
+
3086
+ **`approval_revoke` 的处置(如实记账)**:本包**今天零消费口** —— `isToolApprovalFrame` 只认
3087
+ legacy 的 `tool_approval` / `tool_approval_complete`。新臂与它的兄弟 `approval_request` 同处置:
3088
+ `dropped/unsupported_arm`(**有痕**,经 `reportDroppedFrame` 走宿主 sink),不是静默的
3089
+ `none/not_in_slice`。端**不要**把「撤卡帧没反应」读成「引擎没发」;接那条新卡链是另一批。
3090
+
3091
+ ### 22b. B-025 修根:「不再询问」候选窄读器不再手抄上游闭词表
3092
+
3093
+ **病形**(0.43.0 铸、0.57.0 仍在;由 sdk [6464] 两侧源码对读点名,坐标 `toolApprovalWire.ts:1772` / `:209`):
3094
+
3095
+ | 症状 | 0.57.0 实际行为 | 用户看到什么 |
3096
+ |---|---|---|
3097
+ | ① `match` 词表手抄成两员 | 一条合法的 `match:"wildcard"`(或 `"subpath"`)single **整条丢** | 卡上那一格「不再询问」**凭空消失** |
3098
+ | ② batch 成员没有 `directoryRead` 臂 | 一只带 `cd` 段目录只读授权的 batch **整只丢** | 同上,且与该函数自己注释承诺的「逐条丢坏、不整拒」相反 |
3099
+ | ③ 没有 `uncoveredDetail` 座 | design/382 §3.5 的 additive 明细整段读不到 | 「为什么这段还会问」无从渲 |
3100
+
3101
+ **修**=三张闭词表**单源化**到 sdk 8.2.0,本包不再有第二份:
3102
+
3103
+ ```ts
3104
+ import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS } from '@sema-agent/client-core'
3105
+ // RULE_OFFER_MATCHES = ['exact', 'prefix', 'wildcard', 'subpath']
3106
+ // RULE_OFFER_BATCH_MEMBER_KINDS = ['command', 'directoryRead']
3107
+ // RULE_OFFER_UNCOVERED_REASONS = ['redirection', 'no_rule_form', 'cap_overflow']
3108
+ ```
3109
+
3110
+ 🔴 **端拿它们判定,别再手抄字面量** —— 三端与包共用同一份数组对象,词表加员时上游一处改、四处跟。
3111
+ 常驻门对 `match` 做**双向全等钉**:表里每个词都必须被读器认下(⊇;手抄的窄表在新词上当场红),
3112
+ 构造出来保证在表外的词必须被丢(⊆;读器放宽成「是串就收」时当场红)。
3113
+
3114
+ **batch 成员的新形**(sdk 8.2.0 `RuleOfferBatchMember`,core design/382 §2.3 B3):
3115
+
3116
+ ```ts
3117
+ type RuleOfferBatchMember =
3118
+ | { kind: 'command'; rule: string; match: RuleOfferMatch; command: string; segment: string }
3119
+ | { kind: 'directoryRead'; rule: string; directory: string; segment: string }
3120
+ ```
3121
+
3122
+ - `directoryRead` = `cd <dir>` 段铸的**目录只读授权**:`rule` 是规范 `Read(//dir/**)` 文本,
3123
+ `directory` 是词法规范绝对目录(渲染座,免二次解析)。本臂**没有** `match`/`command` 两座 ——
3124
+ 拿「三元组」窄读器去读它会整只判假,那正是症状②。
3125
+ - 🔴 **成员 `kind` 不识 ⇒ 丢整只 batch,绝不丢单个成员,也绝不丢整卡**(core 的**规范性**降级臂,
3126
+ §20c 第 3 条已引原文)。端不许自行改成成员级容错。
3127
+ - ⚠️ **本包另收一条 pre-B3 兼容臂**:`kind` **缺席**的成员按 `kind:'command'` 归一(server ≥7.46.0
3128
+ 到 B3 落地之间铸的成员没有判别位;窄读域只许等于或宽于铸点域)。⇒ **归一形上 `kind` 恒在场**,
3129
+ 端拿到的成员永远是判别联合,零分支差异。
3130
+
3131
+ **additive `uncoveredDetail`**(0.58.0 起透传到 `RuleOffer` 的 batch 臂):
3132
+
3133
+ ```ts
3134
+ uncoveredDetail?: readonly { segment: string; reason: 'redirection' | 'no_rule_form' | 'cap_overflow' }[]
3135
+ ```
3136
+
3137
+ - 🔴 **缺席 ≠ 「没有未覆盖段」**:server 对坏形的座**只丢座不丢批**,老引擎更是压根不铸 ——
3138
+ 真源恒是 `uncoveredSegments` 那个 **count**。本包缺席时**不铸空数组**(空数组会被端读成
3139
+ 「已确认没有未覆盖段」)。
3140
+ - 行数与 `uncoveredSegments` **不强制相等**(见上一条);坏行**只丢那一行**,坏载体只让**本位**
3141
+ 降缺席,**绝不**因为一个 additive 位否决整只 batch。
3142
+ - **行数帽 = 32**,锚在上游铸点域上(server `MAX_UNCOVERED_DETAIL_ROWS`)。⚠️ 未覆盖段数**不受
3143
+ 成员帽约束**:一只只有 1 个成员的 batch 可以带 9 条明细(9 个带重定向的段各自 mint 不出规则形)
3144
+ —— 端若自己再设一个更窄的帽,就会把合法明细整座吞掉(本包初稿的 8 正是这么错的,异源对抗复审
3145
+ 逮到)。33 行及以上 ⇒ 本位降缺席(与 server 座级预筛同判)。
3146
+ - `segment` 与其余文本座同属 **UNTRUSTED-for-display**。
3147
+
3148
+ **端的迁移动作**(逐条,都很小):
3149
+ 1. 对 `RuleOfferMatch` 写穷尽 `switch` 的端:补 `wildcard` / `subpath` 两格(编译红会指给你)。
3150
+ ⚠️ 这两格此前在端上是**静默不可达**的(包在读器里就丢掉了),不是「新增的空格子」。
3151
+ 2. 渲 batch 成员前先读 `kind`;`directoryRead` 臂渲 `directory`(它没有 `command` 可渲)。
3152
+ 3. 想渲「为什么这段还会问」的端:读 `uncoveredDetail`,**缺席就什么都别说**(别渲成 0)。
3153
+ 4. 已走卡端口的宿主:`ApprovalCardRequest.ruleOffers` / `.ruleOffersReadOnly` 是同一把读器的产物,
3154
+ 新形自动到位;常驻门 ⑨e 段把公面与两条卡腿对同一份新形素材逐字对账。
3155
+
3156
+ ### 22c. L-102 下半场:resume 拒绝**文案铸点**上收(壳侧改薄成适配层)
3157
+
3158
+ 0.57.0 上收的是**事实读数**(§21 的 `resumeRetryLaterFromError`:命中哪个码 / server 给没给窗 /
3159
+ 等一会儿有没有用)。留在壳里的另一半是**人话** —— cli 1.0.x 的 `sema/resumeRefusalCopy.ts`(⚠️ **cli 仓坐标,不是本仓坐标**)自铸了
3160
+ 一份判型 + 三句 `·` 分段文案,而 web-client / desktop 要么没有、要么将来会再抄一份。三端各抄一份
3161
+ = 同一次拒绝在三个端上说三句不一样的话,而这三句回答的是**同一个安全问题**:
3162
+ 「这次拒绝有没有消费掉我的决定 / 这张卡还能不能再决」。
3163
+
3164
+ **新公面**(`src/resumeRefusalCopy.ts`):
3165
+
3166
+ ```ts
3167
+ export const RESUME_REFUSAL_CODES: readonly string[] // 冻结数组,恰两员
3168
+ export interface ResumeRefusalDetail { code: string; retryAfterSec?: number; waitable: boolean }
3169
+ export function resumeRefusalFromError(err: unknown): ResumeRefusalDetail | null
3170
+ export function resumeRefusalContent(detail: ResumeRefusalDetail): string
3171
+ // 同批新增码常量:RESUME_PLACEMENT_MISMATCH(engineErrorCodes.ts)
3172
+ ```
3173
+
3174
+ 🔴 **两个闭集刻意分家**(端别把它们当同一张表的两个名字):
3175
+
3176
+ | 闭集 | 闭的是什么 | 成员 |
3177
+ |---|---|---|
3178
+ | `RESUME_RETRY_LATER_CODES`(§21,0.57.0) | **server 在哪些码上铸 `retryAfterSec`** ⇒ 答「能不能等」 | `resume.usage_window_exhausted` · `resume.preflight_rejected` |
3179
+ | `RESUME_REFUSAL_CODES`(本节,0.58.0) | **哪些 resume 拒绝有人话可补** ⇒ 答「该对人说什么」 | `resume.placement_mismatch` · `resume.preflight_rejected` |
3180
+
3181
+ 两集**交于** `preflight_rejected` 一码、**各有**一个独占成员:
3182
+ - `usage_window_exhausted` 只在前者 —— 它没有专属人话,「你可以等」就是全部信息;
3183
+ - `placement_mismatch` 只在后者 —— server 不给它铸窗,而且**等一会儿对它毫无用处**:出路是
3184
+ 「用记录里的那个 root 重来,或干脆不传 `internals.placementRoot` 继承记录值」,是**换参数**
3185
+ 不是**等时间**。把它放进时间性闭集 = 让人白等一个永远不会自己好的拒绝。
3186
+
3187
+ 🔴 **本口不复制判定**:`preflight_rejected` 的窗与可等性一律**转调** `resumeRetryLaterFromError`,
3188
+ 本模块里没有第二个 `retryAfterSec` 窄读器。常驻门用九形入参驱动两口,`waitable` 与 `retryAfterSec`
3189
+ 必须**逐字相同**(含「缺席」那一格)。
3190
+
3191
+ **`waitable` 的两种 `false` 落到不同的第三句**(端不必自己再分):
3192
+
3193
+ | 码 | `waitable` | 第三句 |
3194
+ |---|---|---|
3195
+ | `placement_mismatch` | 恒 `false`(等没用) | `Retry with the recorded root, or omit the placement root to inherit it` |
3196
+ | `preflight_rejected` ∧ 无窗 | `false`(**不可判**) | `The engine line above says whether this token can still be redeemed` |
3197
+ | `preflight_rejected` ∧ 有窗 | `true`(正向证据) | `The engine supplied a wait, so this token stays redeemable once the obstacle clears` |
3198
+
3199
+ 🔴 第三句由 `waitable` 选,**绝不**由 message 文本选:按上游散文分支正是「上游改一个词、端的判定
3200
+ 静默空转」的形。门里把两族原话(terminal / retry_later)都灌进 message 而窗不动,文案必须一字不动。
3201
+
3202
+ ⚠️ **`retryAfterSec` 的窄读域比 cli 1.0.x 那份自铸的更窄**(端提货要知道的行为差分):
3203
+
3204
+ | | cli 1.0.x 自铸 | 本口(与 §21 同律) |
3205
+ |---|---|---|
3206
+ | 域 | 有限数 ∧ ≥0 | **整数 ∧ ≥1** |
3207
+ | `0` / 负数 / 小数 | 透传(`0` 会渲成「立刻重试」) | **降缺席**(不渲等待行) |
3208
+
3209
+ server 的铸键逐字是「ms → 秒**向上取整**、**下限 1**」⇒ 真供给里不存在 0 / 负数 / 小数。放行 `0`
3210
+ 就是对端说「立刻重试」,而 resume 是 **AT-MOST-ONCE** 的有副作用动作(叫醒 = 真跑一轮)—— 一个 0
3211
+ 会把「等一会儿」变成热循环。⇒ 壳提货后这三形上的行为**会变**,这是**修好**不是回归。
3212
+
3213
+ **端该怎么接**(cli 半场 = 1.0.101,本车不改壳):
3214
+
3215
+ 1. cli 仓 `sema/resumeRefusalCopy.ts` **改薄成适配层**(或整个删掉,直接从包里 re-export):
3216
+ `RESUME_REFUSAL_CODES` / `resumeRefusalFromError` / `resumeRefusalContent` 三个名字与壳现有的
3217
+ **逐字同名同形**,壳侧的 `ResumeRefusalDetail` 多出一位 `waitable`(additive)。
3218
+ 2. cli 仓 `sema/apiErrorSupplement.ts` 的 61-73 行那条**互斥链**改消费包面:`resumeRefusalFromError` 换成
3219
+ 包导出的那一个,其余一字不动 —— 段序、互斥序(quota → scenario → resume → device)、
3220
+ `retryAfterHint` 的 `??` 取值口全部照旧。
3221
+ 3. 🔴 **等待那一行仍归端渲**:包里的文案**不铸秒数**(写在里面 = 同一个数字上屏两遍);
3222
+ 壳继续用 `retryAfterHint(err, quotaDetail?.retryAfterSec ?? resumeRefusal?.retryAfterSec)`。
3223
+ 4. 开集兜底一字不动:不认识的码 ⇒ `null` ⇒ 端一个字都不补 ⇒
3224
+ `API Error: <status> <errorCode> · <msg>` 原样上屏。
3225
+
3226
+ **可达性如实登记**(不许把预置说成到货):两码在 server 7.51 当版**结构性不可达**(四条腿都不供
3227
+ `placementRoot`,也没有 `resumePreflight` 座)。本模块与壳那份一样是**预置臂**,不是当版可触发的
3228
+ 行为面 —— 收进包是为了「码到货那天三端不至于各说各话」。
3229
+
3230
+ ### 22d. 常驻门
3231
+
3232
+ | 门 | 守什么 |
3233
+ |---|---|
3234
+ | `scripts/run-rule-offers-reader-test.mjs` | 段 ⑨ 新增:三张闭词表单源化与再导出逐字相等 · match 词集双向全等钉 · `directoryRead` 臂认回与四座逐字 · pre-B3 成员归一 · 成员 `kind` 不识丢整只(七形)· `uncoveredDetail` 透传/只丢坏行/缺席不铸空 · 卡端口两腿同吃新形 |
3235
+ | `scripts/run-resume-refusal-copy-test.mjs` | 🆕 公面在场 · **两个闭集关系双向钉** · 不复制判定(九形入参两口逐字相同)· `placement_mismatch` 恒无窗恒不可等且带窗也不翻 · 窄读域「整数 ∧ ≥1」· 文案三句由 `waitable` 选而非 message · 负控与坏载体 · 纯函数 |
3236
+ | `scripts/run-approval-frame-keys-test.mjs` | `ruleOffers` 领先登记退役后回到逐元素相等(其余 6 条领先登记仍在) |
3237
+ | `scripts/run-sdk-floor-test.mjs` | 地板 `8.2.0` 与 peer 声明**三位逐位等值**互绑 |
3238
+ | `scripts/run-public-surface-test.mjs` | peer 地板 / README 三处逐字核 + 公面导出基线 **821 → 828** |
3239
+
3240
+ ---
3241
+
3242
+ ## §23 🆕 sdk 8.3.0 提货 · `Capabilities` 74→93 逐键复核与 SQL 姿态读面上收(S-131)· 三件候件投影(0.59.0)
3243
+
3244
+ 本节三件同一批。**共同的形**都是「上游已经把事实摆在 wire 上了,而包边界这一格空转」——
3245
+ `[1947]` `toolCallId` / `[2942]` `governanceForced` / `#263` 两键 / A-D2 `resolution` /
3246
+ `[4851]` 窗三键之后的**同款病形第 N 例**;不同的是这一批还堵了一条此前**没有任何门看得见**的轴
3247
+ (能力位)。
3248
+
3249
+ ### 23a. sdk 8.3.0 提货:peer 地板 `>=8.2.0` → `>=8.3.0`(本版唯一的非 additive 面)
3250
+
3251
+ | 面 | 0.58.0 | 0.59.0 | 端要做什么 |
3252
+ |---|---|---|---|
3253
+ | peer 地板 | `@sema-agent/sdk >=8.2.0` | **`>=8.3.0`** | 提货前先抬自己的 sdk 依赖;装 <8.3.0 会看到 peer 警告,且本包**运行期真的需要** 8.3.0(见下) |
3254
+ | sdk 值级消费 | 8 个符号 | **10** 个(新增两张 `as const` 闭词表) | 无(本包内部) |
3255
+ | `TOOL_APPROVAL_FRAME_KEYS` 锚 | 18 项 | **27** 项 | 无(对账在门里) |
3256
+ | `APPROVAL_CARD_KEYS` 锚 | 17 项 | **19** 项 | 无(0.59.0 起本包对它有**逐键处置台账**,见 23d) |
3257
+ | `Capabilities` | 74 键 | **93** 键 | 见 23b |
3258
+
3259
+ 🔴 **地板抬升的三条硬理由**(逐条写在 `scripts/run-sdk-floor-test.mjs` 的 `FLOOR` 注里):
3260
+ ① `RULE_OFFERS_ABSENCE_REASONS` / `DENIAL_LIMIT_KINDS` 两张闭词表是**值级** import(随 8.2.0 那三张
3261
+ 一起再导出给三端),<8.3.0 上这两个名字不存在,整包编译不过 —— **这一条单独就足以钉死地板**;
3262
+ ② type-only 的 `AskOrigin` / `RuleOffersAbsence` / `DenialLimitKind` / `DenialLimitFallback` 四个型面
3263
+ (`ToolApprovalFrame.denialLimitFallback` 与公面别名直接引用),<8.3.0 上 `tsc` 报「没有导出成员」;
3264
+ ③ 判据的**真正的量**不是版本号而是三张锚本身(27 / 19 / 93),分别由
3265
+ `run-approval-frame-keys-test.mjs`(帧腿 + 卡面腿)与 `run-engine-caps-ledger-test.mjs` 逐元素对账。
3266
+
3267
+ **同批退役的一整张表**(带退出条件的登记到期自红,不是清理):`run-approval-frame-keys-test.mjs` 的
3268
+ `AHEAD_OF_ANCHOR`(「server 已真发、SDK 锚未跟」的领先记账)里**六条同一天到期** ——
3269
+ `requiresRealApproval` / 窗三键 `expiresAtMs`·`expiresInMs`·`serverNowMs` / `inputHasBidi` / `parked`,
3270
+ sdk 8.3.0 的锚一次全补上。删登记前**先让它自红一次留证**(车内实翻,红词逐字「领先登记
3271
+ requiresRealApproval:SDK 锚**仍无**此键 —— 锚补上了就该删这条登记」),与 `persistedRuleShadowed`
3272
+ (#229)/ `probeCause`(#280)/ `ruleOffers`(0.58.0)三次走的是同一条路。
3273
+ ✅ **表回空 = 健康态**:镜像 27 项与锚 27 项逐元素相等,零豁免。
3274
+
3275
+ #### 帧上新增三键(全 additive;端可直接消费)
3276
+
3277
+ | 键 | 出身 | 缺席语义 | 🔴 端的硬条款 |
3278
+ |---|---|---|---|
3279
+ | `origin` | S-125③ / core 7.5.0 `ASK_ORIGINS` 闭八词(`content_question`/`unresolvable`/`org_unavailable`/`org_rule`/`hook`/`ask_rule`/`denial_limit_fallback`/`policy`),**引擎在门上盖章** | 老引擎 / 非 ask 路径 | **缺席不是 `"policy"`** —— `policy` 是一个正面事实(出自部署 ToolPolicy),把缺席折进去 = 替引擎编话。按**开集**分支,认不得的词渲「未知出身」而不是「没有出身」。与 `governanceForced` **顶替不了对方**(本词答「哪一类权威提的问」,那一位答「本部署运维治理层是不是这只 ask 的门」) |
3280
+ | `ruleOffersAbsence` | S-15 第五单 / core #490 修②,闭三词 `mandated`/`shadowed`/`lane_cannot_speak` | 同时覆盖「有报价」与三扇结构门,**一帧分不出来** | **缺席不是断言**:不许据它渲「这台部署没有规则车道」(那句话看 `capabilities.permissionRules`)。`mandated` 臂**不得**指向「去写一条规则」(门是强制的,写了也消不掉)。ADVISORY 展示元数据,**永不是裁决输入** |
3281
+ | `denialLimitFallback` | S-114 / core 7.4.0 #548,`{consecutive,total,limit,autoDenyAfterMs}` **四成员全必填** | 绝大多数 ask 根本不是回落卡 | 与 `requiresRealApproval` 是**同一次铸造盖的孪生键**,两句话一起渲。🔴 `autoDenyAfterMs` **只渲倒计时,绝不据它自铸第二只定时器**——窗的执行全在引擎,两只窗重叠比原缺陷更坏且静默;`0` = 不武装,**不是**「立刻拒」 |
3282
+
3283
+ **包侧做了什么、没做什么**:
3284
+ - 三键都**到得了卡口**(`ApprovalCardRequest.origin` / `.ruleOffersAbsence` / `.denialLimitFallback`),
3285
+ 单源 = **活卡帧腿**(durable park 行今天不携后两者,core 的 `PendingAction` 上没有这两位);
3286
+ - `origin` / `ruleOffersAbsence` **按开集透传、包内零闭集校验** —— 词表属主是 core,server 侧已按闭集
3287
+ 拒过词表外的值,包再校一遍只会在 core 加员当天把一个**合法**值判没(与 `wiring_manifest.autoMode.reason`
3288
+ 的透传纪律逐字同规)。型面与运行期词表都在公面上,端写 `switch` **必须带 `default` 臂**;
3289
+ - `denialLimitFallback` 走**包内窄读器**(四成员全必填,与 server `readDenialLimitFallback` 的 `.strict()`
3290
+ 同判据):**缺一整只丢** —— 半只对象上的 `consecutive` 会被人当成真实次数读。计数与窗按「有限非负数」
3291
+ 判(`0` 是合法读数,不折缺席),`limit` 按**开集**读(非空串即收)。
3292
+
3293
+ ### 23b. `Capabilities` 74→93 逐键复核 + 嵌套对象读口 + S-131 SQL 姿态读面上收
3294
+
3295
+ **病**:sdk 一版加了 **19 个能力位**,而本包一个字不动这件事,在此前的门盘上**一声不响** —— 没有任何
3296
+ 一道门看得见「上游给了一个新能力位」。这正是本节开头那个病形在**能力位**这条轴上的形状。
3297
+
3298
+ **修一:逐键处置台账 + 常驻门**(`scripts/run-engine-caps-ledger-test.mjs`)。93 键逐键定性,
3299
+ 台账 ↔ SDK `Capabilities` 键集**逐元素相等**(SDK 加位 ⇒ 台账缺行 ⇒ 红,逼一次显式处置;
3300
+ 台账留着 SDK 已删的键 ⇒ 也红)。今天的分布:
3301
+
3302
+ | 处置 | 数 | 说明 |
3303
+ |---|---|---|
3304
+ | `read` | 14 | 本包真读:`approvals`·`fleet`·`manualCompact`·`permissionRules`·`permissionRulesRevoke`·**`sql`**(本批新增)·`subagentOutput`·`subagentResume`·`subagentStream`·`taskAgents`·`taskHandles`·`version`·`workflows`·`workflowsGate`。每行登记读点文件,门核**代码位置**(剥注释)真提到这个键 |
3305
+ | `host_injected` | 3 | `approvalDecisionNote`/`respondFreeFormRules`/`respondBatchRuleOffers` —— 位由宿主经 `ToolApprovalFrameLaneOpts.*Capable` 注入,包不自读(respond 函数本身是宿主注入的,由注入方一并交代自己那台引擎的能力位,少一条「包探到的与宿主发出去的不是同一台引擎」的静默分叉) |
3306
+ | `submission_side` | 8 | `oneShot`/`images`/`scratchpadDir`/`interactiveTools`/`retainBackgroundProcesses`/`forwardSubagentEvents`/`compactionModel`/`appendSystemPrompt` —— **同名的是提交位不是能力门**;提交体是开集、老 worker 静默忽略 ⇒ 发送侧刻意不设前置门 |
3307
+ | `not_read` | 68 | 本包**零读点**(门 grep 实证),本位不经包边界:端要它就直读 `client.capabilities()` 的回体。**写明理由的未消费,不是丢位** |
3308
+
3309
+ 🔴 门还有一条**反向普查**:src 里每一处 caps 读点(五种调用形)的键必须是台账里的 `read` 行 ——
3310
+ 悄悄加读点而台账还写着「不读」当场红。
3311
+
3312
+ **修二:嵌套对象读口 `engineCapValue`**(`src/engineCapsCache.ts`,additive)。既有三口
3313
+ (`engineCapTrue` / `engineCapNestedTrue` / `engineCapString`)把四种「读不出」**全折成 fail-closed 的
3314
+ 一档** —— 对**放行**问题这是对的,对**读面/诊断**问题是错的。新口四态诚实作答:
3315
+
3316
+ ```ts
3317
+ type EngineCapValueState =
3318
+ | { kind: 'unobserved' } // 这个 base 的 caps 一次都没落地(没 kick / 还在飞 / 探测失败)
3319
+ | { kind: 'not_reported' } // caps 在手,回体上没有这个键 ⇒ 老引擎
3320
+ | { kind: 'null' } // 引擎明确说 null —— 正面事实,不是缺席
3321
+ | { kind: 'value'; value: unknown }
3322
+ engineCapValue(baseUrl: string | undefined, key: string): EngineCapValueState
3323
+ ```
3324
+ 🔴 `value` 位**不做形校验**:形归各能力位自己的窄读器,通用口再校一遍就会在上游 additive 加成员那天
3325
+ 把合法值挡在包边界外。既有三口的 fail-closed 语义**一字未改**。
3326
+
3327
+ **修三:S-131 SQL 姿态读面从壳侧上收**(`src/sqlEngineCapability.ts`,additive 六件)。
3328
+ `GET /v1/capabilities.sql`(server ≥7.60.0)的值是 `{engine,isolation,txnMode} | null`。
3329
+ 0.58.0 时这份窄读器长在**壳里**,理由是包侧结构上读不出来(没有嵌套对象读口)—— 归层债,本批同批清。
3330
+
3331
+ | 导出 | 形 |
3332
+ |---|---|
3333
+ | `projectSqlEngineCapability(caps: unknown): SqlEngineReading \| undefined` | caps 回体 → 四态读数;畸形一律 `undefined` |
3334
+ | `SqlEngineReading` | `{kind:'unobserved'} \| {kind:'not_reported'} \| {kind:'none'} \| {kind:'present', view}` |
3335
+ | `SqlEngineCapabilityView` | `{engine: string, isolation: string, txnMode: string \| null}` |
3336
+ | `noteEngineCapsForSqlEngine(baseUrl, caps)` | 宿主 caps probe 的读面 tee 落点(fail-soft,绝不 throw) |
3337
+ | `observedSqlEngine(baseUrl?)` | per-base 同步读;这一格空缺 ⇒ `unobserved`(缺省锚 = `engineWireTarget()?.baseUrl`) |
3338
+ | `forgetSqlEngineReading(baseUrl)` | **换代失效口**(引擎温切后调) |
3339
+ | `sqlEngineDoctorDetail(reading)` | 四态 → doctor 行的 detail 串,**唯一措辞真源** |
3340
+
3341
+ 🔴 **四态不是两态**,四件事互不相同、也互不蕴含:`unobserved`(本进程没观测过,一次性 doctor 恒在
3342
+ 这一档)/ `not_reported`(老引擎不报这一位)/ `none`(**引擎明确说没有 SQL 后端**,正面事实)/
3343
+ `present`。折任意两档 = 屏上出现一句**说得斩钉截铁却不成立**的话。
3344
+ 🔴 `txnMode: null` 是**铸点域内的合法值**(上游逐字:`null` = 这个引擎没有这个指示位,**不是**
3345
+ `optimistic`),三种引擎里 `innodb`/`pg` 两种恒 `null` —— 判成畸形会让两种正常部署的完整读数被整条
3346
+ 丢掉(B-025「消费域比铸点域更窄」在新件上复发)。
3347
+ 🔴 **换代失效口是独立的一条路**:代际闸挡的是「旧响应写脏新一代」,而这一格的病是反过来的 ——
3348
+ 新一代探测**根本没成功**(超时 / reject / 还在飞),tee 一次都没触发,上一台引擎留在同一端口上的读数
3349
+ 继续被当成当代事实答出去。处置是**清成未观测**,不是留旧值也不是铸一个 `none`。
3350
+
3351
+ **端该怎么接**(cli 半场 = 1.0.102,本车不改壳):
3352
+ 1. 🔴 **导出名与壳侧那份(cli 仓 `sema/sqlEngineCapability.ts`)逐字相同** —— 这是本件的 drift-lock:
3353
+ 包一发同名符号,壳的 `run-layer-shadow-export-gate-test.mjs`(同名影子导出门)**当场红**,逼那份
3354
+ 壳侧副本换装成 `export { … } from '@sema-agent/client-core'`,而不是两边各自演进。
3355
+ 2. 壳侧 `capsBaseUrl()` 直读 `process.env.SEMA_LIVE_BASEURL`;包内零 `process`(portability 门盯着),
3356
+ 读锚走 `engineWireTarget()?.baseUrl` —— 其 env 臂读的**就是同一个变量** ⇒ Node 壳上行为一字节不变,
3357
+ 浏览器/桌面宿主改用 `installEngineWireTarget()` 显式装。
3358
+ 3. ⚠️ **一处已知呈现差分,换装时随批裁一次**:壳那份 `sqlEngineDoctorDetail` 用
3359
+ `cleanUntrustedForDisplay`(`.` 占位形),而壳自己的 `untrustedDisplayText` 头注写着「单行字段
3360
+ (路径/URL/参数键值)**必须**用 `cleanUntrustedScalar`」(可见转义形)—— 三座正是单行标量。
3361
+ 包按那条规则实现(`escapeDisplayControlChars` 单源),所以对**正常读数**(`tidb` /
3362
+ `REPEATABLE-READ` / `pessimistic`)两侧**逐字节相同**,只有含控制符的病态值渲染形不同。
3363
+ 另:包侧**先按 40 单元截原字节再消毒**(壳那份是先清后截)—— 可见转义是 1:6 展开,先清后截会把
3364
+ 一个转义序列拦腰截断,屏上留下 `\u20` 这种既不是字符也不是转义的残片。
3365
+
3366
+ ### 23c. 三件候件投影(cli [6476]⑥;壳不自铸 ⇒ 包侧铸)
3367
+
3368
+ **① `tool_end.autoDenied`**(S-125⑧;server ≥7.57.0 `trace/project.js` 的 `toolEndEventData` 条件 stamp)
3369
+ —— 这次 deny 是**引擎的窗自己拒的**。落点 = `eventToSdkMessage` 的 `case 'tool_end'` 内部臂
3370
+ (`ToolEndResultArmLike.autoDenied`),**严格 `true` 才上臂**。
3371
+
3372
+ 🔴 **它答的是既有两键答不了的那一问**:`settledBy:"timeout"` 与 `resolution:"window_expired"` 覆盖
3373
+ **一切**审批窗到期(普通 ask 的 TTL 也在内),分不出「这一次到期是**自动拒**收的场」还是「park 了
3374
+ 等人」。要渲「自动拒(限额回落)」而不是「已转后台候批」,判据只有这一位。
3375
+ 🔴 **缺席不带语义**:同时覆盖「不是自动拒」「老引擎不报」「这次根本没走审批」三形 ⇒ **禁**读成
3376
+ 「是人拒的」。⇄ 卡面那一侧的孪生位 = `ApprovalCardRequest.denialLimitFallback`(带触限计数与窗),
3377
+ 两者是同一件事的**事前 / 事后**两个面。
3378
+
3379
+ **② `denialLimitFallback` 上卡**:见 23a 第三行(端渲「自动拒(限额回落)· 已连续拒 N / 累计 M,
3380
+ 触的是 consecutive|total 这道界」,并**必须**同时呈 `requiresRealApproval` 的「这一次得真人批」)。
3381
+
3382
+ **③ `wiring_manifest.mcp[]`**(S-124 / core 7.5.0,server ≥7.60.0)—— `WiringManifestChromeEvent`
3383
+ 的**第三段**(前两段 = 0.56.0 的 `modelGate` / `autoMode`)。条目形
3384
+ `{name, status, source?, errorCode?, toolCount?}`,投影键 `_sema_mcp`(登记在 `docs/type-superset.json`)。
3385
+
3386
+ 🔴 **空数组不是缺席**(core 顶注逐字:"an empty array is *this leg declared no servers*, absence is an
3387
+ older mint or an external derivation")—— `mcp: []` 是「这条腿一台 MCP 都没申报」这句**正面事实**,
3388
+ 缺席才是「没报」。判在场写 `mcp !== undefined`,写 `mcp?.length` 就把两句话折成了一句。
3389
+ ⚠️ **与同帧 `modelGate.removed: []` 规矩方向相反**(那一格空数组是**坏值**,因为 core 的契约是
3390
+ 「有门卸才铸段」)——两条相反的规矩同处一帧,门里有一条**反向对照**钉着,不许被顺手统一。
3391
+ 🔴 **逐条独立**:坏行(缺 `name` / 缺 `status` / 非对象)只丢自己,绝不丢整表;`toolCount: 0` 是读数
3392
+ (连上了、零工具)不是缺席。
3393
+ ⚠️ **「过滤后为空」不是「原本就是空」**(异源对抗复审 r1 真病):一份非空却**零行幸存**的回体
3394
+ (例:唯一那行缺 `status`)若照样铸 `[]`,消费端按上面那条义务读到的就是「一台都没申报」这句
3395
+ **肯定话** —— 读不出来被伪装成一个确定的零。⇒ 本包对这一形落**段缺席**;端读到的 `[]` 因此
3396
+ **一定**是引擎真报的零申报。只要还有幸存者,坏行照旧只丢自己(半张表仍是真读数)。
3397
+ 🔴 **`errorCode` 不套闭集也不套形正则**:core `MCP_FAILURE_CODES` 十个具名词之外还有 `http_<status>`
3398
+ 形,词的单一属主在 core ⇒ 只判非空串,端的 `switch` **必须带 `default` 臂**。
3399
+ 🔴 **远端作者的自由文本 `error` 一格不投**(上游同裁):进来会同时破本段「无自由文本 ⇒ 不脱敏」的
3400
+ 段内不变量、和 core 把远端 MCP 错误文本脱敏收敛成**一个**铸点的单铸律。可操作的因由在 `errorCode`。
3401
+ ⚠️ **不与 `GET /v1/sessions/:id/mcp` 的二态合并、也不互相校验**:那条端点的真源是 server 自己的
3402
+ 部署面台账,本段的真源是 core 这条腿 materialize 的连接时快照 —— 同名不同源,合并只会造出一个
3403
+ 「哪个才算数」的新问题。
3404
+
3405
+ ### 23d. 黑盒验收判据(wire 可观察,不引用内部实现)
3406
+
3407
+ | # | 构造 | 期望 |
3408
+ |---|---|---|
3409
+ | G1 | 一台 ≥7.57.0 引擎上让 auto 分类器连拒到限额,拿到那张回落卡 | 卡上同时有「限额回落」四座(两个计数 + 触的哪道界 + 窗)与「这一次必须真人批」;窗为 `0` 时**不渲倒计时**,而不是渲「立刻拒」 |
3410
+ | G2 | 同一张卡不理它,等引擎的窗走完 | 该 call 的 `tool_end` 上出现自动拒判别位;端渲「自动拒(限额回落)」而**不是**「已转后台候批」 |
3411
+ | G3 | 一台**无**规则店的部署上触一次 mandated 门 | 卡上没有「不再询问」这一格,但有一句**点名哪扇门关了**的话;那句话**不指向**「去写一条规则」 |
3412
+ | G4 | 老引擎(<7.57.0)上跑同样的 ask | 卡上三个新位**一个都不在场**,卡形与 0.58.0 逐字节相同(additive 不回削) |
3413
+ | G5 | 一条腿**零** MCP 申报 vs 一台老引擎 | 前者屏上说「这条腿没有申报任何 MCP 服务器」,后者**什么都不说**(两者不可同形) |
3414
+ | G5b | 一份 `mcp` 里**每一行**都缺 `status`(整表读不出来) | 屏上**不说**「一台都没申报」——与 G5 前者不可同形(读不出 ≠ 知道是零) |
3415
+ | G6 | 一台 MCP 连接失败 | 屏上有机器码(含 `http_<status>` 形照渲),**没有**远端返回的自由文本 |
3416
+ | G7 | `sema doctor` 一次性进程(不起 live client) | SQL 行说「未观测」,**不说**「这台部署没有 SQL 后端」 |
3417
+ | G8 | 壳自 spawn 的单机形(引擎回 `sql: null`) | SQL 行说「这台部署没有 SQL 后端」,**不说**「未观测」;两句话与 G7 那句**逐字不同** |
3418
+ | G9 | 同端口 respawn 到一台起不来的引擎 | SQL 行回到「未观测」,**不**继续答上一台引擎的姿态 |
3419
+ | G10 | 一台 `innodb` / `pg` 部署 | SQL 行渲出完整三座,txn 那一格是一句**显式的话**(「这个引擎没有这个指示位」),既不留白也不写 `optimistic` |
3420
+
3421
+ ### 23e. 常驻门
3422
+
3423
+ | 门 | 守什么 |
3424
+ |---|---|
3425
+ | `scripts/run-approval-frame-keys-test.mjs` | 帧腿:镜像 27 项 ↔ sdk 8.3.0 锚逐元素相等,`AHEAD_OF_ANCHOR` **回空**;fixture 腿:server 7.60.0 的 26 个声明键本仓镜像全有(多出的只许是登记过的退役键 `ruleSuggestions`)。🆕 **卡面腿**:sdk `APPROVAL_CARD_KEYS`(19)逐键处置台账 —— `carried` 行必须真在 `ApprovalCardRequest` 上、`not_carried` 行必须真不在且写了理由,与锚**逐元素相等**(sdk 给卡加位当天红) |
3426
+ | 🆕 `scripts/run-engine-caps-ledger-test.mjs` | `Capabilities` 93 键逐键处置台账;台账 ↔ SDK 键集双向等值;`read` 行的代码位置实证;`not_read` 行零读点;五形读点反向普查(每形先在伪造样本上自证)。**r1 采纳两条真病**:读口表补 `engineCapState`(漏它 ⇒ 台账可以一边写 not_read 一边真在读)、键按**第 2 实参的位置事实**解析且**不在对账前按锚过滤**(过滤掉锚外键 ⇒ 一个拼错的键名连同它代表的真读点在对账前蒸发,门原样绿而那条能力车道恒 false)—— 两条复现出来的反例已长驻门内 |
3427
+ | 🆕 `scripts/run-sql-engine-capability-test.mjs` | 导出名 drift-lock;四态判别(`none` ≠ `not_reported` ≠ `unobserved`);`txnMode: null` 是合法值;畸形回体删格;换代失效口;四句话互不蕴含;UNTRUSTED 消毒与封长(截长在消毒**之前**);`engineCapValue` 四态两两可分 + 既有放行口语义未改 |
3428
+ | `scripts/run-wiring-manifest-projection-test.mjs` | 段 P6/A4 新增:`mcp: []` 是正面事实(投影层与适配层两处都按 `Array.isArray` 判在场)· **非空输入零行幸存 ⇒ 段缺席**(r1 真病,带判别力自证与「至少一行幸存仍只丢坏行」的边界)· 坏行只丢自己 · `toolCount: 0` 是读数 · `errorCode` 不套闭集 · `error` 自由文本不投 · 未知新键不 spread · **与 `removed: []` 的反向对照** |
3429
+ | `scripts/run-additive-key-passthrough-test.mjs` | 段 G6 新增:`tool_end.autoDenied` 严格 `true` 上臂 · `false`/非布尔一律不在场 · **判别力**(只有 `settledBy:"timeout"`+`resolution:"window_expired"` 时本位缺席)· 老引擎零差异 |
3430
+ | `scripts/run-hitl-gate-honesty-test.mjs` | 段 F15 新增:三个新位**到不到得了卡口** · `origin` 缺席不折 `"policy"` · `ruleOffersAbsence` 与 `ruleOffers` 同时在场时两者都上卡(包不替上游湮灭矛盾)· `denialLimitFallback` 四成员缺一整只丢 / `0` 是合法读数 / `limit` 开集 · 老引擎三键全不在场 |
3431
+ | `scripts/run-sdk-floor-test.mjs` | 地板 `8.3.0` 与 peer 声明**三位逐位等值**互绑 |
3432
+ | `scripts/run-public-surface-test.mjs` | peer 地板 / README 三处逐字核 + 公面导出基线 **828 → 836**(测试钩 41 → 42) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/client-core",
3
- "version": "0.57.0",
3
+ "version": "0.59.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",
@@ -31,12 +31,12 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@sema-agent/agent-types": ">=0.2.0",
34
- "@sema-agent/sdk": ">=7.4.0"
34
+ "@sema-agent/sdk": ">=8.3.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@sema-agent/agent-types": "^0.2.0",
38
38
  "@sema-agent/core": "~7.3.0",
39
- "@sema-agent/sdk": "^7.4.0",
39
+ "@sema-agent/sdk": "^8.3.0",
40
40
  "esbuild": "^0.27.4",
41
41
  "typescript": "^6.0.2"
42
42
  }