chainlesschain 0.166.65 → 0.166.68

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 (198) hide show
  1. package/README.md +20 -12
  2. package/package.json +4 -4
  3. package/src/assets/web-panel/assets/{AIOps-Byz17CTN.js → AIOps-CXkSNOGY.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-C5LiW2-J.js → ActionButton-ysMR6gTs.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-D1INcvZF.js → Analytics-WGZ0sWuw.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DZzHO1VV.js → AppLayout-Cs2iRlQG.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-WfYQL6Ia.js → Artifacts-5IdfxWz0.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DohBoGWO.js → Audit-U9V434QX.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-Chtk-Hde.js → BackgroundAgents-BvFwxPlC.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-B813PuMz.js → Backup-C9yTr9hO.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DaDdWWgK.js → BaseInput-BdsSwUgE.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-D4pJ6oZ7.js → Chat-BB_2oBgH.js} +5 -5
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-Bpf1hDUl.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-Clo9TvO6.js → Checkbox-v6M5m7dK.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-uejLg8Ih.js → Codegen-CtouWSIz.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-B7nbx-iJ.js → Col-CqQJ4ORW.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-FEyjPK1j.js → Community-BO__QCOy.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-B6Fk0Kn6.js → Compact-D0Kq4xlH.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BQG8goUl.js → Compliance-BSLKKBjA.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-CbBeEfHp.js → Cowork-VsujXW5o.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-DPzlFcEZ.js → Cron-j8DbLGi5.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-B8pWJrbg.js → Crosschain-DWpYH1yN.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-gGQHUlFN.js → DID-mLaRxLQh.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-C2TMFHrn.js → Dashboard-Cff033Jr.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BVPxGbll.js → Dropdown-B1Upt6fP.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-CNPxs0hd.js → EmailListRenderer-CPtb8joV.js} +1 -1
  27. package/src/assets/web-panel/assets/{EvolutionSettings-_XTiB7q1.js → EvolutionSettings-CVh4Uv4g.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-UyE3VWtI.js → FamilyGuardDashboard-CrD1PhbF.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-CLt6FHK-.js → Federation-ftxrvqW5.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-CdNQPRPw.js → FormItemContext-9O80slC1.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-BJ0AMhrh.js → GenericCardRenderer-DaYvYIj9.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-CQnvMfOM.js → Git-BKZh0YE5.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-deYsHC-o.js → Governance-vWbN873j.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-qaSck43z.js → Inference-BN6RR-l8.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-De0aJ3Ls.js → KnowledgeGraph-x49x9m7Q.js} +1 -1
  36. package/src/assets/web-panel/assets/Logs-Co2EPLsJ.js +2 -0
  37. package/src/assets/web-panel/assets/MarkdownRenderer-D7wIB-c7.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-Byz3xCBN.js → Marketplace-DpPu6XQp.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-DOZUUW6z.js → McpTools-BR0ksiax.js} +3 -3
  40. package/src/assets/web-panel/assets/{Memory-C33wC2hA.js → Memory-BXznJ5-C.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-zZe-T_6M.js → MobileBridge-BHSOpfv7.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-CRnUIume.js → MobileProjects-DdWmgIup.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-C1xlRVAN.js → Mtc-D9Rk_IGT.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-D0U07bIi.js → MtcAudit--i8q1lKc.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-DF8uvV3h.js → Multisig-BHnNG7R9.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-bBPGAFlt.js → NLProgramming-Duo1ij2_.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BHAaOsgg.js → Notes-B44Le73p.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-Cl0fG_rA.js → NotificationSettings-C3oy_7Gf.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-BEPAs8Zv.js → OrderTableRenderer-Da_73SI5.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-BAxSwgk5.js → Organization-ChsSwKxT.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-D68KubAu.js → Overflow-DR5G_cCn.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-bhdT17zk.js → P2P-yfaobqow.js} +2 -2
  53. package/src/assets/web-panel/assets/PdhVaultBrowser-DgimH6Jp.js +7 -0
  54. package/src/assets/web-panel/assets/{Permissions-Bq8fvkak.js → Permissions-DhinFvtE.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-BYd2JEic.js → PersonalDataHub-CfeNVic1.js} +5 -5
  56. package/src/assets/web-panel/assets/{Pipeline-Csg_ja69.js → Pipeline-CGKO26Nk.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-lwxwLj4M.js → Privacy-CxxfYEJh.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-BdBZkH8z.js → ProjectInit-CZsaAab9.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-ClWgFy-K.js → ProjectSettings-BUm_6clQ.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-Bu-qj8N1.js → Projects-Capr8bVq.js} +1 -1
  61. package/src/assets/web-panel/assets/{Providers-DEjxrxw3.js → Providers-D28VqPja.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-eccy-8Vi.js → QrScannerModal-Cj200vUb.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-Vx3uDvFg.js → QuickAsk-BGpnEiam.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-CfUivNps.js → Recommend-Ix79Tpni.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-BU4gk7GI.js → RemoteSession-BdGAFbIk.js} +3 -3
  66. package/src/assets/web-panel/assets/{Reputation-CbPzdZ0C.js → Reputation-B1Lis0Wk.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-CYLrgfKA.js → Row-Ba_okwOW.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-DbY1oyuv.js → RssFeed-DDbEuI-m.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-QeW41K5r.js → Search-D89wAkMy.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-CJxf1kLZ.js → Security-CJKCKAU-.js} +3 -3
  71. package/src/assets/web-panel/assets/{Services-CFO9ySZc.js → Services-mitEc1XV.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-CQFjeQN0.js → Skeleton-CnBjLDfX.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CLLB4INW.js → Skills-DSzDYvH3.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-DxeLIJk0.js → Sla-CglJ_4p3.js} +1 -1
  75. package/src/assets/web-panel/assets/SpeechSettings-BicWJS7f.js +1 -0
  76. package/src/assets/web-panel/assets/{SyncSettings-C6NOkcQK.js → SyncSettings-Cq7o6fmr.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-LmVPWDfQ.js → Tasks-DOxFOBpU.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-BdEfUoVB.js → Templates-bY0wSbQM.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-IUlESacN.js → Tenant-BAyyl0qX.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-B9pDe7sn.js → Terminal-BGBhSpqc.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-ZCwB-Pki.js → TimelineRenderer-BvW5lXYz.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-4qk16LX1.js → Tokens-Ua_LIx8-.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-jXNyargn.js → Trigger-BGwb2KL1.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-D13PydtT.js → Trust-CD2IEHvj.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-yPgws6mS.js → UkeySign-D5LetK6P.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-B329WjpG.js → VideoEditing-oP7ehFgR.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-T8VM-Ttm.js → Wallet-BBtu4-xa.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-XuRibrpP.js → WebAuthn-iSPRU4Ht.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-D1Gwz3YR.js → WorkflowEditor-DuEDhQmB.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-DjydtnT-.js → chat-DGDgqvvm.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-gFtBvPrr.js → colors-DGQMWa1-.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-CndxhGfx.js → compact-item-COVznBL4.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-DnfGpd0L.js → createContext-DIxVeHXI.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-CjR9h-Z_.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-CmT5hRVW.js → hasIn-DkxZO3E9.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BGlmPbl_.js → index-0ToBFsvW.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BsRKmb6k.js → index-2JZizEPc.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-C14jryXi.js → index-BAL2p7YC.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-B0WFjxWs.js → index-BAlrovUm.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BlTcxT_L.js → index-BBw2MLIe.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DjcR-CwS.js → index-BHH95jcm.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DreYqebI.js → index-BOTshZNx.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DaEPE2DC.js → index-BQm7ntcn.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BNHdO6Jr.js → index-BUqwlzc8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C3HvYeA3.js → index-BY6MSbWT.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DUlubR4l.js → index-BY9Ossof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Dbpk75MO.js → index-BgM-3a1w.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CqpR0Des.js → index-Bv0_u0ze.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DjY-3sMA.js → index-C3XeNS82.js} +3 -3
  110. package/src/assets/web-panel/assets/{index-DV6NrfJx.js → index-C3bN6751.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DuAvYTmY.js → index-CNRRrP3-.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BW3nWiu0.js → index-CV0KnNqR.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CZLDbPTa.js → index-CcNGQWum.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-D5na0B7G.js → index-Ci34vbh0.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DoBKSzqu.js → index-ClQVcrFt.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CuOx4Pbe.js → index-Cligb-Dl.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CgMKElUh.js → index-CokrhbY2.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BFif4Cev.js → index-CpZxDiVK.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-HHP1zzo7.js → index-CyMHF2Bi.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-_-wGLtAg.js → index-DDwPBGdA.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-ktN-K1Tf.js → index-DU1ArKl5.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C4Mqhmas.js → index-DV0H83eS.js} +1 -1
  123. package/src/assets/web-panel/assets/index-D_nxBMX5.js +1 -0
  124. package/src/assets/web-panel/assets/{index-BXNUTiW8.js → index-DaWQSp5a.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DKyuE_Y2.js → index-DmduvOYT.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DV2PR3Fa.js → index-ECoDhyH3.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BVM_w30N.js → index-ZcqTvPnt.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CRqz8TtI.js → index-b2_M6o20.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CB27echm.js → index-b_0qTo8O.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-D88-8bsB.js → index-dfYkGovV.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DGbKeg8G.js → index-jo7DbU0w.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D2d7358Y.js → index-usmG13jq.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-zQf599Uq.js → index-vXrktF3e.js} +1 -1
  134. package/src/assets/web-panel/assets/index-z_cTUMX-.js +1 -0
  135. package/src/assets/web-panel/assets/{initDefaultProps-KV3V-PNH.js → initDefaultProps-CkSeiBwL.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-PFGQg7_X.js → motion-CSzhDP0s.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-Dnl79wq4.js → move-mgCt4iC6.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-Bwl5JH9V.js → mtc-parser-BEZBLcKt.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-DCcTtM1l.js → omit-BsHctMEr.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-Cl6BjjDf.js → pickAttrs-1BHamnGW.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-fdqhyo42.js → placementArrow--Vb4Bd7l.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-DYQpmcDW.js → responsiveObserve-DD33SqCm.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-C4l-VfO4.js → slide-DfrLtxgK.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-DYDw_dyZ.js → statusUtils-D9Pe_gXW.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-BEsubSMu.js → styleChecker-0NY5iMun.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-Cj82ggQ_.js → useFlexGapSupport-DSsZstwg.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-B7L1eJ0V.js → useFs-BU8HyH59.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-DVlJVD4d.js → usePersonalDataHub-D_xttink.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-BBAbRN_Y.js → vnode-39VhX2lM.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-BYn48q-I.js → zoom-D5KQ8Pks.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/data/changelog.json +20 -7
  153. package/src/lib/dependency-install-policy.js +1 -1
  154. package/src/lib/evolution/browser-download-action-authority.js +747 -0
  155. package/src/lib/evolution/browser-download-artifact-disposal-authority.js +436 -0
  156. package/src/lib/evolution/browser-filesystem-quarantine-custody.js +2453 -0
  157. package/src/lib/evolution/browser-filesystem-quarantine-disposal.js +36 -0
  158. package/src/lib/evolution/browser-keyboard-action-authority.js +560 -0
  159. package/src/lib/evolution/browser-navigation-action-authority.js +546 -0
  160. package/src/lib/evolution/browser-quarantine-lock-maintenance-authority.js +573 -0
  161. package/src/lib/evolution/browser-quarantine-operator-revocation-authority.js +442 -0
  162. package/src/lib/evolution/browser-quarantine-retention-authority.js +503 -0
  163. package/src/lib/evolution/browser-quarantine-retention-scheduler.js +207 -0
  164. package/src/lib/evolution/browser-quarantined-download-executor.js +525 -0
  165. package/src/lib/evolution/browser-tab-open-action-authority.js +491 -0
  166. package/src/lib/evolution/browser-vision-action-authority.js +444 -0
  167. package/src/lib/evolution/browser-vision-observation-authority.js +304 -0
  168. package/src/lib/evolution/evolution-deployment-loader.js +202 -1
  169. package/src/lib/evolution/evolution-eval-child-evidence-ledger-adapter.js +5 -0
  170. package/src/lib/evolution/evolution-eval-gate.js +2 -1
  171. package/src/lib/evolution/evolution-eval-process-supervisor-worker.mjs +71 -9
  172. package/src/lib/evolution/evolution-eval-process-supervisor.js +276 -9
  173. package/src/lib/evolution/evolution-workbench-metrics.js +81 -21
  174. package/src/lib/evolution/pm-exploration-benchmark.js +747 -0
  175. package/src/lib/evolution/pm-exploration-budget-executor.js +106 -9
  176. package/src/lib/evolution/pm-exploration-egress-authority.js +382 -0
  177. package/src/lib/evolution/pm-exploration-evidence-bundle.js +149 -44
  178. package/src/lib/evolution/pm-exploration-execution-host.js +1254 -8
  179. package/src/lib/evolution/pm-exploration-process-grader.js +458 -0
  180. package/src/lib/evolution/pm-exploration-process-reviewer.js +456 -0
  181. package/src/lib/evolution/pm-exploration-process-runner.js +500 -0
  182. package/src/lib/evolution/pm-exploration-receipts.js +211 -11
  183. package/src/lib/evolution/pm-exploration-recovery-snapshot-store.js +465 -46
  184. package/src/lib/evolution/pm-exploration-transition-committer.js +185 -34
  185. package/src/lib/evolution/skill-outcome-index-authority.js +7 -3
  186. package/src/lib/governance-coverage.js +1 -1
  187. package/src/lib/headless-manifest.js +1 -1
  188. package/src/lib/protocol-replay.js +1 -1
  189. package/src/lib/skill-outcome-transcript-authority.js +45 -5
  190. package/src/runtime/agent-core.js +17 -0
  191. package/src/assets/web-panel/assets/ChatBubbleRenderer-Cf3LLgDc.js +0 -1
  192. package/src/assets/web-panel/assets/Logs-ZtS98jCm.js +0 -2
  193. package/src/assets/web-panel/assets/MarkdownRenderer-CTsYo9NN.js +0 -1
  194. package/src/assets/web-panel/assets/PdhVaultBrowser-DqaO6wgH.js +0 -7
  195. package/src/assets/web-panel/assets/SpeechSettings-D4FA9KYI.js +0 -1
  196. package/src/assets/web-panel/assets/devWarning-D60SbiD-.js +0 -1
  197. package/src/assets/web-panel/assets/index-C0yR4_7h.js +0 -1
  198. package/src/assets/web-panel/assets/index-D4xuvo03.js +0 -1
@@ -1,14 +1,76 @@
1
- let input = "";
2
- for await (const chunk of process.stdin) {
3
- input += chunk.toString("utf8");
4
- if (Buffer.byteLength(input) > 1024 * 1024)
5
- throw new Error("evaluation process input exceeds 1 MiB");
6
- }
7
- const request = JSON.parse(input);
1
+ import { createInterface } from "node:readline";
2
+
3
+ const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
4
+ const iterator = lines[Symbol.asyncIterator]();
5
+ const first = await iterator.next();
6
+ if (first.done || Buffer.byteLength(first.value) > 1024 * 1024)
7
+ throw new Error("evaluation process input exceeds 1 MiB");
8
+ const request = JSON.parse(first.value);
8
9
  const moduleUrl = new URL(request.moduleUrl);
9
10
  const implementation = await import(moduleUrl.href);
10
11
  const handler = implementation[request.exportName];
11
12
  if (typeof handler !== "function")
12
13
  throw new Error("evaluation process export is unavailable");
13
- const value = await handler(request.payload);
14
- process.stdout.write(`${JSON.stringify({ ok: true, value })}\n`);
14
+
15
+ if (request.protocol !== "chainlesschain.evolution-process-broker/v1") {
16
+ const extra = await iterator.next();
17
+ if (!extra.done) throw new Error("evaluation process received extra input");
18
+ const value = await handler(request.payload);
19
+ process.stdout.write(`${JSON.stringify({ ok: true, value })}\n`);
20
+ } else {
21
+ let sequence = 0;
22
+ const pending = new Map();
23
+ const readResponses = (async () => {
24
+ for await (const line of iterator) {
25
+ if (Buffer.byteLength(line) > 1024 * 1024)
26
+ throw new Error("evaluation broker response exceeds 1 MiB");
27
+ const message = JSON.parse(line);
28
+ const waiter = pending.get(message?.requestId);
29
+ if (
30
+ !waiter ||
31
+ message?.type !== "broker-response" ||
32
+ typeof message.ok !== "boolean" ||
33
+ Object.keys(message).some(
34
+ (key) => !["type", "requestId", "ok", "value", "error"].includes(key),
35
+ )
36
+ ) {
37
+ throw new Error("evaluation broker response is invalid");
38
+ }
39
+ pending.delete(message.requestId);
40
+ if (message.ok) waiter.resolve(message.value);
41
+ else waiter.reject(new Error("parent broker rejected the operation"));
42
+ }
43
+ if (pending.size > 0)
44
+ throw new Error("evaluation broker closed with pending operations");
45
+ })();
46
+
47
+ const call = (operation, input) =>
48
+ new Promise((resolve, reject) => {
49
+ sequence += 1;
50
+ const requestId = `broker-${sequence}`;
51
+ pending.set(requestId, { resolve, reject });
52
+ process.stdout.write(
53
+ `${JSON.stringify({
54
+ type: "broker-request",
55
+ requestId,
56
+ operation,
57
+ input,
58
+ })}\n`,
59
+ );
60
+ });
61
+ const runtime = Object.freeze({
62
+ recordTokens: (count) => call("record-tokens", { count }),
63
+ invokeTool: (toolId, input) => call("invoke-tool", { toolId, input }),
64
+ retrieveMemory: (input) => call("retrieve-memory", { input }),
65
+ invokeModel: (input) => call("invoke-model", { input }),
66
+ });
67
+ const value = await handler(request.payload, runtime);
68
+ if (pending.size > 0)
69
+ throw new Error(
70
+ "evaluation target returned with unsettled broker requests",
71
+ );
72
+ process.stdout.write(`${JSON.stringify({ type: "result", value })}\n`, () =>
73
+ process.exit(0),
74
+ );
75
+ await readResponses;
76
+ }
@@ -3,6 +3,7 @@ import { lstat, readFile, realpath } from "node:fs/promises";
3
3
  import { lstatSync, readFileSync, realpathSync } from "node:fs";
4
4
  import { dirname, isAbsolute, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { isProxy } from "node:util/types";
6
7
 
7
8
  import executionBroker from "../process-execution-broker/index.js";
8
9
  import { isEvolutionEvalChildEvidenceStore } from "./evolution-eval-child-evidence-ledger-adapter.js";
@@ -29,6 +30,7 @@ const MIN_MEMORY_LIMIT_MB = 32;
29
30
  const MAX_MEMORY_LIMIT_MB = 1024;
30
31
  const MAX_PERMISSION_PATHS = 32;
31
32
  const PROCESS_SUPERVISORS = new WeakSet();
33
+ const PROCESS_RUNTIME_BROKERS = new WeakMap();
32
34
 
33
35
  function canonical(value) {
34
36
  if (value === null || typeof value !== "object") return JSON.stringify(value);
@@ -127,14 +129,23 @@ function sandboxPolicy(value) {
127
129
  if (paths === undefined) return Object.freeze([]);
128
130
  if (!Array.isArray(paths) || paths.length > MAX_PERMISSION_PATHS)
129
131
  throw new TypeError(`${label} must be a bounded array`);
130
- const normalized = paths.map((path) => {
132
+ const requested = paths.map((path) => {
131
133
  if (typeof path !== "string" || !isAbsolute(path))
132
134
  throw new TypeError(`${label} paths must be absolute`);
133
135
  return resolve(path);
134
136
  });
135
- if (new Set(normalized).size !== normalized.length)
137
+ if (new Set(requested).size !== requested.length)
136
138
  throw new TypeError(`${label} paths must be unique`);
137
- return Object.freeze(normalized);
139
+ const normalized = requested.flatMap((absolute) => {
140
+ try {
141
+ const physical = realpathSync(absolute);
142
+ return physical === absolute ? [absolute] : [absolute, physical];
143
+ } catch (cause) {
144
+ if (cause?.code === "ENOENT") return [absolute];
145
+ throw new Error(`${label} path could not be resolved`, { cause });
146
+ }
147
+ });
148
+ return Object.freeze([...new Set(normalized)]);
138
149
  };
139
150
  const memoryLimitMb = value.memoryLimitMb ?? DEFAULT_MEMORY_LIMIT_MB;
140
151
  if (
@@ -237,6 +248,253 @@ function processResult(child, input) {
237
248
  });
238
249
  }
239
250
 
251
+ function writeBrokerMessage(child, value) {
252
+ const encoded = `${JSON.stringify(value)}\n`;
253
+ if (Buffer.byteLength(encoded) > MAX_OUTPUT_BYTES)
254
+ return Promise.reject(new Error("evaluation broker message exceeds 1 MiB"));
255
+ return new Promise((resolveWrite, reject) => {
256
+ if (child.stdin.destroyed || child.stdin.writableEnded) {
257
+ reject(new Error("evaluation broker input is closed"));
258
+ return;
259
+ }
260
+ child.stdin.write(encoded, (error) => {
261
+ if (error) reject(error);
262
+ else resolveWrite();
263
+ });
264
+ });
265
+ }
266
+
267
+ function processBrokeredResult(child, input, brokerValue) {
268
+ const broker = PROCESS_RUNTIME_BROKERS.get(brokerValue);
269
+ if (!broker)
270
+ return Promise.reject(
271
+ new TypeError("a branded evaluation process runtime broker is required"),
272
+ );
273
+ return new Promise((resolveResult, reject) => {
274
+ let stdoutBuffer = "";
275
+ let stdoutBytes = 0;
276
+ let stderr = "";
277
+ let settled = false;
278
+ let completionError = null;
279
+ let resultSeen = false;
280
+ let resultValue;
281
+ let requestCount = 0;
282
+ const requestIds = new Set();
283
+ let messages = Promise.resolve();
284
+ const rejectOnce = (error) => {
285
+ if (settled) return;
286
+ settled = true;
287
+ reject(error);
288
+ };
289
+ const handleMessage = async (line) => {
290
+ if (!line || Buffer.byteLength(line) > MAX_OUTPUT_BYTES)
291
+ throw new Error("evaluation broker record exceeds 1 MiB");
292
+ const message = JSON.parse(line);
293
+ if (message?.type === "result") {
294
+ if (
295
+ resultSeen ||
296
+ Object.keys(message).length !== 2 ||
297
+ requestIds.size !== 0
298
+ ) {
299
+ throw new Error("evaluation broker result is invalid or premature");
300
+ }
301
+ resultSeen = true;
302
+ resultValue = jsonClone(message.value, "evaluation target result");
303
+ return;
304
+ }
305
+ if (
306
+ resultSeen ||
307
+ message?.type !== "broker-request" ||
308
+ typeof message.requestId !== "string" ||
309
+ !/^broker-[1-9][0-9]*$/u.test(message.requestId) ||
310
+ ![
311
+ "record-tokens",
312
+ "invoke-tool",
313
+ "retrieve-memory",
314
+ "invoke-model",
315
+ ].includes(message.operation) ||
316
+ !message.input ||
317
+ typeof message.input !== "object" ||
318
+ Array.isArray(message.input) ||
319
+ Object.keys(message).length !== 4 ||
320
+ requestIds.has(message.requestId) ||
321
+ requestCount >= 512
322
+ ) {
323
+ throw new Error("evaluation broker request is invalid");
324
+ }
325
+ requestCount += 1;
326
+ requestIds.add(message.requestId);
327
+ try {
328
+ let value;
329
+ if (message.operation === "record-tokens") {
330
+ if (
331
+ Object.keys(message.input).length !== 1 ||
332
+ !Number.isSafeInteger(message.input.count) ||
333
+ message.input.count < 0
334
+ ) {
335
+ throw new TypeError("broker token count is invalid");
336
+ }
337
+ value = await broker.recordTokens(message.input.count);
338
+ } else if (message.operation === "invoke-tool") {
339
+ if (
340
+ Object.keys(message.input).length !== 2 ||
341
+ typeof message.input.toolId !== "string"
342
+ ) {
343
+ throw new TypeError("broker tool request is invalid");
344
+ }
345
+ value = await broker.invokeTool(
346
+ message.input.toolId,
347
+ jsonClone(message.input.input, "evaluation broker tool input"),
348
+ );
349
+ } else {
350
+ if (Object.keys(message.input).length !== 1) {
351
+ throw new TypeError("broker egress request is invalid");
352
+ }
353
+ const inputValue = jsonClone(
354
+ message.input.input,
355
+ "evaluation broker egress input",
356
+ );
357
+ const port =
358
+ message.operation === "retrieve-memory"
359
+ ? broker.retrieveMemory
360
+ : broker.invokeModel;
361
+ if (port === null)
362
+ throw new Error("evaluation broker egress port is unavailable");
363
+ value = await port(inputValue);
364
+ }
365
+ await writeBrokerMessage(child, {
366
+ type: "broker-response",
367
+ requestId: message.requestId,
368
+ ok: true,
369
+ value: jsonClone(value, "evaluation broker result"),
370
+ });
371
+ } catch {
372
+ await writeBrokerMessage(child, {
373
+ type: "broker-response",
374
+ requestId: message.requestId,
375
+ ok: false,
376
+ error: "operation-rejected",
377
+ }).catch(() => {});
378
+ } finally {
379
+ requestIds.delete(message.requestId);
380
+ }
381
+ };
382
+ child.stdout.on("data", (chunk) => {
383
+ const text = chunk.toString("utf8");
384
+ stdoutBytes += Buffer.byteLength(text);
385
+ if (!completionError && stdoutBytes > MAX_OUTPUT_BYTES) {
386
+ completionError = new Error("evaluation target stdout exceeds 1 MiB");
387
+ child.kill("SIGKILL");
388
+ return;
389
+ }
390
+ stdoutBuffer += text;
391
+ for (;;) {
392
+ const newline = stdoutBuffer.indexOf("\n");
393
+ if (newline < 0) break;
394
+ const line = stdoutBuffer.slice(0, newline);
395
+ stdoutBuffer = stdoutBuffer.slice(newline + 1);
396
+ messages = messages.then(() => handleMessage(line));
397
+ }
398
+ messages.catch((cause) => {
399
+ completionError ??= new Error("evaluation broker protocol failed", {
400
+ cause,
401
+ });
402
+ child.kill("SIGKILL");
403
+ });
404
+ });
405
+ child.stderr.on("data", (chunk) => {
406
+ stderr += chunk.toString("utf8");
407
+ if (!completionError && Buffer.byteLength(stderr) > MAX_OUTPUT_BYTES) {
408
+ completionError = new Error("evaluation target stderr exceeds 1 MiB");
409
+ child.kill("SIGKILL");
410
+ }
411
+ });
412
+ child.once("error", rejectOnce);
413
+ child.once("close", (code, signal) => {
414
+ messages.then(
415
+ () => {
416
+ if (settled) return;
417
+ if (completionError) {
418
+ rejectOnce(completionError);
419
+ return;
420
+ }
421
+ if (code !== 0) {
422
+ rejectOnce(
423
+ new Error(
424
+ `evaluation target exited ${code ?? "null"}/${signal ?? "none"}: ${stderr.slice(0, 512)}`,
425
+ ),
426
+ );
427
+ return;
428
+ }
429
+ if (stdoutBuffer.length !== 0 || !resultSeen) {
430
+ rejectOnce(new Error("evaluation broker result is incomplete"));
431
+ return;
432
+ }
433
+ settled = true;
434
+ resolveResult(resultValue);
435
+ },
436
+ (cause) =>
437
+ rejectOnce(
438
+ new Error("evaluation broker response is invalid", { cause }),
439
+ ),
440
+ );
441
+ });
442
+ child.stdin.once("error", (error) => {
443
+ completionError ??= error;
444
+ });
445
+ writeBrokerMessage(child, {
446
+ ...input,
447
+ protocol: "chainlesschain.evolution-process-broker/v1",
448
+ }).catch((cause) => {
449
+ completionError ??= cause;
450
+ child.kill("SIGKILL");
451
+ });
452
+ });
453
+ }
454
+
455
+ export function createEvolutionEvalProcessRuntimeBroker(options = {}) {
456
+ const plain =
457
+ !options ||
458
+ typeof options !== "object" ||
459
+ Array.isArray(options) ||
460
+ isProxy(options) ||
461
+ Object.getPrototypeOf(options) !== Object.prototype;
462
+ if (plain)
463
+ throw new TypeError("evaluation process runtime broker ports are invalid");
464
+ const hasMemory = Object.hasOwn(options, "retrieveMemory");
465
+ const hasModel = Object.hasOwn(options, "invokeModel");
466
+ if (
467
+ Reflect.ownKeys(options).length !==
468
+ 2 + Number(hasMemory) + Number(hasModel) ||
469
+ !Object.hasOwn(options, "recordTokens") ||
470
+ !Object.hasOwn(options, "invokeTool") ||
471
+ typeof options.recordTokens !== "function" ||
472
+ isProxy(options.recordTokens) ||
473
+ typeof options.invokeTool !== "function" ||
474
+ isProxy(options.invokeTool) ||
475
+ (hasMemory &&
476
+ (typeof options.retrieveMemory !== "function" ||
477
+ isProxy(options.retrieveMemory))) ||
478
+ (hasModel &&
479
+ (typeof options.invokeModel !== "function" ||
480
+ isProxy(options.invokeModel)))
481
+ ) {
482
+ throw new TypeError("evaluation process runtime broker ports are invalid");
483
+ }
484
+ const broker = Object.freeze({});
485
+ PROCESS_RUNTIME_BROKERS.set(broker, {
486
+ recordTokens: options.recordTokens,
487
+ invokeTool: options.invokeTool,
488
+ retrieveMemory: hasMemory ? options.retrieveMemory : null,
489
+ invokeModel: hasModel ? options.invokeModel : null,
490
+ });
491
+ return broker;
492
+ }
493
+
494
+ export function isEvolutionEvalProcessRuntimeBroker(value) {
495
+ return PROCESS_RUNTIME_BROKERS.has(value);
496
+ }
497
+
240
498
  export function createEvolutionEvalProcessSupervisor({
241
499
  targets,
242
500
  authorityDescriptor,
@@ -446,7 +704,7 @@ export function createEvolutionEvalProcessSupervisor({
446
704
  );
447
705
  }
448
706
 
449
- async function invokeTarget(request) {
707
+ async function invokeTarget(request, context = null) {
450
708
  const entry = registry.get(request?.target?.handlerId);
451
709
  if (!entry) {
452
710
  if (fallbackSupervisor) return fallbackSupervisor.invokeTarget(request);
@@ -478,11 +736,14 @@ export function createEvolutionEvalProcessSupervisor({
478
736
  );
479
737
  active.set(request.capabilityDigest, { child, closed });
480
738
  try {
481
- const value = await processResult(child, {
739
+ const processInput = {
482
740
  moduleUrl: entry.snapshot.moduleUrl,
483
741
  exportName: entry.exportName,
484
742
  payload: request.payload,
485
- });
743
+ };
744
+ const value = PROCESS_RUNTIME_BROKERS.has(context)
745
+ ? await processBrokeredResult(child, processInput, context)
746
+ : await processResult(child, processInput);
486
747
  await moduleSnapshot(entry.snapshot.physical, entry.snapshot.digest);
487
748
  return Object.freeze({
488
749
  value,
@@ -534,15 +795,21 @@ export function createEvolutionEvalProcessSupervisor({
534
795
  terminatedAt: revocation.terminatedAt,
535
796
  supervisorRevision,
536
797
  };
537
- return attest(
538
- core,
798
+ return persistEvidence(
799
+ "supervision",
800
+ await attest(
801
+ core,
802
+ EVOLUTION_EVAL_ATTESTATION_PURPOSES.supervisor,
803
+ attestSupervisor,
804
+ ),
539
805
  EVOLUTION_EVAL_ATTESTATION_PURPOSES.supervisor,
540
- attestSupervisor,
541
806
  );
542
807
  }
543
808
 
544
809
  const supervisor = Object.freeze({
545
810
  authorityDescriptor: Object.freeze(structuredClone(authorityDescriptor)),
811
+ childEvidenceStoreDescriptor:
812
+ durableEvidence === null ? null : durableEvidence.descriptor,
546
813
  invokeTarget,
547
814
  revokeTarget,
548
815
  verifyEnforcement,
@@ -3,10 +3,17 @@ import { types as utilTypes } from "node:util";
3
3
 
4
4
  import skillInvocationReceipt from "@chainlesschain/session-core/skill-invocation-receipt";
5
5
 
6
- const { verifySkillInvocationReceipt } = skillInvocationReceipt;
6
+ const {
7
+ inspectSkillInvocationReceiptCompatibility,
8
+ verifySkillInvocationReceipt,
9
+ } = skillInvocationReceipt;
7
10
 
8
- export const EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA =
11
+ export const LEGACY_EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA =
9
12
  "chainlesschain.evolution-workbench-metrics-snapshot/v1";
13
+ export const EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA =
14
+ "chainlesschain.evolution-workbench-metrics-snapshot/v2";
15
+ export const EVOLUTION_WORKBENCH_RECEIPT_COMPATIBILITY_POLICY =
16
+ "environment-bound-v2";
10
17
  export const EVOLUTION_WORKBENCH_METRICS_MAX_RECEIPTS = 100_000;
11
18
  export const EVOLUTION_WORKBENCH_METRICS_MAX_DELTA = 10_000;
12
19
  export const EVOLUTION_WORKBENCH_METRICS_MAX_HOT_RECEIPTS = 10_000;
@@ -39,6 +46,13 @@ const LEGACY_SNAPSHOT_KEYS = Object.freeze(
39
46
  const OUTCOME_SNAPSHOT_KEYS = Object.freeze(
40
47
  [...RETENTION_SNAPSHOT_KEYS, "outcomeHistoryComplete"].sort(),
41
48
  );
49
+ const COMPATIBILITY_SNAPSHOT_KEYS = Object.freeze(
50
+ [
51
+ ...OUTCOME_SNAPSHOT_KEYS,
52
+ "excludedReceiptCount",
53
+ "receiptCompatibilityPolicy",
54
+ ].sort(),
55
+ );
42
56
  const LEGACY_VERSION_KEYS = Object.freeze(
43
57
  [
44
58
  "blocked",
@@ -161,6 +175,9 @@ export function createEmptyEvolutionWorkbenchMetricsSnapshot(
161
175
  retainedReceiptCount: 0,
162
176
  retentionRootDigest: null,
163
177
  outcomeHistoryComplete: true,
178
+ excludedReceiptCount: 0,
179
+ receiptCompatibilityPolicy:
180
+ EVOLUTION_WORKBENCH_RECEIPT_COMPATIBILITY_POLICY,
164
181
  receiptDigests: [],
165
182
  versions: [],
166
183
  };
@@ -246,12 +263,17 @@ export function verifyEvolutionWorkbenchMetricsSnapshot(
246
263
  value,
247
264
  { tenantId, evolutionRunId, skillName },
248
265
  ) {
266
+ const exactCompatibility = exactRecord(value, COMPATIBILITY_SNAPSHOT_KEYS);
249
267
  const exactOutcome = exactRecord(value, OUTCOME_SNAPSHOT_KEYS);
250
268
  const exactRetention = exactRecord(value, RETENTION_SNAPSHOT_KEYS);
251
269
  const exactLegacy = exactRecord(value, LEGACY_SNAPSHOT_KEYS);
270
+ const currentSchema =
271
+ value?.schema === EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA;
272
+ const legacySchema =
273
+ value?.schema === LEGACY_EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA;
252
274
  if (
253
- (!exactOutcome && !exactRetention && !exactLegacy) ||
254
- value.schema !== EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA ||
275
+ ((!currentSchema || !exactCompatibility) &&
276
+ (!legacySchema || (!exactOutcome && !exactRetention && !exactLegacy))) ||
255
277
  !boundedString(value.tenantId) ||
256
278
  !boundedString(value.evolutionRunId) ||
257
279
  !boundedString(value.skillName) ||
@@ -280,6 +302,9 @@ export function verifyEvolutionWorkbenchMetricsSnapshot(
280
302
  }
281
303
  const retainedReceiptCount = value.retainedReceiptCount ?? 0;
282
304
  const retentionRootDigest = value.retentionRootDigest ?? null;
305
+ const excludedReceiptCount = exactCompatibility
306
+ ? value.excludedReceiptCount
307
+ : 0;
283
308
  if (
284
309
  !safeCount(retainedReceiptCount) ||
285
310
  (retainedReceiptCount === 0 && retentionRootDigest !== null) ||
@@ -290,18 +315,27 @@ export function verifyEvolutionWorkbenchMetricsSnapshot(
290
315
  if (
291
316
  value.revision === 0 &&
292
317
  (retainedReceiptCount !== 0 ||
318
+ excludedReceiptCount !== 0 ||
293
319
  value.receiptDigests.length !== 0 ||
294
320
  value.versions.length !== 0)
295
321
  ) {
296
322
  throw new TypeError("Workbench metrics genesis snapshot is invalid");
297
323
  }
298
324
  if (
299
- exactOutcome &&
325
+ (exactCompatibility || exactOutcome) &&
300
326
  (typeof value.outcomeHistoryComplete !== "boolean" ||
301
327
  (value.revision === 0 && value.outcomeHistoryComplete !== true))
302
328
  ) {
303
329
  throw new TypeError("Workbench metrics outcome coverage is invalid");
304
330
  }
331
+ if (
332
+ exactCompatibility &&
333
+ (!safeCount(excludedReceiptCount) ||
334
+ value.receiptCompatibilityPolicy !==
335
+ EVOLUTION_WORKBENCH_RECEIPT_COMPATIBILITY_POLICY)
336
+ ) {
337
+ throw new TypeError("Workbench metrics receipt compatibility is invalid");
338
+ }
305
339
  for (const receiptDigest of value.receiptDigests)
306
340
  digest(receiptDigest, "receipt digest");
307
341
  const versionDigests = new Set();
@@ -378,23 +412,20 @@ export function verifyEvolutionWorkbenchMetricsSnapshot(
378
412
  }
379
413
  }
380
414
  if (
381
- projectedReceiptCount !==
415
+ projectedReceiptCount + excludedReceiptCount !==
382
416
  retainedReceiptCount + value.receiptDigests.length
383
417
  ) {
384
418
  throw new Error("Workbench metrics receipt retention total is invalid");
385
419
  }
386
420
  if (
387
- (exactOutcome && versionLayout === "legacy") ||
388
- (!exactOutcome && versionLayout === "outcome")
421
+ ((exactCompatibility || exactOutcome) && versionLayout === "legacy") ||
422
+ (!exactCompatibility && !exactOutcome && versionLayout === "outcome")
389
423
  ) {
390
424
  throw new TypeError("Workbench metrics outcome layout is invalid");
391
425
  }
392
426
  const core = structuredClone(value);
393
427
  delete core.snapshotDigest;
394
- if (
395
- hash(EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA, core) !==
396
- value.snapshotDigest
397
- ) {
428
+ if (hash(value.schema, core) !== value.snapshotDigest) {
398
429
  throw new Error("Workbench metrics snapshot digest is invalid");
399
430
  }
400
431
  return freeze(structuredClone(value));
@@ -422,11 +453,19 @@ function nextSnapshot(previous, source, receipts, retention) {
422
453
  );
423
454
  const outcomeHistoryComplete =
424
455
  previous.outcomeHistoryComplete === true || previousReceiptCount === 0;
456
+ let excludedReceiptCount = previous.excludedReceiptCount;
425
457
  for (const receipt of receipts) {
426
458
  if (seen.has(receipt.receiptDigest)) {
427
459
  throw new Error("Workbench metrics source replayed a receipt");
428
460
  }
429
461
  seen.add(receipt.receiptDigest);
462
+ if (
463
+ !inspectSkillInvocationReceiptCompatibility(receipt)
464
+ .environmentBoundAttributionEligible
465
+ ) {
466
+ excludedReceiptCount += 1;
467
+ continue;
468
+ }
430
469
  for (const contentDigest of receipt.selectedSkillDigests) {
431
470
  const current = versions.get(contentDigest) ?? {
432
471
  contentDigest,
@@ -485,6 +524,9 @@ function nextSnapshot(previous, source, receipts, retention) {
485
524
  retainedReceiptCount: retention.retainedReceiptCount,
486
525
  retentionRootDigest: retention.retentionRootDigest,
487
526
  outcomeHistoryComplete,
527
+ excludedReceiptCount,
528
+ receiptCompatibilityPolicy:
529
+ EVOLUTION_WORKBENCH_RECEIPT_COMPATIBILITY_POLICY,
488
530
  receiptDigests: [...seen].sort(),
489
531
  versions: [...versions.values()].sort((left, right) =>
490
532
  left.contentDigest.localeCompare(right.contentDigest),
@@ -596,8 +638,8 @@ export class EvolutionWorkbenchMetricsOutcomeBackfiller {
596
638
  this.descriptor,
597
639
  );
598
640
  if (
599
- previous.outcomeHistoryComplete === true ||
600
- previous.versions.length === 0
641
+ previous.schema === EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA &&
642
+ previous.outcomeHistoryComplete === true
601
643
  ) {
602
644
  return freeze({ status: "already-complete", snapshot: previous });
603
645
  }
@@ -643,7 +685,6 @@ export class EvolutionWorkbenchMetricsOutcomeBackfiller {
643
685
  const verified = verifySkillInvocationReceipt(receipt);
644
686
  if (
645
687
  verified.evolutionRunId !== this.descriptor.evolutionRunId ||
646
- verified.attributionEligible !== true ||
647
688
  Date.parse(verified.completedAt) > Date.parse(previous.throughAt)
648
689
  ) {
649
690
  throw new Error("Workbench metrics history lacks exact attribution");
@@ -692,9 +733,19 @@ export class EvolutionWorkbenchMetricsOutcomeBackfiller {
692
733
  );
693
734
  }
694
735
  }
695
- const versions = projectReceiptHistory(receipts);
736
+ const eligibleReceipts = receipts.filter(
737
+ (receipt) =>
738
+ inspectSkillInvocationReceiptCompatibility(receipt)
739
+ .environmentBoundAttributionEligible,
740
+ );
741
+ const versions = projectReceiptHistory(eligibleReceipts);
742
+ const reconciliationVersions = projectReceiptHistory(
743
+ previous.schema === LEGACY_EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA
744
+ ? receipts
745
+ : eligibleReceipts,
746
+ );
696
747
  if (
697
- canonical(legacyProjection(versions)) !==
748
+ canonical(legacyProjection(reconciliationVersions)) !==
698
749
  canonical(legacyProjection(previous.versions))
699
750
  ) {
700
751
  throw new Error("Workbench metrics history does not reconcile");
@@ -711,6 +762,9 @@ export class EvolutionWorkbenchMetricsOutcomeBackfiller {
711
762
  retainedReceiptCount: previous.retainedReceiptCount ?? 0,
712
763
  retentionRootDigest: previous.retentionRootDigest ?? null,
713
764
  outcomeHistoryComplete: true,
765
+ excludedReceiptCount: receipts.length - eligibleReceipts.length,
766
+ receiptCompatibilityPolicy:
767
+ EVOLUTION_WORKBENCH_RECEIPT_COMPATIBILITY_POLICY,
714
768
  receiptDigests: previous.receiptDigests,
715
769
  versions,
716
770
  };
@@ -809,6 +863,15 @@ export class EvolutionWorkbenchMetricsAggregator {
809
863
  loaded.snapshot,
810
864
  this.descriptor,
811
865
  );
866
+ if (
867
+ previous.schema === LEGACY_EVOLUTION_WORKBENCH_METRICS_SNAPSHOT_SCHEMA
868
+ ) {
869
+ const error = new Error(
870
+ "Workbench metrics snapshot requires receipt compatibility backfill",
871
+ );
872
+ error.code = "CC_WORKBENCH_METRICS_COMPATIBILITY_BACKFILL_REQUIRED";
873
+ throw error;
874
+ }
812
875
  } else {
813
876
  throw new Error("Workbench metrics snapshot load is not authoritative");
814
877
  }
@@ -832,10 +895,7 @@ export class EvolutionWorkbenchMetricsAggregator {
832
895
  }
833
896
  const receipts = source.receipts.map((receipt) => {
834
897
  const verified = verifySkillInvocationReceipt(receipt);
835
- if (
836
- verified.evolutionRunId !== this.descriptor.evolutionRunId ||
837
- verified.attributionEligible !== true
838
- ) {
898
+ if (verified.evolutionRunId !== this.descriptor.evolutionRunId) {
839
899
  throw new Error("Workbench metrics receipt lacks exact attribution");
840
900
  }
841
901
  return verified;