@sema-agent/client-core 0.61.0 → 0.62.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.
@@ -29,7 +29,7 @@
29
29
  * 🔴 与**模式型** write deny(`SENSITIVE_WRITE_PATTERNS`)是**并列机制**,两个读面分开报、
30
30
  * 绝不合成一位:两者的解法不同(一套改模式,一套改名表)。
31
31
  */
32
- import { escapeDisplayControlChars } from './fleetTaskDesc.js';
32
+ import { capForDisplay } from './fleetTaskDesc.js';
33
33
  import { engineWireTarget } from './engineWireTarget.js';
34
34
  import { engineCapsGeneration } from './engineCapsCache.js';
35
35
  /**
@@ -186,17 +186,21 @@ export function writeProtectionDoctorDetail(reading) {
186
186
  /**
187
187
  * operator 面读数 → 一行 detail(行名是 UNTRUSTED 自由文本 ⇒ 呈前**逐条**消毒 + 封长)。
188
188
  *
189
+ * 🔴 消毒与封长的顺序 = **先转义、后按转义结果封长**({@link capForDisplay},0.62.0 起本包该族的
190
+ * 唯一实现)。此前这三处是反的(先按原文 `slice` 再转义),一段纯控制字符的 40 字符原文转义后
191
+ * 能占 240 个显示字符 —— 承诺的列宽预算成了名义值的六倍。同形存量另有 SQL 姿态行一处,同批同改。
192
+ *
189
193
  * 🔴 只给**行数与来源**加上「头几行的名字」,不整表倾泻:一行诊断不是一个表格,而 operator 面的
190
194
  * 真表读法是那个端点本身。
191
195
  * 🔴 `rows: []` 渲的是**显式无表**这句正面事实,不是「读不出」。
192
196
  */
