chainlesschain 0.166.102 → 0.166.104

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.
Files changed (213) hide show
  1. package/package.json +1 -1
  2. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  3. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-CyHIMEd8.js → AIOps-Bah3HREy.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-vuNxDpHm.js → ActionButton-DY2aeZMc.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-D0quEM0q.js → Analytics-BFly8Xaa.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-xRSVpbCs.js → AppLayout-dp0Zz-JM.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-ktfVAZBC.js → Artifacts-DcIg09ai.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-UJW6maH4.js → Audit-DkN-lsjZ.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BYrfdCoT.js → BackgroundAgents-BjzgusLx.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-IBgsJ7BK.js → Backup-CU8S6qu9.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-BmP8_zxy.js → BaseInput-B1pC2gjL.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-urkw8_BF.js → Chat-B6xFp6gD.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Cw44zZbh.js → ChatBubbleRenderer-DxNCLZ_X.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-CYboo-__.js → Checkbox-QHw7Vc4U.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-DaqR_Ay8.js → Codegen-gdecsfjg.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-04BSIj_z.js → Col-B0_JmAmc.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DxFk7Trv.js → Community-DRCcP5xR.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-mjgWlMCB.js → Compact-DZtoGzhX.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CC5ee7QV.js → Compliance-BfNTvEnT.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-BK4BhHZd.js → Cowork-CDXTLm84.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-CP6jAxq0.js → Cron-Big35CbN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-DJPaViZS.js → Crosschain-C8ArrAVr.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-BTLxkuOj.js → DID-D_77BI2O.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-Djkiqh3d.js → Dashboard-D2SxTzEp.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-t_eUhqom.js → Dropdown-mR1-b9ud.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-7w6USx_J.js → EmailListRenderer-DPl7TE1c.js} +1 -1
  28. package/src/assets/web-panel/assets/{EvolutionSettings-mU5IHEk5.js → EvolutionSettings-BxRYLRSH.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BCh-VBBC.js → FamilyGuardDashboard-rnGtXJ5Z.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-Be_VpjI2.js → Federation-BpxenYK8.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-D_lzQ7PI.js → FormItemContext-Cz1kDf6l.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-LYu3KapV.js → GenericCardRenderer-CGV3KN6U.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-BBeF-PP4.js → Git-CIRP4UTx.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-CoF8Kzg7.js → Governance-DX4r8Vmt.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-C4DLMnXS.js → Inference-DQKk02Hl.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-B2mlNewk.js → KnowledgeGraph-DdD6J-By.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-DMZ_44Ya.js → Logs-DA2w-1_m.js} +2 -2
  38. package/src/assets/web-panel/assets/{MarkdownRenderer-Ck7Iv_9e.js → MarkdownRenderer-C9aSGETh.js} +1 -1
  39. package/src/assets/web-panel/assets/{Marketplace-BqDzTew_.js → Marketplace-BsJ6_6KW.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-BbwSbDN9.js → McpTools-_6k30z6u.js} +2 -2
  41. package/src/assets/web-panel/assets/{Memory-DAaTWgrm.js → Memory-C0_dYY0A.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-BjbTGxoR.js → MobileBridge-CCTnVqiC.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-DMODOBr-.js → MobileProjects-RZdxDSwC.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-DT9N2rCs.js → Mtc-D4Ys8lvX.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-DagMfUVv.js → MtcAudit-BKTC--a2.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-C1BKP6nM.js → Multisig-CGR1qOe1.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-B5LFh72i.js → NLProgramming-hKKD4qWb.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-Q77V3ltW.js → Notes-pCn7Ec40.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-HxdpNIBs.js → NotificationSettings-B9eEJXEs.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-Dc0DpvBH.js → OrderTableRenderer-CmJuhaT2.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-QL3NZ7uW.js → Organization-CcQbrnwW.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-B_gqOKho.js → Overflow-HmD4Mn72.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BBJubU8Z.js → P2P-B7LIgx5H.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-CFnGd-2E.js → PdhVaultBrowser-CXiHnBfX.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-BKkznIUM.js → Permissions-CQRI3y_l.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-DYK7ZAcd.js → PersonalDataHub-1EeHmsy5.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-CoeKpjoN.js → Pipeline-BFyoIdn8.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-Diw4G-92.js → Privacy-BxWthXMF.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-CHBOFkma.js → ProjectInit-DfigBilu.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-BJIsgdOf.js → ProjectSettings-CFmIcVc-.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-CR7H59v3.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-o8QCimor.js → Providers-2ulom-76.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-z2W-zvhW.js → QrScannerModal-BwhO07b_.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-_yubhsna.js → QuickAsk-_Wg34OwF.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CucgJwih.js → Recommend-D_jq6Svg.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-EzfIIRg1.js → RemoteSession-BlzvEfsa.js} +2 -2
  67. package/src/assets/web-panel/assets/{Reputation-_shttE67.js → Reputation-9CTXHfL4.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-DQA_S8-9.js → Row-DlCYCN-t.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-BOqWawXT.js → RssFeed-BvlInFCH.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-Dx1v2xOq.js → Search-CfaUzKuL.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-Bt4HHsT4.js → Security-bAWgLyve.js} +4 -4
  72. package/src/assets/web-panel/assets/{Services-sruHiQ-r.js → Services-C4LOGACW.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-CiBxvmOJ.js → Skeleton-Dd0Uwh3_.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-De9qKODU.js → Skills-ZYF1kYCU.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-B_6yn8Wp.js → Sla-DpsmIaEo.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-C2CafExS.js → SpeechSettings-BBXoJ4yc.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-Dhh3Qmb0.js → SyncSettings-SOnROi2Y.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-Mvo5mTWm.js → Tasks-HFA_ZlDk.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-D7WVTQQy.js → Templates-fsK-RCEc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-7ur9Yfxd.js → Tenant-CuqYxamb.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-BgzrOA6k.js → Terminal-GKlI2R5F.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-Dco20pT1.js → TimelineRenderer-DMDMHLeY.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-hN6qBPag.js → Tokens-BoV60rh3.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-C4f_twAM.js → Trigger-CE344-Ws.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-Wf1SMypp.js → Trust-DENwgkVc.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-DUXSyg3N.js → UkeySign-FrcM7yfm.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-BvqsJaL0.js → VideoEditing-DAY9WaC2.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-CgAbcjKl.js → Wallet-BuUR5i82.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-DaLT0W3s.js → WebAuthn-nfSQuq85.js} +2 -2
  90. package/src/assets/web-panel/assets/{WorkflowEditor-CQqAXoaS.js → WorkflowEditor-DHhPOp9l.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-BhlohFTB.js → chat-C4nsLzYy.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-D7HqXIL8.js → colors-BwXH0Wjn.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-Bqk4FCLY.js → compact-item-uApFG30S.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-CEmWrWf0.js → createContext-BpyYs4fe.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-Bk6HGn3N.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-CDY0pFi2.js → hasIn-MXCLi00p.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-e9oCy7_4.js → index-1LxX2IwJ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DEzL7s7P.js → index-61CBBrHE.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D0nfNmbq.js → index-B0P1Z_oa.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BiLu-ImR.js → index-B7jojVc7.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CqK0J4Sj.js → index-BEGMfaOo.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-aBHlgMrq.js → index-BOhjapd5.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DPBoWNwq.js → index-BaBwXpAp.js} +1 -1
  104. package/src/assets/web-panel/assets/index-Bb1LPYdi.js +1 -0
  105. package/src/assets/web-panel/assets/{index-BxXFRLTZ.js → index-Btv--Nnt.js} +1 -1
  106. package/src/assets/web-panel/assets/index-C-FsTuFG.js +1 -0
  107. package/src/assets/web-panel/assets/{index-BxYO6nde.js → index-CF0bUOP4.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DGKRAO61.js → index-CNjUPfJP.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CkjgSHVz.js → index-CRmNdEk_.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CrsM-oiD.js → index-C_oOpXhP.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BNrvBWDS.js → index-ChUTKrOq.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CYcjOnDX.js → index-CiIpIYhs.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C02yDu4f.js → index-CwVvk2i7.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DmKdCWq1.js → index-D3_tj06B.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CkqBoCiu.js → index-DE4W4vLO.js} +3 -3
  116. package/src/assets/web-panel/assets/{index-B8L3_-sG.js → index-DLxKx5_J.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Dwob5XoD.js → index-DTXi_gQh.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DuMt3ewl.js → index-Daco83me.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DpI1LqJX.js → index-DffWVpZv.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-lBAbMOzg.js → index-Dkncxel3.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DRcDWMwP.js → index-Dn12gJJU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CVrwozwH.js → index-Dt-nq2eF.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-C3opQg47.js → index-Du01X9N9.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-o_lc3eww.js → index-DucLR6YX.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Cur88hoN.js → index-Gz2rGWef.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-XErJQ1yF.js → index-IvgszJ3C.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BuKGuH_y.js → index-S80LLjdx.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Chxt0t-A.js → index-WKbnwbKa.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-1HBam9t1.js → index-XHBXtvqp.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BXRooi-O.js → index-nn22NSDK.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BHGOdvOQ.js → index-pCIAE2yS.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Cf1ha8l0.js → index-pRpMLhMt.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-6f6n0KFR.js → index-pgHGBAoF.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BPmRkxeX.js → index-ugIUt5TL.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-C9mvnSii.js → index-xLGf7f9K.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-CIeEUxIN.js → initDefaultProps-C58CkKEo.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-IPIj1ZtP.js → motion-BLWPO2NV.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-BfSeXZ-f.js → move-BgrFMwYp.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-DX03-Xp4.js → mtc-parser-Cq2AuGzl.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-z9EannfX.js → omit-Bb-9L7if.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-DXKmRkqZ.js → pickAttrs-vLmOxYr1.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-k2HV7cIU.js → placementArrow-BNySU_dJ.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-bX7CsyWy.js → responsiveObserve-xnbwagnm.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-NskjQLbJ.js → slide-BccbY5Cn.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-B3IoG-Er.js → statusUtils-DOp9d2-w.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-DHv_UilX.js → styleChecker-Bu1w6ho9.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-DEqGB5Ng.js → useFlexGapSupport-ZsUOrVdL.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-Bl9CbrqZ.js → useFs-C0zpzKtO.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-O-Ukv93M.js → usePersonalDataHub-DO1OdgXK.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-hGCHTaZt.js → vnode-jTIRyhR5.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-BWhIVeKQ.js → zoom-DKvS7-Qs.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/commands/agent.js +56 -20
  154. package/src/commands/ask.js +6 -4
  155. package/src/commands/batch.js +17 -12
  156. package/src/commands/eval.js +24 -8
  157. package/src/commands/team.js +28 -19
  158. package/src/data/changelog.json +26 -0
  159. package/src/harness/mcp-client.js +187 -26
  160. package/src/harness/prompt-compressor.js +2 -0
  161. package/src/lib/advisor-runtime.js +4 -2
  162. package/src/lib/agent-ipc-bus.js +2 -0
  163. package/src/lib/background-agent-keeper-client.js +3 -0
  164. package/src/lib/background-session-transport.js +21 -5
  165. package/src/lib/browser-automation.js +4 -0
  166. package/src/lib/cc-android-bridge.js +4 -0
  167. package/src/lib/chat-core.js +11 -9
  168. package/src/lib/cloud/cloud-client.js +10 -1
  169. package/src/lib/cowork-adapter.js +4 -3
  170. package/src/lib/decision-layer/providers.js +16 -11
  171. package/src/lib/decision-layer/runtime.js +180 -10
  172. package/src/lib/direct-model-usage.js +34 -0
  173. package/src/lib/evolution/agent-evolution-ingress.js +63 -7
  174. package/src/lib/evolution/evolution-evidence-artifact-adapter.js +10 -0
  175. package/src/lib/evolution/evolution-evidence-projector.js +46 -7
  176. package/src/lib/evolution/governed-hub-llm.js +31 -16
  177. package/src/lib/evolution/governed-hub-resolver.js +4 -0
  178. package/src/lib/evolution/governed-skill-synthesis-process-grader.js +4 -0
  179. package/src/lib/evolution/skill-decision-projection.js +211 -0
  180. package/src/lib/evolution/skill-retrieval-revocation-authority.js +17 -2
  181. package/src/lib/evomap-client.js +14 -2
  182. package/src/lib/formal-budget-authority.js +191 -59
  183. package/src/lib/formal-budget-contract.js +7 -13
  184. package/src/lib/formal-budget-errors.js +31 -0
  185. package/src/lib/formal-budget-lineage-registry.js +612 -0
  186. package/src/lib/formal-budget-provider-scope.js +143 -0
  187. package/src/lib/formal-budget-transport.js +235 -100
  188. package/src/lib/gateway-client-resilience.js +5 -0
  189. package/src/lib/hub-llm-client.js +25 -16
  190. package/src/lib/llm-connection-probe.js +17 -10
  191. package/src/lib/llm-providers.js +4 -1
  192. package/src/lib/model-failure-policy.js +2 -0
  193. package/src/lib/plugin-runtime/marketplace-network.js +9 -5
  194. package/src/lib/process-execution-broker/credential-agent.js +7 -2
  195. package/src/lib/process-execution-broker/credential-transport.js +4 -0
  196. package/src/lib/process-execution-broker/index.js +8 -0
  197. package/src/lib/provider-stream.js +28 -13
  198. package/src/lib/sandbox-egress-worker.js +3 -0
  199. package/src/lib/skill-loader.js +16 -0
  200. package/src/lib/stream-retry.js +2 -0
  201. package/src/lib/sub-agent-context.js +6 -3
  202. package/src/lib/web-fetch.js +2 -0
  203. package/src/lib/web-search.js +5 -0
  204. package/src/repl/agent-repl.js +86 -7
  205. package/src/runtime/agent-core.js +141 -22
  206. package/src/runtime/headless-runner.js +212 -22
  207. package/src/runtime/headless-stream.js +189 -25
  208. package/src/runtime/mcp-config.js +26 -17
  209. package/src/runtime/mcp-tool-search.js +44 -14
  210. package/src/assets/web-panel/assets/Projects-GJjItXIk.js +0 -1
  211. package/src/assets/web-panel/assets/devWarning-YPX_TU7w.js +0 -1
  212. package/src/assets/web-panel/assets/index-D53szVZQ.js +0 -1
  213. package/src/assets/web-panel/assets/index-Ub2nJbV2.js +0 -1
@@ -5,6 +5,7 @@ import evolutionRun from "@chainlesschain/session-core/evolution-run";
5
5
  import { EvolutionEvidenceArtifactAdapter } from "./evolution-evidence-artifact-adapter.js";
6
6
  import {
7
7
  EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST,
8
+ EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST,
8
9
  EVOLUTION_PROJECTION_RULESET_DIGEST,
9
10
  } from "./evolution-evidence-projector.js";
10
11
  import { EvolutionRunLedgerAdapter } from "./evolution-run-ledger-adapter.js";
@@ -15,6 +16,10 @@ import {
15
16
  snapshotAgentModelRequest,
16
17
  buildAgentModelRequest,
17
18
  } from "./agent-model-projection.js";
19
+ import {
20
+ snapshotSkillDecisionRequest,
21
+ buildSkillDecisionPayload,
22
+ } from "./skill-decision-projection.js";
18
23
 
19
24
  const { EVOLUTION_RUN_EVENT_SCHEMA, EVENT_TYPES } = evolutionRun;
20
25
 
@@ -265,6 +270,7 @@ export function createAgentEvolutionIngress({
265
270
  options = {},
266
271
  modelRequest = null,
267
272
  cacheRecord = false,
273
+ skillDecisionRequest = null,
268
274
  ) =>
269
275
  guardIngress(
270
276
  serialize(async () => {
@@ -304,7 +310,7 @@ export function createAgentEvolutionIngress({
304
310
  ),
305
311
  responseEvent: clone(lastModelResponse.event),
306
312
  }
307
- : (modelRequest ?? clone(evidence));
313
+ : (skillDecisionRequest?.payload ?? modelRequest ?? clone(evidence));
308
314
  const sourceEnvelope = await issueSourceEnvelope(
309
315
  Object.freeze({
310
316
  schema: AGENT_EVOLUTION_INGRESS_SCHEMA,
@@ -321,12 +327,17 @@ export function createAgentEvolutionIngress({
321
327
  payload,
322
328
  };
323
329
  const persisted =
324
- modelRequest === null
325
- ? await evidenceAdapter.projectAndPersist(projectionInput)
326
- : await EvolutionEvidenceArtifactAdapter.prototype.projectAndPersistAgentModelRequest.call(
330
+ skillDecisionRequest !== null
331
+ ? await EvolutionEvidenceArtifactAdapter.prototype.projectAndPersistSkillDecisionRequest.call(
327
332
  evidenceAdapter,
328
333
  projectionInput,
329
- );
334
+ )
335
+ : modelRequest === null
336
+ ? await evidenceAdapter.projectAndPersist(projectionInput)
337
+ : await EvolutionEvidenceArtifactAdapter.prototype.projectAndPersistAgentModelRequest.call(
338
+ evidenceAdapter,
339
+ projectionInput,
340
+ );
330
341
  if (
331
342
  persisted?.tenantId !== descriptor.tenantId ||
332
343
  persisted.evidenceId == null ||
@@ -353,6 +364,13 @@ export function createAgentEvolutionIngress({
353
364
  evidenceKind: kind,
354
365
  occurredAt,
355
366
  derivationManifestDigest: persisted.manifest.digest,
367
+ ...(skillDecisionRequest === null
368
+ ? {}
369
+ : {
370
+ decisionId: skillDecisionRequest.decisionId,
371
+ requestDigest: skillDecisionRequest.requestDigest,
372
+ candidateSetDigest: skillDecisionRequest.candidateSetDigest,
373
+ }),
356
374
  },
357
375
  });
358
376
  if (kind === "model-input") {
@@ -370,7 +388,8 @@ export function createAgentEvolutionIngress({
370
388
  eventId,
371
389
  artifact: persisted,
372
390
  });
373
- if (modelRequest === null) return appended;
391
+ if (modelRequest === null && skillDecisionRequest === null)
392
+ return appended;
374
393
  // Resolve the published manifest and every attested component afresh.
375
394
  // The prototype call requires the real adapter's private state; an
376
395
  // instance-shaped facade cannot mint model-visible input.
@@ -383,7 +402,9 @@ export function createAgentEvolutionIngress({
383
402
  resolved.verification.verified !== true ||
384
403
  resolved.verification.tenantId !== descriptor.tenantId ||
385
404
  resolved.bundle.modelProjection.rulesetDigest !==
386
- EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST ||
405
+ (skillDecisionRequest === null
406
+ ? EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST
407
+ : EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST) ||
387
408
  resolved.bundle.modelProjection.evidenceId !== persisted.evidenceId
388
409
  ) {
389
410
  throw new Error("Agent model projection readback is unbound");
@@ -396,6 +417,26 @@ export function createAgentEvolutionIngress({
396
417
  throw new Error("Agent model projection Run frontier changed");
397
418
  }
398
419
  if (admissionFailure !== null) throw admissionFailure;
420
+ if (skillDecisionRequest !== null) {
421
+ return Object.freeze({
422
+ payload: buildSkillDecisionPayload(
423
+ skillDecisionRequest.payload,
424
+ resolved.bundle.modelProjection,
425
+ ),
426
+ receipt: Object.freeze({
427
+ tenantId: descriptor.tenantId,
428
+ runId: descriptor.runId,
429
+ eventId,
430
+ evidenceId: persisted.evidenceId,
431
+ requestDigest: skillDecisionRequest.requestDigest,
432
+ candidateSetDigest: skillDecisionRequest.candidateSetDigest,
433
+ manifestDigest: persisted.manifest.digest,
434
+ projectionDigest:
435
+ resolved.bundle.modelProjection.projectionDigest,
436
+ rulesetDigest: resolved.bundle.modelProjection.rulesetDigest,
437
+ }),
438
+ });
439
+ }
399
440
  return buildAgentModelRequest(
400
441
  modelRequest,
401
442
  resolved.bundle.modelProjection,
@@ -522,6 +563,21 @@ export function createAgentEvolutionIngress({
522
563
  return response;
523
564
  },
524
565
  start: () => guardIngress(serialize(() => appendStarted())),
566
+ prepareSkillDecisionRequest: (request) => {
567
+ if (admissionFailure !== null) return Promise.reject(admissionFailure);
568
+ let snapshot;
569
+ try {
570
+ snapshot = snapshotSkillDecisionRequest(request);
571
+ if (snapshot.binding.tenantId !== descriptor.tenantId)
572
+ throw new TypeError(
573
+ "Skill decision request belongs to another tenant",
574
+ );
575
+ } catch (error) {
576
+ admissionFailure = ingressFailure(error);
577
+ return Promise.reject(admissionFailure);
578
+ }
579
+ return ingest("skill-decision-input", null, {}, null, false, snapshot);
580
+ },
525
581
  prepareModelRequest: (request) => {
526
582
  if (admissionFailure !== null) return Promise.reject(admissionFailure);
527
583
  let snapshot;
@@ -340,6 +340,7 @@ export class EvolutionEvidenceArtifactAdapter {
340
340
  #ttlMs;
341
341
  #project;
342
342
  #projectAgentModel;
343
+ #projectSkillDecision;
343
344
  #verify;
344
345
  #ports;
345
346
  #resolveManifestRef;
@@ -385,6 +386,11 @@ export class EvolutionEvidenceArtifactAdapter {
385
386
  "projectAgentModelRequest",
386
387
  "projector",
387
388
  );
389
+ this.#projectSkillDecision = captureMethod(
390
+ projector,
391
+ "projectSkillDecisionRequest",
392
+ "projector",
393
+ );
388
394
  this.#verify = captureMethod(bundleVerifier, "verify", "bundleVerifier");
389
395
  this.#ports = artifactPorts;
390
396
  this.#resolveManifestRef =
@@ -411,6 +417,10 @@ export class EvolutionEvidenceArtifactAdapter {
411
417
  return this.#persist(await this.#projectAgentModel(input));
412
418
  }
413
419
 
420
+ async projectAndPersistSkillDecisionRequest(input) {
421
+ return this.#persist(await this.#projectSkillDecision(input));
422
+ }
423
+
414
424
  async #persist(bundle) {
415
425
  const verification = await this.#verify(bundle);
416
426
  if (
@@ -14,6 +14,7 @@ import {
14
14
  projectAgentOpaqueTransportBlock,
15
15
  snapshotAgentModelRequest,
16
16
  } from "./agent-model-projection.js";
17
+ import { snapshotSkillDecisionPayload } from "./skill-decision-projection.js";
17
18
  import {
18
19
  createEvidenceJsonTextBoundary,
19
20
  EVIDENCE_JSON_POLICY,
@@ -523,7 +524,24 @@ export const EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST = `sha256:${createH
523
524
  "utf8",
524
525
  )
525
526
  .digest("hex")}`;
527
+ const SKILL_DECISION_RULESET = Object.freeze({
528
+ ...AGENT_MODEL_RULESET_V2,
529
+ schema: "chainlesschain.evolution-skill-decision-projection-rules/v1",
530
+ version: 1,
531
+ protocol: "skill-routing-state-and-questions/v1",
532
+ maxInputBytes: 256 * 1024,
533
+ });
534
+ export const EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST = `sha256:${createHash(
535
+ "sha256",
536
+ )
537
+ .update(
538
+ `${SKILL_DECISION_RULESET.schema}\0${JSON.stringify(SKILL_DECISION_RULESET)}`,
539
+ "utf8",
540
+ )
541
+ .digest("hex")}`;
542
+
526
543
  const SUPPORTED_RULESETS = new Map([
544
+ [EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST, SKILL_DECISION_RULESET],
527
545
  [RULESET_DIGEST, RULESET],
528
546
  [RAW_RULESET_V3_DIGEST, RAW_RULESET_V3],
529
547
  [AGENT_MODEL_RULESET_V1_DIGEST, AGENT_MODEL_RULESET_V1],
@@ -601,7 +619,8 @@ const AGENT_VALUE_PATTERNS = Object.freeze([
601
619
  ]);
602
620
 
603
621
  function valuePatterns(ruleset) {
604
- return ruleset === AGENT_MODEL_RULESET ||
622
+ return ruleset === SKILL_DECISION_RULESET ||
623
+ ruleset === AGENT_MODEL_RULESET ||
605
624
  ruleset === AGENT_MODEL_RULESET_V2 ||
606
625
  ruleset === AGENT_MODEL_RULESET_V1
607
626
  ? AGENT_VALUE_PATTERNS
@@ -3101,6 +3120,18 @@ function validateBundleIntegrity(bundle) {
3101
3120
  );
3102
3121
  }
3103
3122
  if (model.content !== null) {
3123
+ if (ruleset === SKILL_DECISION_RULESET) {
3124
+ snapshotSkillDecisionPayload(model.content);
3125
+ if (
3126
+ model.truncated ||
3127
+ (model.redactionSummary.byType["content-truncation"] ?? 0) > 0
3128
+ ) {
3129
+ throw projectionError(
3130
+ EVOLUTION_PROJECTION_INVALID_CODE,
3131
+ "Skill decision projection cannot be truncated",
3132
+ );
3133
+ }
3134
+ }
3104
3135
  if (
3105
3136
  ruleset === AGENT_MODEL_RULESET ||
3106
3137
  ruleset === AGENT_MODEL_RULESET_V2 ||
@@ -3368,6 +3399,10 @@ export class EvolutionEvidenceProjector {
3368
3399
  return this.#project(input, AGENT_MODEL_RULESET);
3369
3400
  }
3370
3401
 
3402
+ projectSkillDecisionRequest(input) {
3403
+ return this.#project(input, SKILL_DECISION_RULESET);
3404
+ }
3405
+
3371
3406
  async #project(input, ruleset) {
3372
3407
  assertExactRecord(input, INPUT_KEYS, "evidence projection input");
3373
3408
  if (
@@ -3381,9 +3416,11 @@ export class EvolutionEvidenceProjector {
3381
3416
  );
3382
3417
  }
3383
3418
  const payload =
3384
- ruleset === AGENT_MODEL_RULESET
3385
- ? snapshotAgentModelRequest(input.payload)
3386
- : cloneCanonical(input.payload);
3419
+ ruleset === SKILL_DECISION_RULESET
3420
+ ? snapshotSkillDecisionPayload(input.payload)
3421
+ : ruleset === AGENT_MODEL_RULESET
3422
+ ? snapshotAgentModelRequest(input.payload)
3423
+ : cloneCanonical(input.payload);
3387
3424
  const sourceInputDigest = digest(
3388
3425
  payload,
3389
3426
  "chainlesschain.evolution-raw-plaintext/v2",
@@ -3627,9 +3664,11 @@ export class EvolutionEvidenceProjector {
3627
3664
  const modelProjection = buildModelProjection(
3628
3665
  rawRecord,
3629
3666
  sanitized,
3630
- ruleset === AGENT_MODEL_RULESET
3631
- ? EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST
3632
- : RAW_RULESET_V3_DIGEST,
3667
+ ruleset === SKILL_DECISION_RULESET
3668
+ ? EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST
3669
+ : ruleset === AGENT_MODEL_RULESET
3670
+ ? EVOLUTION_AGENT_MODEL_PROJECTION_RULESET_DIGEST
3671
+ : RAW_RULESET_V3_DIGEST,
3633
3672
  );
3634
3673
  const trustedSanitized = source.compilable
3635
3674
  ? sanitizePayload(
@@ -1,6 +1,10 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { types } from "node:util";
3
3
  import { prepareGovernedModelTurn } from "./governed-model-turn.js";
4
+ import {
5
+ providerFetch,
6
+ requireUnscopedModelTransport,
7
+ } from "../formal-budget-provider-scope.js";
4
8
 
5
9
  const { createAuthenticatedEvolutionModelClient } = createRequire(
6
10
  import.meta.url,
@@ -97,21 +101,25 @@ function captureHubTransport(llm, sdk) {
97
101
  const signal = options.signal
98
102
  ? AbortSignal.any([controller.signal, options.signal])
99
103
  : controller.signal;
100
- const response = await fetchImpl(`${baseUrl}/api/chat`, {
101
- method: "POST",
102
- headers: { "Content-Type": "application/json" },
103
- redirect: "error",
104
- signal,
105
- body: JSON.stringify({
106
- model,
107
- messages,
108
- stream: false,
109
- options: {
110
- temperature: options.temperature ?? 0.2,
111
- ...(options.numCtx ? { num_ctx: options.numCtx } : {}),
112
- },
113
- }),
114
- });
104
+ const response = await providerFetch(
105
+ `${baseUrl}/api/chat`,
106
+ {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ redirect: "error",
110
+ signal,
111
+ body: JSON.stringify({
112
+ model,
113
+ messages,
114
+ stream: false,
115
+ options: {
116
+ temperature: options.temperature ?? 0.2,
117
+ ...(options.numCtx ? { num_ctx: options.numCtx } : {}),
118
+ },
119
+ }),
120
+ },
121
+ fetchImpl,
122
+ );
115
123
  if (!response.ok)
116
124
  throw new Error(
117
125
  `Hub Ollama request failed: HTTP ${response.status}`,
@@ -202,6 +210,7 @@ function captureHubTransport(llm, sdk) {
202
210
  );
203
211
  },
204
212
  async chat(messages, options) {
213
+ requireUnscopedModelTransport();
205
214
  const result = await chat(messages, options);
206
215
  const text =
207
216
  result?.content ??
@@ -233,7 +242,13 @@ function captureHubTransport(llm, sdk) {
233
242
  },
234
243
  };
235
244
  }
236
- return { assertIdentity() {}, chat: llm.chat.bind(llm) };
245
+ return {
246
+ assertIdentity() {},
247
+ chat(messages, options) {
248
+ requireUnscopedModelTransport();
249
+ return llm.chat(messages, options);
250
+ },
251
+ };
237
252
  }
238
253
 
239
254
  // A scoped wrapper preserves the Hub's independent local/cloud consent check.
@@ -1,4 +1,5 @@
1
1
  import { prepareGovernedModelTurn } from "./governed-model-turn.js";
2
+ import { requireUnscopedModelTransport } from "../formal-budget-provider-scope.js";
2
3
  import {
3
4
  captureGovernedHubSdkPorts,
4
5
  createGovernedHubLlm,
@@ -48,6 +49,9 @@ function captureEmbeddingTransport(stage, sdk) {
48
49
  );
49
50
  },
50
51
  async embed(profile) {
52
+ // Neither arbitrary embedding callbacks nor the native embeddings
53
+ // protocol have a verified Chat billing contract in this scope.
54
+ requireUnscopedModelTransport();
51
55
  if (!defaultOllama) return await embed.call(stage, profile);
52
56
  // The raw SDK ollamaEmbed remains closed. This private transport is only
53
57
  // invoked below, after the scoped Run projected the profile.
@@ -8,6 +8,7 @@ import executionBroker, {
8
8
  SANDBOX_BOUNDARIES,
9
9
  } from "../process-execution-broker/index.js";
10
10
  import { BUILT_IN_PROVIDERS } from "../llm-providers.js";
11
+ import { requireUnscopedModelTransport } from "../formal-budget-provider-scope.js";
11
12
 
12
13
  export const GOVERNED_SKILL_SYNTHESIS_PROCESS_GRADER_SCHEMA =
13
14
  "chainlesschain.governed-skill-synthesis-process-grader/v2";
@@ -399,6 +400,9 @@ export function createGovernedSkillSynthesisProcessGrader(options = {}) {
399
400
  persistentProcessAuditRequired: true,
400
401
  });
401
402
  const port = async (messages) => {
403
+ // This worker owns a separate credential reference and cannot inherit an
404
+ // async-local authority. Refuse before provisioning or launching it.
405
+ requireUnscopedModelTransport();
402
406
  const current = executionSnapshot();
403
407
  if (!executionSnapshotMatches(current, snapshot)) {
404
408
  throw new Error(
@@ -0,0 +1,211 @@
1
+ import { types } from "node:util";
2
+ import { createSkillDecisionRequest } from "../decision-layer/contracts.js";
3
+
4
+ const MAX_BYTES = 256 * 1024;
5
+
6
+ function canonical(value) {
7
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
8
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
9
+ return `{${Object.keys(value)
10
+ .sort()
11
+ .map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
12
+ .join(",")}}`;
13
+ }
14
+
15
+ // Capture descriptors before any authority await. Never evaluate source getters
16
+ // or allow caller mutation to change committed evidence or outbound bytes.
17
+ function snapshot(value) {
18
+ let nodes = 0;
19
+ let bytes = 0;
20
+ const seen = new Set();
21
+ const visit = (entry, depth) => {
22
+ if (++nodes > 4096 || depth > 16)
23
+ throw new TypeError("Skill decision input exceeds its structural budget");
24
+ if (typeof entry === "string") {
25
+ bytes += Buffer.byteLength(entry, "utf8");
26
+ if (bytes > MAX_BYTES)
27
+ throw new TypeError("Skill decision input exceeds its byte budget");
28
+ return entry;
29
+ }
30
+ if (
31
+ entry === null ||
32
+ typeof entry === "boolean" ||
33
+ (typeof entry === "number" && Number.isFinite(entry))
34
+ )
35
+ return entry;
36
+ if (
37
+ !entry ||
38
+ typeof entry !== "object" ||
39
+ types.isProxy(entry) ||
40
+ seen.has(entry)
41
+ )
42
+ throw new TypeError(
43
+ "Skill decision input must be acyclic plain JSON data",
44
+ );
45
+ const array = Array.isArray(entry);
46
+ if (
47
+ !array &&
48
+ ![Object.prototype, null].includes(Object.getPrototypeOf(entry))
49
+ )
50
+ throw new TypeError("Skill decision input must use plain objects");
51
+ const keys = Reflect.ownKeys(entry).filter(
52
+ (key) => !(array && key === "length"),
53
+ );
54
+ if (
55
+ array &&
56
+ (keys.length !== entry.length ||
57
+ keys.some((key, index) => key !== String(index)))
58
+ )
59
+ throw new TypeError("Skill decision arrays must be dense data");
60
+ seen.add(entry);
61
+ const output = array ? [] : Object.create(null);
62
+ for (const key of keys) {
63
+ const property = Object.getOwnPropertyDescriptor(entry, key);
64
+ if (
65
+ typeof key !== "string" ||
66
+ !property?.enumerable ||
67
+ !("value" in property)
68
+ )
69
+ throw new TypeError(
70
+ "Skill decision input cannot contain accessors or symbols",
71
+ );
72
+ bytes += Buffer.byteLength(key, "utf8");
73
+ if (bytes > MAX_BYTES)
74
+ throw new TypeError("Skill decision input exceeds its byte budget");
75
+ Object.defineProperty(output, key, {
76
+ value: visit(property.value, depth + 1),
77
+ enumerable: true,
78
+ });
79
+ }
80
+ seen.delete(entry);
81
+ return Object.freeze(output);
82
+ };
83
+ const result = visit(value, 0);
84
+ if (Buffer.byteLength(JSON.stringify(result), "utf8") > MAX_BYTES)
85
+ throw new TypeError("Skill decision input exceeds its byte budget");
86
+ return result;
87
+ }
88
+
89
+ function exact(value, keys) {
90
+ if (
91
+ !value ||
92
+ typeof value !== "object" ||
93
+ Array.isArray(value) ||
94
+ Object.keys(value).sort().join("\0") !== [...keys].sort().join("\0")
95
+ )
96
+ throw new TypeError("Skill decision has an unsupported protocol shape");
97
+ }
98
+
99
+ function text(value) {
100
+ if (typeof value !== "string" || !value.length)
101
+ throw new TypeError("Skill decision requires nonempty text");
102
+ }
103
+
104
+ export function snapshotSkillDecisionPayload(value) {
105
+ const payload = snapshot(value);
106
+ exact(payload, ["state", "questions"]);
107
+ exact(payload.state, ["task", "candidates"]);
108
+ text(payload.state.task);
109
+ const candidates = payload.state.candidates;
110
+ if (
111
+ !Array.isArray(candidates) ||
112
+ candidates.length < 1 ||
113
+ candidates.length > 8
114
+ )
115
+ throw new TypeError("Skill decision requires bounded candidates");
116
+ candidates.forEach((candidate, index) => {
117
+ exact(candidate, [
118
+ "candidateId",
119
+ "name",
120
+ "description",
121
+ "category",
122
+ "tags",
123
+ ]);
124
+ if (candidate.candidateId !== `c${index + 1}`)
125
+ throw new TypeError("Skill decision candidate identity changed");
126
+ for (const key of ["name", "description", "category"]) text(candidate[key]);
127
+ if (!Array.isArray(candidate.tags) || candidate.tags.length > 32)
128
+ throw new TypeError("Skill decision tags are unbounded");
129
+ candidate.tags.forEach(text);
130
+ });
131
+ const ids = candidates.map(({ candidateId }) => candidateId);
132
+ exact(payload.questions, [
133
+ "needs_skill",
134
+ "best_skill",
135
+ ...ids.map((id) => `fits_${id}`),
136
+ ]);
137
+ for (const key of ["needs_skill", ...ids.map((id) => `fits_${id}`)]) {
138
+ exact(payload.questions[key], ["type", "instructions"]);
139
+ if (payload.questions[key].type !== "noul")
140
+ throw new TypeError("Skill decision question type changed");
141
+ text(payload.questions[key].instructions);
142
+ }
143
+ const choice = payload.questions.best_skill;
144
+ exact(choice, ["type", "instructions", "criteria"]);
145
+ if (choice.type !== "choice")
146
+ throw new TypeError("Skill decision question type changed");
147
+ text(choice.instructions);
148
+ exact(choice.criteria, [...ids, "none"]);
149
+ Object.values(choice.criteria).forEach(text);
150
+ return payload;
151
+ }
152
+
153
+ export function snapshotSkillDecisionRequest(value) {
154
+ const request = snapshot(value);
155
+ const rebuilt = createSkillDecisionRequest({
156
+ decisionId: request.decisionId,
157
+ ...request.binding,
158
+ query: request.payload?.state?.task,
159
+ candidates: request.candidates,
160
+ });
161
+ if (canonical(request) !== canonical(rebuilt))
162
+ throw new TypeError("Skill decision request identity or contract changed");
163
+ snapshotSkillDecisionPayload(request.payload);
164
+ return request;
165
+ }
166
+
167
+ function textPath(path) {
168
+ return (
169
+ /^state\.task$/u.test(path) ||
170
+ /^state\.candidates\.\d+\.(?:name|description|category|tags\.\d+)$/u.test(
171
+ path,
172
+ ) ||
173
+ /^questions\.best_skill\.criteria\.c[1-8]$/u.test(path)
174
+ );
175
+ }
176
+
177
+ export function buildSkillDecisionPayload(original, projection) {
178
+ if (
179
+ projection.visibility !== "model-visible" ||
180
+ projection.truncated ||
181
+ (projection.redactionSummary?.byType?.["content-truncation"] ?? 0) > 0
182
+ )
183
+ throw new Error("Skill decision projection is opaque or truncated");
184
+ const captured = snapshotSkillDecisionPayload(original);
185
+ const projected = snapshotSkillDecisionPayload(projection.content);
186
+ const compare = (before, after, path = "") => {
187
+ if (
188
+ typeof before === "string" &&
189
+ typeof after === "string" &&
190
+ textPath(path)
191
+ )
192
+ return;
193
+ if (before === null || typeof before !== "object") {
194
+ if (before !== after)
195
+ throw new Error("Skill decision projection changed protocol metadata");
196
+ return;
197
+ }
198
+ if (
199
+ !after ||
200
+ typeof after !== "object" ||
201
+ Array.isArray(before) !== Array.isArray(after) ||
202
+ Object.keys(before).sort().join("\0") !==
203
+ Object.keys(after).sort().join("\0")
204
+ )
205
+ throw new Error("Skill decision projection changed protocol structure");
206
+ for (const key of Object.keys(before))
207
+ compare(before[key], after[key], path ? `${path}.${key}` : key);
208
+ };
209
+ compare(captured, projected);
210
+ return projected;
211
+ }
@@ -239,9 +239,19 @@ export async function openSkillRetrievalRevocationAuthority({
239
239
  ) {
240
240
  throw new Error("Retrieval revocation load is not authoritative");
241
241
  }
242
- state = loaded.found
242
+ const loadedState = loaded.found
243
243
  ? verifySkillRetrievalRevocationState(loaded.state, tenantId)
244
244
  : null;
245
+ if (
246
+ state !== null &&
247
+ (loadedState === null ||
248
+ loadedState.revision < state.revision ||
249
+ (loadedState.revision === state.revision &&
250
+ loadedState.stateDigest !== state.stateDigest))
251
+ ) {
252
+ throw new Error("Retrieval revocation state regressed");
253
+ }
254
+ state = loadedState;
245
255
  return state;
246
256
  }
247
257
 
@@ -265,6 +275,10 @@ export async function openSkillRetrievalRevocationAuthority({
265
275
  receiptDigest: entry?.propagationRequestDigest ?? null,
266
276
  });
267
277
  },
278
+ async refresh() {
279
+ const current = await reload();
280
+ return current?.stateDigest ?? null;
281
+ },
268
282
  async invalidateRetrieval(input) {
269
283
  const request = normalizeRequest(input, tenantId);
270
284
  const contentDigest = request.dependency.digest;
@@ -351,7 +365,8 @@ export function captureSkillRetrievalRevocationReader(reader) {
351
365
  if (
352
366
  !readerBrand.has(reader) ||
353
367
  reader.schema !== SKILL_RETRIEVAL_REVOCATION_READER_SCHEMA ||
354
- typeof reader.inspect !== "function"
368
+ typeof reader.inspect !== "function" ||
369
+ typeof reader.refresh !== "function"
355
370
  ) {
356
371
  throw new TypeError(
357
372
  "A branded Skill retrieval revocation reader is required",