193
197
  export function writeProtectionPostureDetail(posture) {
194
- const source = escapeDisplayControlChars(posture.source.slice(0, WP_DETAIL_MAX));
198
+ const source = capForDisplay(posture.source, WP_DETAIL_MAX);
195
199
  if (posture.rows.length === 0)
196
200
  return `source ${source} · no protected names in effect`;
197
201
  const shown = posture.rows
198
202
  .slice(0, 3)
199
- .map((r) => `${escapeDisplayControlChars(r.name.slice(0, WP_DETAIL_MAX))}(${escapeDisplayControlChars(r.kind.slice(0, WP_DETAIL_MAX))})`)
203
+ .map((r) => `${capForDisplay(r.name, WP_DETAIL_MAX)}(${capForDisplay(r.kind, WP_DETAIL_MAX)})`)
200
204
  .join(', ');
201
205
  const more = posture.rows.length > 3 ? `, +${String(posture.rows.length - 3)} more` : '';
202
206
  const dropped = posture.droppedDefaultRows !== undefined && posture.droppedDefaultRows.length > 0
@@ -23,7 +23,7 @@
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
- | 公开导出面 | **864** 个运行期符号(+ 43 个测试钩;= 工作树当下的值 = 0.61.0 三件 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
+ | 公开导出面 | **869** 个运行期符号(+ 44 个测试钩;= 工作树当下的值 = 0.62.0 五件 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`(**864** 项)。
114
+ > 全集真源 = `scripts/public-export-baseline.json` 的 `names`(**869** 项)。
115
115
  > 本节**不逐名抄**,只给「域 → 承重导出 → 用途 → 实现锚」。承重导出 = 一个端为了让这个域干活
116
116
  > **必须**直接调到的那几个符号;其余是它们的类型、变体与辅助位。
117
117
  > 单一入口:`import { … } from '@sema-agent/client-core'`(`exports` 只有 `.` 一个;
@@ -135,20 +135,20 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
135
135
  `WorkflowsGateUnknownDenial` 四形**不在**基线里,`src/selfOrchestrationDenial.ts` 对基线贡献
136
136
  **4** 项运行期导出(三个函数 + `SELF_ORCHESTRATION_RETRY_WITHOUT`)。
137
137
 
138
- 864 项的内部构成(帮助端估读表大小):**256** 项是 `SCREAMING_SNAKE` 常量数据表/词汇表
138
+ 869 项的内部构成(帮助端估读表大小):**258** 项是 `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 域,逐域计数之和 = 864)
143
+ ### 2b. 域图(16 域,逐域计数之和 = 869)
144
144
 
145
145
  | # | 域 | 名数 | 承重导出 | 用途 | 实现锚 |
146
146
  |---|---|---|---|---|---|
147
147
  | 1 | **适配内核(下行主链)** | 39 | `adapt` · `createWireToCcAdapter` · `runStream` · `eventToSdkMessage` · `terminalToSdkResult` · `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 主战场) | 153 | `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) · `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
- | 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
- | 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` |
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` |
151
+ | 5 | **fleet 投影** | 47 | `createFleetLedger` · `projectTasks` · `projectWorkflows` · `projectFleetAgentRows` · `readEngineActiveBgTasks` · `FLEET_TASK_VIEW_KEYS` · `escapeDisplayControlChars`(不可见字符可见化,行标签/描述消毒的共享底座)· `capForDisplay`(0.62.0:呈前**消毒 + 封长**的共用铸点 —— 先转义、后按转义结果封长,截点避开半截转义 token 与合法代理对;本包该族四处此前各写一份、其中三份顺序是反的,详见 §26⑦)· `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` |
153
153
  | 7 | **通知与 outstanding 台账** | 51 | `installNotificationQueuePort` · `normalizeTaskNotification` · `taskNotificationDedupKeyFromWire` · `registerOutstandingBgTask` / `registerOutstandingWorkflowRun` · `notificationQueuePortMisses` · `subscribeOutstandingWorkflows` · `outstandingDeliverableWorkflowCount` | `task_notification` 归一 + 去重 + 投递进宿主命令队列的**一把闸**;`outstandingDeliverableWorkflowCount()` 是 headless `-p` 的**退出门** · `classifyPeerNotification` / `renderPeerFrameTranscriptText` / `parsePeerFrameText` / `peerFrameDisplayName` + 三张闭集表(design/385,0.54.0:同一条 `task_notification` 车道上三条**引擎注入帧**的类型化投影 —— 判别位=载体在场而非 summary 文本,详见 §17) | `src/notifications.ts`(11 个 module 台账) |
154
154
  | 8 | **工具结果卡** | 25 | `structuredToToolUseResult` · `readAsyncLaunchedAgentReceipt` · `wireOutputToBody` · `parseModelFacingBash` · `getPatchFromContents` · `toolEndResultToUserFrame` · `flattenToolOutput` | 铸端要渲的 `tool_result` 卡体,含客户端 diff hunk(唯一 runtime dep 的用处) | `src/toolResult.ts`、`src/printToolResultFrame.ts`、`src/diff/patch.ts` |
@@ -156,7 +156,7 @@ SDK 核对「本包 import 的每个值级符号仍然导出」「`TaskStats.cos
156
156
  | 10 | **headless / 部署旋钮 wire** | 61 | `parseSandboxArgv` / `sandboxRequestFields` · `parseLimitsArgv` / `limitsForPrint` · `resolveHeadlessFinalVerify` · `resolveHeadlessPermissionMode` · `resolveHeadlessInteractiveTools` · `armDetachCancel` + `detachCancelArm` + `isDetachArmed` · `withHeadlessR1Reconnect` | `-p`/headless 车道的 env+argv 旋钮。🔴 `detachWire` 是**拆**的补偿:判定与 cancel-arm 台账在库,信号路径的裸 fetch 留宿主(`detachCancelArm()` 是取件口) | `src/sandboxWire.ts`、`scenarioWire.ts`、`finalVerifyWire.ts`、`limitsWire.ts`、`interactiveToolsWire.ts`、`headlessPermissionModeWire.ts`、`headlessReconnectWire.ts`、`detachWire.ts` |
157
157
  | 11 | **模型目录与预算** | 67 | `resolveModelCatalog` · `loadCatalogWithSources` · `PROVIDER_PRESETS` / `MODEL_FAMILIES` · `defaultMaxTokensFor` · `getLiveModelCatalog` / `setLiveModelCatalogRefresher` · `providerAuthMethods` / `beginDeviceCodeAuth` · `providerCatalogRows` / `providerCatalogRowDetail` / `providerPresetById`(#244 F4 族D A-028.17:46 家表的规范折表层 —— 全表不重排、诚实缺席「model id typed in」,cli 目录/web 向导同一份折表)· `TIER_ORDER` / `CC_TIER_ALIASES` / `isTier` / `resolveTierBinding`(A-028.18:档位词表+校验+fail-open 降档派生单源;settings 存储归宿主)· `resolveEntryVision` / `computeDeleteBlockers` / `computeDeleteWarnings`(0.38.0 #318 件③ 上收:Model Hub 供给面的三端公共判定 —— vision 生效值+来源三态、删除断链核(拒删+指路)、删除降级后果(照删但必说)。**零 IO**,读盘那半场留各端;`doc === null` 的两义在调用方分流) | 三层 provider 目录解析(线上 URL → 包内预设 → 用户覆盖)+ per-model `maxTokens` 封顶。线上腿需注入 `CatalogFetchJson`,缺席 ⇒ 整条不启用(`online.reason='no-fetch-port'`);缓存落盘经 `CatalogCachePort` | `src/model/{catalog,catalogLoader,providerAuth,providerPresets,providerCatalog,tierVocabulary}.ts`、`src/liveModelCatalog.ts`、`src/modelBudgetRule.ts`、`src/sessionModelLatch.ts`、`src/effortWire.ts` |
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
- | 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 桌面壳里的符号只会零命中,而零命中在这里**既不证真也不证伪**。复核这些断言**不得**拿本仓语料当反证 |
159
+ | 13 | **座位 IPC 契约** | 34 | `LOCAL_SESSIONS_SPEC` · `SEAT_METHOD_NAMES` · `SEAT_EVENT_TYPES` · `isLocalSessionEvent` · `isToolPermissionRequest` · `toolPermissionRequestId` · `SEAT_VALIDATOR_KEY_COVERAGE` · `SEAT_SEND_MESSAGE_KEY_ORIGINS`(0.62.0:座位载荷**逐键出身**登记 —— 每个位要么写明转投哪个引擎请求位、要么写明为什么不上 wire;常驻门对**装在盘上的** sdk 型面逐名核,详见 §26③)| desktop↔web 座位 IPC 契约的**单一真源**(此前两边各一份、名字零重合 ⇒ 编译器永远不会告诉你它们漂了)。🔴 加 verb 忘了加 `LOCAL_SESSIONS_SPEC` **不报错**:preload 不注册 channel、渲染端读到 `undefined` | `src/seatContract.ts`(**零 import**,纯类型 + 常量 + 纯谓词)。🔴 **证据等级标注(0.42.0,test [5087] 的「语料**种类**缺口」/ cli [5088] 认领件)**:该文件里所有以「CC 如何如何」为形的断言(`212 methods` / `854-channel census` / 方法名逐字保留 / `fQe` 逐字段对照 / 一切 `.vite/build/index.chunk-*.js` 坐标)**证据等级 = 桌面 unpack,本地语料库不可复验** —— 本仓手边可复验的参照语料**只覆盖终端 CLI 形态**的静态产物,拿它去 grep 桌面壳里的符号只会零命中,而零命中在这里**既不证真也不证伪**。复核这些断言**不得**拿本仓语料当反证 |
160
160
  | 14 | **宿主端口与会话槽** | 26 | `installHost` · `installHostFor` · `hostPortMisses(For)` · `DEFAULT_SESSION_KEY` · `hostEnv` · `unrefTimer` · `parseLocaleTag` / `pickUiLanguage`(#244 F4 族D A-028.20:locale tag 手术单源 + UI 语言判定;与 `resolveRegionHint` 双出口成文 —— 语言偏好域 en/zh ≠ 地址可达域 cn/intl/unknown,`zh-Hant` 前者 zh 后者 intl 是设计)· `engineNamespaceKeyFor` / `mergeSessionMapRecord` / `mergeEngineEntry`(A-028.12:会话 id 映射单一键形 + merge 判定;存储经 `SessionMapStorePort` 归端 —— cli 文件锁/原子写,web localStorage)| 进程/端级装配层(settings/fs/queue/timers/session/log/probe),与 per-turn 的 `AdapterContext` **分层**。头注的判定规则:**这个能力每 turn 都会变吗?** 会 ⇒ `ctx`;不会 ⇒ `installHost` | `src/host.ts`、`src/hostEnv.ts`、`src/sessionSlot.ts`、`src/unrefTimer.ts`、`src/env/{localeGeo,localeTag,uiLanguage}.ts`、`src/sessionMap.ts` |
161
161
  | 15 | **控制面与传输** | 99 | `ControlRouter`(+ `ControlSafetyError`)· `makeEngineWireClient` + `resolveWireAuth` · `installEngineWireTarget` · `diagnoseSseIdleTear` / `isSseIdleError` · `attemptActiveRunSelfHeal` + `activeRunBusySignal` + `activeRunSelfHealRow` / `activeRunBusyHeadlessRow` · `kickEngineCapsProbe` / `engineCapTrue` / `invalidateEngineCaps(baseUrl, probe?)`(#307 S25:引擎温切后的 caps 生产失效口 —— kick 自带幂等闸,同 baseUrl 重启后不显式失效就永远读到旧引擎那一版能力位;调用方 = 壳的 respawn/restartEngine。🔴 **推荐两参形**:第二参给替代探测则「推进代际 + 注册新探测」在同一同步块内完成,失效与下一次 kick 之间那个「等待者读到未判」的窗按构造不存在;单参形保留给「只丢缓存、这一刻没有替代探测」的调用方,那种情形下读到未判是诚实结局) · `engineCapValue`(S-131,0.59.0:能力位的**四态**通用读口 `unobserved`/`not_reported`/`null`/`value` —— 既有三口把四种「读不出」全折成 fail-closed 一档,对**放行**问题是对的、对**读面/诊断**问题是错的:`null`(引擎明确说没有,正面事实)会与「老引擎不报」「还没探到」在屏上同形。`value` 位刻意不做形校验,形归各能力位自己的窄读器,详见 §23b)· `projectSqlEngineCapability` / `observedSqlEngine` / `noteEngineCapsForSqlEngine` / `forgetSqlEngineReading` / `sqlEngineDoctorDetail`(S-131,0.59.0:`Capabilities.sql`(server ≥7.60.0)的四态读面**从壳侧上收** —— 归层债,0.58.0 时它长在壳里正是因为包侧没有嵌套对象读口。🔴 **导出名与壳侧那份逐字同名 = drift-lock**;`txnMode: null` 是铸点域内的合法值不是畸形;换代失效口清成未观测而不是留旧值,详见 §23b)· `mapBrainStatusToRetry` · `waitForClaimRelease` + `CLAIM_RELEASED_STATES` / `CLAIM_HELD_STATES` · `atMostOnceFailureClass` / `readSteerDelivery` · `clearRunningChoiceOffer`(Inkglow-1085 P0b①:「Do nothing」登记的清口 —— 端的「重新打开操作菜单」入口;登记在场时 attemptActiveRunSelfHeal 不整卡重弹,not-parked 结局带 `alreadyOffered: true` 判别位,端据此降级渲一行)· `INTERACTIVE_WAY_OUT`(默认出路串单源)· `engineSessionParamFor`(design/285 批 0:`?session=` 派生的 **per-key** 形 —— `hostSessionFor(sessionKey)?.currentSessionId()` + [1501] 空串归一;零参 `engineSessionParam()` = 默认槽兼容层,取值链逐字等价)· `normalizeWirePrincipal`(A-028.10:principal 在场性 trim 原语 —— 全空白=缺席不发头,engineWireTarget 两臂/makeEngineWireClient/壳 livePrincipal 同尺)· `readSessionMemoryStatus` / `classifyMemoryStatusFailure` / `readCaptureOptOut` / `readLastCapture`(S-53 会话记忆姿态读面,0.48.0:失败分诊**码优先**——两个 404 分道 `not_found.session` / `not_found.route`,无码 404 不猜落 failed;五键逐键缺席语义两个合读器,`lastCapture` 三态的判别材料是 `committedCount` 不是本键;IO 归宿主注入 `MemoryStatusClientLike`,详见 §11) · `classifyTurnWireError` / `isWireTransportError` / `isPreStreamDrainingReject` / `isResumeAtRejection` / `drainingRetryDelayMs` / `scenarioDenyFromError` + `WIRE_NETWORK_ERROR_PATTERN`(A-028.11/.13:turn 错误分型判定半场,人话文案与渲染归端)· `resumeRetryLaterFromError`(L-102,0.57.0:resume 族**时间性拒绝**二码的判型半场 —— 这一族里唯一**带得出「等多久」**(`retryAfterSec`)的两个码。🔴 闭集**不是**「哪些码可以等」的名单:同族 `resume.row_recycling` 同样可等(窗口自清)只是没有秒数 ⇒ 本读口返回 `null` 只意味着没命中这两码,详见 §21) · `projectWriteProtectionCapability` / `observedWriteProtection` / `noteEngineCapsForWriteProtection` / `forgetWriteProtectionReading` / `writeProtectionDoctorDetail` / `projectWriteProtectionPosture` / `writeProtectionPostureDetail`(S-138,0.60.0:`Capabilities.writeProtection` (engine ≥7.63.0)的**四态**读面 + operator 面行表 —— 与上面 S-131 那一格**同构同纪律**。🔴 三位刻意不合成一个布尔;`not_reported` **不是**「这台部署没有写保护表」(座位缺席恰是缺省表在岗);逐行 name/kind 走**最小披露**只上 operator 面,详见 §24e)· `projectReadFacePosture` / `readFacePostureDetail` / `readFaceDisagreement`(S-167,0.61.0:operator 面 `diagnostics.wiring.readFace`(engine ≥7.65.0)的窄读器 —— 与上面S-138 那一格**同构同纪律**。🔴 三句「答不出来」逐字互异且没有一句等于「没有 READ 档」;`source` 按开集读;与租户面 `capabilities.readFace` 刻意不合流,只带一个纯比较函数,详见 §25)| 上行通道的**监管**半场(submit / steer / kill / 队列命令定序)+ 传输构造、caps 探测、SSE 断流分诊、**409 active-run 自愈** | `src/controlRouter.ts`、`steering.ts`、`sseIdleTriage.ts`、`retryStatus.ts`、`diagnostics.ts`、`engineWireSdk.ts`、`engineWireTarget.ts`、`src/principalWire.ts`、`src/wireErrorTriage.ts`、`engineSessionParam.ts`、`engineCapsCache.ts`、`liveInitToolFace.ts`、`adapter/activeRunSelfHeal.ts`、`src/sessionMemoryStatus.ts`、`src/writeProtectionCapability.ts`、`src/readFacePosture.ts` |
162
162
  | 16 | **引擎词汇表与包自检** | 59 | `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) · `GATE_PARKED_ERROR_CODE`(0.60.0:「门把这次调用 park 了」的机读码单源 —— `frameRouter` 的连坐/中断判据与 `gateOutcome.isGateParkedToolEnd` 读同一个常量;真机黑盒直证 park 短路帧上**没有 `gate`**,这个码是那一形唯一的信号,详见 §24c)| 三端分臂共用的**去字面化** `errorCode` 词表(病根正是三端各抄一份字面);编译期 verb 闭合门;搬迁补偿登记表 | `src/engineErrorCodes.ts`(计数以 `scripts/public-export-baseline.json` 为准,别手抄;A-028.11/.13 补 `DRAINING_ERROR_CODE`/`SCENARIO_NOT_ALLOWED_ERROR_CODE`/`RESUME_AT_ERROR_CODE_PREFIX`;#318 件④ 补 `delegation.*` 族四位 + `config.delegation_entry_caps`;0.39.0 补三新码消费件三位);S-81 补 `capability.self_orchestration_required` 一位;L-102 补 `resume.*` 时间性拒绝二码 + 闭集 `RESUME_RETRY_LATER_CODES` 三位)、`src/classifierVerdictWire.ts`、`src/compensations.ts`、`src/clientSlice.ts` |
@@ -3852,3 +3852,325 @@ readFaceDisagreement(capFace: unknown, posture: ReadFacePostureView | undefined)
3852
3852
  | `scripts/run-sdk-floor-test.mjs` | 地板 `8.5.0` 与 peer 声明**三位逐位等值**互绑 |
3853
3853
  | `scripts/run-public-surface-test.mjs` | peer 地板 / README 三处逐字核 + 公面导出基线 **861 → 864**(测试钩数未动) |
3854
3854
  | `scripts/run-integration-doc-freshness-test.mjs` | 本节新增坐标在盘 + 入库;§0a/§2/§2b 计数与基线等值 |
3855
+
3856
+ ---
3857
+
3858
+ ## §26 🆕 0.62.0 内容批七件(子代内容两件 · 座位子代两位 · 凭证取值时机 · Esc detach 格 · 终答补差 · 呈前封长收口)
3859
+
3860
+ ### 26a. 本节速览
3861
+
3862
+ | # | 件 | 面 | 破坏性 | 端要做什么 |
3863
+ |---|---|---|---|---|
3864
+ | ① | 子代内容分流补 durable 聚合形 | 行为**修复** | 无 | 什么都不用做(自动生效);web 端自守的同款分流**可以退役**,判据见 26b |
3865
+ | ② | 子代内容账本字节预算 | additive 三导出 + 一测试钩 | 无 | 可选:启动时配值;渲染端**建议**接新的 `truncated` 槽位 |
3866
+ | ③ | 座位 lane 子代两位 + 逐键出身表 | additive 两键 + 一导出 | 无 | 想要子代正文/子代续跑的端在 `sendMessage` 里带这两位 |
3867
+ | ④ | 出站凭证位放宽成「串或取值函数」 | additive 型放宽 | 无 | 可选:凭证会变的端把串换成取值函数,不必再重建 client |
3868
+ | ⑤ | Esc 停止判定层补 detach 那一格 | additive 入参键 | 无 | 武装了 detach 的端把 `detachArmed: true` 传进判定口 |
3869
+ | ⑥ | 终答与已上屏正文的补差 | 行为**修复** + additive chrome 臂 | 无 | 转录自动补齐;**建议**接 `result_text_diverged` 臂改口 |
3870
+ | ⑦ | 呈前封长顺序同形四处收口 | additive 一导出 + 行为收紧 | 无 | 端自己有同族铸点的,改接 `capForDisplay` |
3871
+
3872
+ 🔴 七件**全部 additive**:新导出、新可选入参键、新 chrome 臂、新配置口。老宿主一个字节不改照常跑,
3873
+ `peerDependencies` 未动(sdk 地板仍 `>=8.5.0`)。
3874
+
3875
+ ---
3876
+
3877
+ ### 26b. ① 子代内容分流补 durable 聚合形(行为修复)
3878
+
3879
+ **修的是哪一形**:带 `parentToolCallId` 的内容帧属于**子代**,库把它侧信道进子代转录账本、不进主转录
3880
+ (孩子的 token 渲成 leader 的正文是这条腿存在的理由)。而分流判据此前只列了四个**活体**臂
3881
+ (`text_delta` / `reasoning_delta` / `tool_start` / `tool_end`)—— **durable 腿(事件重放)送的是同一段的
3882
+ 聚合形**(`text` / `reasoning`,整段全文,同样带 `parentToolCallId`)。于是重放尾上的聚合帧漏过分流,
3883
+ 一路渲成 leader 自己的 assistant 正文。断线续听与交互续听重放尾都踩这一形。
3884
+
3885
+ **新的输入形**(`SubagentContentEvent`,additive):
3886
+
3887
+ ```ts
3888
+ type: 'text_delta' | 'reasoning_delta' | 'text' | 'reasoning' | 'tool_start' | 'tool_end'
3889
+ text?: string // 聚合两臂的整段全文(刻意不复用 delta 位)
3890
+ ```
3891
+
3892
+ **缺席语义**:`text` 位只在聚合两臂上有意义;缺席/空串 ⇒ 该帧不改变账本(不铸空段)。
3893
+
3894
+ 🔴 **两类语义不可合流**(端若自己也在做同款分流,这是最容易踩的一格):`*_delta` 的语义是**追加**,
3895
+ 聚合帧的语义是**这一段最终是这样**。把聚合帧折成一发增量 ⇒ 已经活体流过、又被重放一遍的段被数**两次**。
3896
+ 库的处置是**吸收**:全文以当前缓冲为前缀 ⇒ 换掉而不是追加(同一条聚合帧重复送达因此**幂等**);
3897
+ 前缀对不上 ⇒ 退回追加、两段都留下(少渲一段比替引擎判定「哪一段才算数」更坏)。段闭合仍由工具帧/收口给。
3898
+
3899
+ **durable 重放的两道幂等闸**(车内异源复审跟修;端若自己也在做同款分流,这两条一起才够):
3900
+ ①**事件身份** —— 聚合帧的 `eventId` 是精确的幂等键,**跨流也管用**(适配器内那道事件序号去重只在
3901
+ **同一条流**内有效,重连后是新的一条流);②**整段内容** —— 已段闭合上屏过的整段(兜底:上游没给身份,
3902
+ 或本进程这条流是重连后新起的)。另有第三形:被预算**裁过头部**的那一段,缓冲此时只剩尾巴,单看前缀
3903
+ 会判成新内容整只追加回来 ⇒ 判据是「全文以缓冲结尾 ⇒ 同一段、整帧丢弃」。
3904
+ 📋 **如实留白**:内容闸的代价是「一条 turn 里出现两段**逐字节相同**的正文时,durable 腿上只留一段」。
3905
+ 取舍明写:每次重连把整轮正文再渲一遍是**必然**发生的用户可见损坏,而同一条 turn 说两遍一模一样的话
3906
+ 是罕见形,且活体腿上两段都在。
3907
+
3908
+ **🔴 web 端退役判据(请逐条核过再退)**:web 端自守的同款分流可以退役,当且仅当
3909
+ ①它消费的是本包 `runStream` 的输出(而不是自己直读 wire);②它没有在分流之外**另外**依赖那些聚合帧
3910
+ (例如自己拿 `text` 帧做进度统计);③它没有对子代账本做第二次写入(两条腿喂同一个账本时,吸收规则
3911
+ 只在库这一侧成立)。三条有任何一条不成立,先在板上说一声再退。
3912
+
3913
+ ---
3914
+
3915
+ ### 26c. ② 子代内容账本字节预算(additive)
3916
+
3917
+ **修的是哪一形**:这本账本此前只有**条数**帽(每条子代 ≤ 200 条 item、≤ 32 条子代),而条数帽在
3918
+ **单条无上限**的前提下不是一个预算 —— 一条工具结果里的整个内联附件、一段几 MB 的模型输出,都能让一个
3919
+ 子代槽位吃到十几 MB 常驻。
3920
+
3921
+ **签名**:
3922
+
3923
+ ```ts
3924
+ interface SubagentContentStoreConfig { maxBytesPerTask: number; maxBytesTotal: number }
3925
+ const SUBAGENT_CONTENT_STORE_DEFAULTS: Readonly<SubagentContentStoreConfig> // 2 MiB / 16 MiB
3926
+ function configureSubagentContentStore(next: Partial<SubagentContentStoreConfig>): void
3927
+ function subagentContentStoreConfig(): SubagentContentStoreConfig // 快照
3928
+ ```
3929
+
3930
+ **单位**:**UTF-8 字节**(按串长度算会让一段 CJK 的真实占用是名义值的三倍)。
3931
+
3932
+ **缺省值的来历(如实)**:对标产品的语料里**没有**对应的「子代转录字节预算」可对齐(查过),这两个数
3933
+ **不假称是 parity** —— 总帽按实测观测到的量级取 16 MiB,每子代帽取总帽的 1/8 = 2 MiB。端按自己的宿主
3934
+ 改配即可;这两个数只保证「不配时不至于无界」。
3935
+
3936
+ **缺席语义**:不调配置口 ⇒ 缺省两位生效。只配一位 ⇒ 另一位保持**现值**(不被悄悄重置成缺省)。
3937
+
3938
+ 🔴 **配置面 fail-loud**:0 / 负数 / 非有限数 / 非整数一律 `throw TypeError`,且拒绝是**原子**的
3939
+ (任何一位不合法 ⇒ 整只拒,既有配置一个字节不动)。一个被静默忽略的预算配置正是这一位要消灭的形。
3940
+
3941
+ 🔴 **配置面第二条闸**:`maxBytesPerTask` **不许高过** `maxBytesTotal`(两位各自合法、合起来自相矛盾:
3942
+ 单条子代能合法地涨到每子代帽,而总帽淘汰**不动当期那条**,于是那一条整只越过了总帽)。判的是**落值
3943
+ 之后**的那一对 —— 只配一位时另一位保持现值,矛盾同样可能是这次配出来的。相等是合法的。
3944
+
3945
+ **越限处置 + 新槽位**:从**最早**的内容开始丢(活体尾巴最后才动),并在账本最前留**恰一条**记录:
3946
+
3947
+ ```ts
3948
+ { kind: 'truncated'; droppedBytes: number; keptFrom: number } // SubagentContentItem 新臂
3949
+ { kind: 'truncated'; slot: string; droppedBytes: number; keptFrom: number } // SubagentViewSlot 新臂
3950
+ ```
3951
+
3952
+ 总帽淘汰**整条最久未用**的子代账本(不做「每条各裁一点」——半截的转录比一条整齐的缺席更难读)。
3953
+
3954
+ 🔴 **渲染端义务**:`planSubagentViewSlots` 现在可能返回 `kind:'truncated'` 槽位。**不认它 = 屏上是一段
3955
+ 无声消失的输出**(用户读到的转录比真实发生的少一截而毫无提示)。渲一行可见的省略说明即可
3956
+ (措辞归端;库只给两个数)。老宿主的 `switch` 若是穷尽形,加一条 case;若已有 `default` 分支则不会崩,
3957
+ 但那一格仍然是**看不见**的。
3958
+
3959
+ **🔴 web 端配值口**:探针那条「单槽十几 MB」的路径,启动时调一次
3960
+ `configureSubagentContentStore({ maxBytesPerTask, maxBytesTotal })` 即可;不必自己在渲染端裁 ——
3961
+ 在渲染端裁只挡得住**上屏**那一份,账本本身还是那么大。
3962
+
3963
+ ---
3964
+
3965
+ ### 26d. ③ 座位 lane 子代两位 + 逐键出身表(additive)
3966
+
3967
+ **修的是哪一形**:两位此前是**结构性缺席** —— 座位载荷是一个闭集接口,不在集里 = 「这一轮要不要看
3968
+ 子代正文 / 要不要保留子代会话」这个决定在这条 lane 上**没有位置可放**(与 `reasoningEffort` 当年同一形)。
3969
+
3970
+ **`SendMessageRequest` 新增两位**(键名与引擎请求位**同名同形**,原样转投):
3971
+
3972
+ ```ts
3973
+ forwardSubagentEvents?: boolean
3974
+ retainSubagentSessions?: boolean | { ttlMs?: number; max?: number }
3975
+ ```
3976
+
3977
+ **缺席语义**:两位缺席 = 不开(父流只有进度帧、子代会话不保留),由引擎默认接管。
3978
+
3979
+ 🔴 **能力位读法(最容易踩的一条)**:`capabilities.forwardSubagentEvents` 说的是「**这个键被受理**」而
3980
+ **不是**「转发已经开着」—— 它是一个恒真的受理位。把它读成后者的消费方会接出一个**永远空着**的子代
3981
+ 转录面,而能力面一直在回答「是」。⇒ 想要子代正文,**每一轮都得自己带这个键**。
3982
+
3983
+ 🔴 **clamp 是收紧不是拒绝**:保留窗口 `ttlMs` 与条数 `max` 过大时,引擎会**悄悄收紧**(窗口上限 24 小时、
3984
+ 条数上限 64),而不是报错。⇒ 渲染端**不许**把自己请求的值当成生效值回显 —— 那是替引擎说了一句它没说
3985
+ 的话;要显示生效值就去读引擎那一面,读不到就诚实留白。
3986
+
3987
+ 🔴 **`retainSubagentSessions` 是「子代续跑」那条路的另一半**:续跑能力位可以是真、路由可以在,调用照样
3988
+ 会被拒 —— 因为保留是**逐 run** 的、且默认关。只看能力位就渲一个「继续这个子代」的入口 = 假 affordance。
3989
+
3990
+ **同批新增导出** `SEAT_SEND_MESSAGE_KEY_ORIGINS`:座位载荷的**逐键出身**登记 —— 每个位要么写明转投哪个
3991
+ 引擎请求位(含 `text → objective` 这种**异名**转投),要么写明为什么不上 wire(`sessionId` 是**同名不同义**
3992
+ 的典型:座位那一位是本地会话句柄,引擎会话 id 由座位记录的 `engineSessionId` 承载)。端可以拿它做
3993
+ 「我这条 lane 上的这个位到底会不会到引擎」的机读对照,不必再读实现。
3994
+
3995
+ ---
3996
+
3997
+ ### 26e. ④ 出站凭证位放宽成「串或取值函数」(additive 型放宽)
3998
+
3999
+ **修的是哪一形**:凭证串是在**构造那一刻**被读走的(底层客户端把它捕获进闭包,此后每一发请求都用那
4000
+ 一份)。引擎被别的会话换代、凭证换新之后,一个长命的 client 会一直拿**旧凭证**发请求,而端唯一的出路是
4001
+ 把整个 client 连同它身上的状态重建一遍。
4002
+
4003
+ **签名**:
4004
+
4005
+ ```ts
4006
+ type WireAuthTokenSource = string | (() => string | undefined)
4007
+ // 放宽的三处(都汇到同一个构造口):
4008
+ EngineWireClientConfig.token?: WireAuthTokenSource | { mode: 'same-origin-relay' }
4009
+ EngineProbeOpts.authToken?: WireAuthTokenSource | undefined
4010
+ WireConfig.authToken?: WireAuthTokenSource // prepare 腿
4011
+ ```
4012
+
4013
+ **取值时机**:取值函数**每发一次请求读一次**;构造期**一次都不读**(构造时读一次只是把快照挪了个位置)。
4014
+
4015
+ **缺席语义**:取值函数返回 `undefined` / 空串 / **抛错**,一律按「这一刻没有凭证」走既有三态 ——
4016
+ 回环地址出**零** Authorization 头(绝不伪造),非回环出 fail-closed 的匿名身份(换一个诚实的 401)。
4017
+ 取值口抛错是 **fail-soft**:请求照发,异常不上抛(一个坏掉的取值口不该让整条 wire 不可用,而且异常里
4018
+ 可能夹带凭证材料)。
4019
+
4020
+ **串形逐字节零行为差**;同源中继声明形(`{mode:'same-origin-relay'}`)不进取值路径(它结构上就没有 token)。
4021
+
4022
+ 📋 **如实留白(同族存量两处刻意不放宽)**:①workflow 活动台账的连线身份**按凭证值比相等**来判「还是不是
4023
+ 同一条连线」,而函数没有值身份 —— 宿主每次渲染新建一个箭头函数会让台账每拍重开一条流;要放宽先给那条
4024
+ lane 一个连线身份口径。②信号路径的 cancel 兜底是**在武装那一刻快照**的,它由信号处理器同步读取,那里
4025
+ 不该调用任意宿主代码。两处都不是遗漏。
4026
+
4027
+ ---
4028
+
4029
+ ### 26f. ⑤ Esc 停止判定层补 detach 那一格(additive 入参键)
4030
+
4031
+ **修的是哪一形**:撕 SSE 的**后果**因 detach 而变。未武装 detach 的车道上,撕流 = 服务端按断连语义当场
4032
+ 收尾那条 run,所以「interrupt 那一发没落地」还有一层兜底;detach 武装之后,撕流只断开**观看**,run 会
4033
+ 一路跑到 turn 结束 —— 此时 interrupt 自身失败(传输失败/超时/未武装)= 用户按下的 Esc **一点效果都没有**,
4034
+ 而屏上没有任何东西会告诉他。
4035
+
4036
+ **签名**(`InteractiveHaltInput` 新增一位):
4037
+
4038
+ ```ts
4039
+ readonly detachArmed?: boolean | undefined
4040
+ ```
4041
+
4042
+ **新的判决词**:`InteractiveHaltReason` 加一员 `'no-verdict-detach-armed'`(闭集,机读)。
4043
+
4044
+ **分支表(七格 → 八格)**:
4045
+
4046
+ | `interruptOutcome` | `parked` | `detachArmed` | 判决 | reason |
4047
+ |---|---|---|---|---|
4048
+ | 缺席(还没打) | 任意 | 任意 | `interrupt` | `first-shot` |
4049
+ | `halted` | 任意 | 任意 | `none` | `halted` |
4050
+ | `refused` + 409 + 升级闭集码 | 任意 | 任意 | `escalate-cancel` | `engine-says-run-level` |
4051
+ | `refused`(其余) | 任意 | 任意 | `none` | `refused-no-escalation` |
4052
+ | `transport` / `unarmed` | `true` | 任意 | `escalate-cancel` | `no-verdict-on-parked-card` |
4053
+ | `transport` / `unarmed` | 其余 | `true` | `escalate-cancel` | `no-verdict-detach-armed` |
4054
+ | `transport` / `unarmed` | 其余 | 其余 | `none` | `no-verdict-not-parked` |
4055
+ | 认不得的形 | 任意 | 任意 | `none` | `unknown-outcome` |
4056
+
4057
+ **缺席语义**:缺席 / 非 `true` 一律按未武装处理(fail-closed,与 `parked` 同尺)。
4058
+ 🔴 **缺席 = 老语义零差**,而且是**证明**出来的:门里带一份上一版判定的参照实现,把全表跑两遍要求零差异。
4059
+ 🔴 `parked` **先判**,所以老宿主(只传 `parked`)的 reason 逐字不变;两者同真时仍报 `no-verdict-on-parked-card`。
4060
+ 🔴 新键**只在「没有判决」那一格**被读:引擎给了判决时判决说了算。
4061
+
4062
+ ---
4063
+
4064
+ ### 26g. ⑥ 终答与已上屏正文的补差(行为修复 + additive chrome 臂)
4065
+
4066
+ **修的是哪一形**:一个 turn 的正文正常是流着上屏的,终帧带的那份是同一段话的全文。断线前已经流过一
4067
+ 部分、重连后终帧带**完整**那份时,「这一轮已经产过 assistant 文本」为真 ⇒ 整条终答兜底被跳过,屏上永远
4068
+ 缺断线期间那一截,而且没有任何东西说少了。
4069
+
4070
+ **四格**(修前只有第一格):
4071
+
4072
+ | 已上屏 vs 终帧 `result` | 处置 |
4073
+ |---|---|
4074
+ | 一个字都还没上屏 | 终帧那份**整段渲**(修前的唯一行为,逐字保留) |
4075
+ | 已上屏是终帧的**前缀** | **只补吐后缀**那一截(相等时零发);上屏总字节 = 终帧那份 |
4076
+ | 终帧是已上屏的**前缀**(引擎侧修剪) | **不动**(屏上不缺任何东西;拿更短的覆盖更长的会抹掉用户已读到的) |
4077
+ | 两份**互相都不是对方前缀** | **零补吐** + 发一个 `result_text_diverged` 事实位 |
4078
+
4079
+ 🔴 **比较的两边必须是同一种东西**(车内异源复审逼出的定谳,端自己做同款补差时必读):终帧那一位在
4080
+ 引擎侧取的是**最后一条** assistant 消息的文本、且出厂 `.trim()` 过 —— **不是**整轮正文的拼接。拿
4081
+ 「本轮全部正文」去比,一个「散文 → 工具 → 散文」的**正常多步回答**会被判成分岔,只差首尾空白的回答
4082
+ 同理。⇒ 左边必须是**当前这条 assistant 消息**已上屏的正文(工具边界重置),相等判定先过一次 `trim()`。
4083
+
4084
+ **新 chrome 臂**:
4085
+
4086
+ ```ts
4087
+ { kind: 'result_text_diverged'; laneProof: LaneProof; committedLength: number; resultLength: number }
4088
+ ```
4089
+
4090
+ 🔴 **宿主消费义务**(可选、fail-soft):把这一拍的转录行**改口** —— 一句诚实的「这一轮的最终答复与上面
4091
+ 流式显示的内容不一致」。**不是补渲一段**:两份对不上时谁才算数只有引擎说得清,把终帧那份接在屏上那段
4092
+ 后面会拼出一段**谁都没说过**的话。不接本臂 = 用户看不到这条披露(不是报错),但**绝不许**把它渲成
4093
+ 「已完成」的正面确认。两个位是**长度**不是内容(库刻意不复述任何一份正文 —— 复述一遍等于给渲染端第三个
4094
+ 版本去挑)。
4095
+
4096
+ ---
4097
+
4098
+ ### 26h. ⑦ 呈前封长顺序同形四处收口(additive 一导出 + 行为收紧)
4099
+
4100
+ **修的是哪一形**:消毒器把每个不可见字符改写成 6 字符的可见转义,而「先按原文截长、后转义」会让承诺的
4101
+ 显示预算**膨胀六倍**(40 字符的纯控制字符原文在屏上占 240 个显示字符)。四处铸点里 READ 档位读器已是
4102
+ 对的,另外三处是反的(写保护姿态行的 `source`、它逐行的 `name`/`kind`、SQL 姿态行的三座)。
4103
+
4104
+ **签名**(共用铸点提到与消毒器同居的底座并**导出**):
4105
+
4106
+ ```ts
4107
+ function capForDisplay(raw: string, max: number): string
4108
+ ```
4109
+
4110
+ 语义:返回值恒是**已消毒**的串,长度 ≤ `max`(可能因避让短于 `max`);`max <= 0` ⇒ 空串。
4111
+ 截点避开两种断裂片段:一枚 `\uXXXX` token 的中间(留半截比整枚不渲更坏 —— 它看起来像一个完整答案的
4112
+ 开头)、一对合法代理对的中间(截断等于人为造一枚裸高位代理项)。
4113
+
4114
+ **行为面**:对**正常读数**(不含控制字符的引擎/数据库回值)四处**逐字节零变化**;只有含控制符的病态值
4115
+ 渲染形收紧。端自己有同族铸点的(先截后转义那一形),改接这一只。
4116
+
4117
+ ---
4118
+
4119
+ ### 26i. 🔴 壳与 web 端换装清单(逐件坐标)
4120
+
4121
+ | 件 | 壳(cli) | web 端 |
4122
+ |---|---|---|
4123
+ | ① | 无(自动生效);续听 durable 尾的两条路径重跑一次冒烟即可 | **可退役**自守分流(退役判据见 26b 三条) |
4124
+ | ② | 启动装配处调一次 `configureSubagentContentStore`(按 TUI 宿主的内存预算);子代查看态渲染加 `truncated` 槽位一行 | 同左;**配值口就是这一个函数**,不要在渲染端裁 |
4125
+ | ③ | 座位 lane 不是壳的主路;壳走的是请求装配口,两位已在引擎请求形上 | `sendMessage` 带 `forwardSubagentEvents: true` 才有子代正文;要子代续跑再带 `retainSubagentSessions`;**不许回显自己请求的 ttl/max** |
4126
+ | ④ | 引擎换代后的凭证换新可以从「重建 client」改成「换值」——把构造口的 `token` 改成取值函数 | 同左(同源中继形的端不受影响) |
4127
+ | ⑤ | Esc 弧调 `planInteractiveHalt` 处补传 `detachArmed`(壳自己知道这条 run 有没有武装 detach) | 同左 |
4128
+ | ⑥ | 转录自动补齐;建议接 `result_text_diverged` 臂改口 | 同左 |
4129
+ | ⑦ | 壳侧同族铸点若是先截后转义,改接 `capForDisplay` | 同左 |
4130
+
4131
+ ---
4132
+
4133
+ ### 26j. 黑盒判据(test 视角;不引用内部实现)
4134
+
4135
+ - **G-1**:开着子代正文转发跑一轮委派,中途断流、按 durable 腿续听 —— 子代说的话**不出现**在 leader 的
4136
+ 转录里,而在子代查看态里**完整**出现一次(不是两次)。
4137
+ - **G-2**:同一轮里让子代先流一段、再重放该段的聚合形 —— 子代查看态里那一段的字节数**等于**该段全文
4138
+ (不是两倍)。
4139
+ - **G-3**:leader 自己的 durable 正文(不带子代归属)照旧出现在主转录里(分流射程没有扩大)。
4140
+ - **G-4**:让一个子代产出远超每子代帽的输出 —— 查看态**仍能读到最近那一段**,且屏上**有一行**说明更早的
4141
+ 输出被丢弃了(有数);账本占用不再随输出线性增长。
4142
+ - **G-5**:给预算配一个 0 或负数 —— **响亮失败**(不是静默按缺省跑)。
4143
+ - **G-6**:座位 lane 不带 `forwardSubagentEvents` 时子代转录面为空;带上之后同一操作有内容 ——
4144
+ 且**能力面在这两次里回答相同**(证明能力位不是开关)。
4145
+ - **G-7**:请求一个超过上限的子代保留窗口 —— 调用**不报错**,而端上显示的生效值**不是**请求值
4146
+ (或诚实留白),两者不许一致。
4147
+ - **G-8**:引擎凭证在两次请求之间换代 —— **同一个** client 的下一发请求带的是新凭证(不必重建);
4148
+ 凭证在任何日志/URL 面上零出现。
4149
+ - **G-9**:武装 detach 的会话里,让 interrupt 那一发打不出去(断网/超时)后按 Esc —— run **真的停了**
4150
+ (不是跑到 turn 结束);未武装 detach 且无审批卡的同款场景**不升级**(行为与上一版逐格相同)。
4151
+ - **G-10**:断线前流过半段答复、重连后终帧带完整答复 —— 屏上最终看到的正文**逐字节等于**终帧那份
4152
+ (不缺尾、也没有重复的前半段)。
4153
+ - **G-11**:构造一个终帧与流式内容**从中途分岔**的场景 —— 屏上**不出现**拼接出来的第三种正文,且转录行
4154
+ **改口**(不是一句「已完成」)。
4155
+ - **G-12**:让引擎/数据库回一个含控制字符的姿态值 —— 诊断行的显示长度**不超过**同长度良性值那一行,
4156
+ 且行尾没有半截转义序列。
4157
+ - **G-13**:一条**正常的多步回答**(散文 → 工具 → 散文)—— 转录里**不出现**任何「最终答复与显示的
4158
+ 不一致」类披露(拿整轮拼接去比会在这里假报)。
4159
+ - **G-14**:活体跑完一整轮(两段散文 + 中间一张工具卡)之后**断线重连**、按 durable 腿整轮重放 ——
4160
+ 子代查看态里每段只出现一次,且顺序与活体时相同。🔴 重连是**新的一条流**,所以这一格必须真的断开
4161
+ 重连来做:在同一条流里重放测不到它。
4162
+ - **G-15**:把每子代帽配得比总帽还大 —— **响亮失败**(一个单条子代能整只越过的总帽不是预算)。
4163
+
4164
+ ### 26k. 常驻门
4165
+
4166
+ | 门 | 守什么 |
4167
+ |---|---|
4168
+ | 🆕 `scripts/run-subagent-durable-divert-test.mjs` | ① 聚合形分流:正控/负控/不双份三格/段边界/增量恒追加/**跨工具边界重放两道闸**(事件身份 + 整段内容) |
4169
+ | 🆕 `scripts/run-subagent-content-budget-test.mjs` | ② 字节预算:每子代帽/总帽/截尾留痕(含进渲染计划)/缺省值可触到/配置面 fail-loud 八形/未越限零行为差/**拼接边界代理对不虚账**/**每子代帽 ≤ 总帽**/**被裁过的段重放不重算统计** |
4170
+ | 🆕 `scripts/run-seat-task-request-origin-test.mjs` | ③ 座位载荷逐键出身对 sdk 型**直读**对账 + 子代两位回归钉 + 保留窗口内层两键 |
4171
+ | 🆕 `scripts/run-wire-auth-source-test.mjs` | ④ 取值时机:构造期零读 / 读取次数 = 请求次数 / 改值即生效 / 三态逐格 / 凭证只在 Authorization 头 / 抛错 fail-soft |
4172
+ | 🆕 `scripts/run-result-text-backfill-test.mjs` | ⑥ 补差四格 + 事实位形 + 跨工具边界格 + **正常多步回答零分岔** + **首尾空白零分岔**(真链路驱动,终帧按引擎真形造) |
4173
+ | 🆕 `scripts/run-display-cap-order-test.mjs` | ⑦ 封长顺序四铸点 + 共用铸点两条避让 + 反向参照 |
4174
+ | `scripts/run-esc-halt-plan-test.mjs` | ⑤ 新增 G6/G6b 两段(detach 格 + 缺席零差全格穷举) |
4175
+ | `scripts/run-public-surface-test.mjs` | 公面导出基线 **864 → 869**(测试钩 43 → 44) |
4176
+ | `scripts/run-integration-doc-freshness-test.mjs` | 本节新增坐标在盘 + 入库;§0a/§2/§2b 计数与基线等值 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/client-core",
3
- "version": "0.61.0",
3
+ "version": "0.62.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",