chainlesschain 0.166.86 → 0.166.87

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 (182) 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-DZwiXAIh.js → AIOps-DdQjhXg9.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-aNzXoIJP.js → ActionButton-CuwA3hPA.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-ETQk4ZXt.js → Analytics-DTVXJSAC.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-D5oEbeEC.js → AppLayout-j06JBfEQ.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-ja48FAne.js → Artifacts-BFAK8LEW.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-DlN0YnDt.js → Audit-BiGxRpOf.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-CzvyNsRg.js → BackgroundAgents-B6uHaPkZ.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-DXgEC2MQ.js → Backup-BNAesB8q.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-D9XqejLx.js → BaseInput-BOuetfCd.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-BTwuYUlN.js → Chat-cVzo3m_D.js} +4 -4
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-0anIC2Wn.js → ChatBubbleRenderer-DZ2Ys-CI.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-CLuaQbDt.js → Checkbox-BaCTS-H8.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-KwQUZs8A.js → Codegen-CBE8NiYh.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-BCmROkzc.js → Col-C9wLiUTN.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-CXlUEHR4.js → Community-jdClBSIp.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-Dzx-lWI2.js → Compact-BIjauIlM.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CfXW82FF.js → Compliance-CZ-AoaNj.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DIISTRm2.js → Cowork-BbTKtDS4.js} +2 -2
  22. package/src/assets/web-panel/assets/{Cron-nyJ-KcFE.js → Cron-ImKdtwNi.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-Dtv1E4cV.js → Crosschain-B54GSHf5.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-BCTpektS.js → DID-BQt5WUzs.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-C1Q_m0So.js → Dashboard--gNOffif.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BrQ5_PPL.js → Dropdown-342A5YJw.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-DjoNlONP.js → EmailListRenderer-CtIZ3ZHd.js} +1 -1
  28. package/src/assets/web-panel/assets/{EvolutionSettings-DaGaE6bX.js → EvolutionSettings-CyZPoTio.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-nJDWBECt.js → FamilyGuardDashboard-B1MCkFEu.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-DhMUY_wG.js → Federation-DZWoERUy.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-CbONJPuc.js → FormItemContext-Onmb0mp3.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-CDdX4dX-.js → GenericCardRenderer-u1qhNNc7.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-DXbDVJdR.js → Git-BEowR1C5.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DbAfAvs1.js → Governance-BiYd3AAg.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-Dy-fGea2.js → Inference-CsC4Vjh5.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-DAxRpGUF.js → KnowledgeGraph-BXA7ikPM.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-5L1UCR8X.js → Logs-C9WoplQm.js} +2 -2
  38. package/src/assets/web-panel/assets/{MarkdownRenderer-u0FPafvT.js → MarkdownRenderer-DecEsXsy.js} +1 -1
  39. package/src/assets/web-panel/assets/{Marketplace-DUk_McDG.js → Marketplace-CCoJBfRL.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-B6PNsZ_p.js → McpTools-CzaOWBoA.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-BUUs8j5F.js → Memory-BPwh7u1-.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-pXRsgyuO.js → MobileBridge-Bk47v6z2.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-D7v-2Hwm.js → MobileProjects-D-CY--Sb.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-Deaj4faB.js → Mtc-ExVyAGlW.js} +4 -4
  45. package/src/assets/web-panel/assets/{MtcAudit-wUV0VUH1.js → MtcAudit-Rrw10csE.js} +5 -5
  46. package/src/assets/web-panel/assets/{Multisig-C67IIkts.js → Multisig-8TxxwxZZ.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-BCA_CWrW.js → NLProgramming-CNckjtnY.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-D9eu14hQ.js → Notes-C4j6cZTu.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-Cnd-J4LM.js → NotificationSettings-CchU8rWd.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-C4pHUuyZ.js → OrderTableRenderer-ZJBoyJ16.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-4YExAbnp.js → Organization-F0Je7EdZ.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-BF-wFuZz.js → Overflow-B2k-JA3u.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-CdiajqCT.js → P2P-yui9Xxe6.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-BkjfS6Th.js → PdhVaultBrowser-CegM7hT6.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-DrZ4D78_.js → Permissions-CSFL0uvh.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-lDc6OXjz.js → PersonalDataHub-BrMcd-vr.js} +5 -5
  57. package/src/assets/web-panel/assets/{Pipeline-DqDS9ON1.js → Pipeline-fzrliaVP.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-BMekZRZu.js → Privacy-BrkUjJ_g.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-LYS7NFvJ.js → ProjectInit-CF_QCsW9.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-CcJNHk9A.js → ProjectSettings-Duwrd8aC.js} +2 -2
  61. package/src/assets/web-panel/assets/{Projects-DrfAHgdF.js → Projects-B0dLVXzU.js} +1 -1
  62. package/src/assets/web-panel/assets/{Providers-aqsly9SR.js → Providers-Db8iS1xQ.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-ZWvR3zqg.js → QrScannerModal-CHbNzEQs.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-BT5CgsvW.js → QuickAsk-CIESMfeR.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-Cz8Dz2RN.js → Recommend-BTMbCMtR.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-BlxPVbtQ.js → RemoteSession-DavyK6J-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-B3VGBE-1.js → Reputation-BFKtMelA.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-Bwv7vSEA.js → Row-BI9AZUvw.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-DHI085r_.js → RssFeed-1nwXt8NY.js} +2 -2
  70. package/src/assets/web-panel/assets/{Search-DBler5T0.js → Search-Ck8PDYbk.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-BZdw43NW.js → Security-BgDqpCbq.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-Cslk5lUj.js → Services-DF8anXm4.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-Bur-C-25.js → Skeleton-CoHyY4ZX.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-v0zgLy0X.js → Skills-dOaD4Ztl.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-B1OWgQ51.js → Sla-XuOawvQY.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-CaBcEaV4.js → SpeechSettings-DFJ7nAiu.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-CBbG8L6J.js → SyncSettings-B2xYj-Pi.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-C7EjXrnN.js → Tasks-D_SzNTLi.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-VBBOZ1H5.js → Templates-BXFmKh7W.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-CtQTj7IF.js → Tenant-CRg2AXbd.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-DXVTQjnl.js → Terminal-DQgxnuep.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-BRIno0aN.js → TimelineRenderer-BrPQhQVc.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-uiiAfkYN.js → Tokens-RByy4USy.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-CPApN8o6.js → Trigger-pE3y8u73.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-T2jKVwCE.js → Trust-DhID9C33.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C2U_gbzP.js → UkeySign-CPxEPNBH.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-BCdlr3Kj.js → VideoEditing-ZD8DUxeQ.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-CWnjoSc1.js → Wallet-Br9JREEd.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-CqSbYqHq.js → WebAuthn-Cn-YacJg.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-Dr_I3jcr.js → WorkflowEditor-BTu0oqMp.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-Cg21FKdE.js → chat-CEjws_QF.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-CK85tY9e.js → colors-Bv2RNebW.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-m-XYPC7W.js → compact-item-gSc3EofP.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BmiEeNvs.js → createContext-kyFDaqWC.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-Dcc8pILJ.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-CCw4KAoc.js → hasIn-BuMWcjhx.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-ByVvAXdl.js → index--nrQmk8X.js} +1 -1
  98. package/src/assets/web-panel/assets/index-05NB95_V.js +1 -0
  99. package/src/assets/web-panel/assets/{index-BIOTRzaF.js → index-42PTBO7a.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-8KzhlvJ9.js → index-BCS5j4SQ.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-lhoexBDH.js → index-BSSIJ-rv.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-6jXf-Lln.js → index-BUOCcXou.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D7gS_TJl.js → index-Bg5jis0q.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BtvVupUL.js → index-C-LPpwe9.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BGb1j2z9.js → index-C56Drzol.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DpIy2HzE.js → index-C7Jo20JB.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cf5arJie.js → index-C9U9SjcT.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CBcgIWOe.js → index-CF3TjDNz.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-J81uvUMN.js → index-CMS3Mk93.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BGUYgc96.js → index-CNt2X-aK.js} +1 -1
  111. package/src/assets/web-panel/assets/index-Cb6q8wlI.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CN2xbLGz.js → index-Cj4RA7oA.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-D1sU5-XA.js → index-CkfvP2dN.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DmSgfXuz.js → index-Cm8K8Evn.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DMbrl43d.js → index-CvSuM_CB.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B7xJkhtJ.js → index-Czo_hw97.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BvjC3t35.js → index-D3m3EXbL.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DAlGVix-.js → index-DR561Sqc.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-B8IC9ZeZ.js → index-DRa4R7vv.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-yYmjkf38.js → index-DYKSuD02.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-Br9t_I1X.js → index-DYcPWVN9.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Bv90WEWa.js → index-DbVUA5l3.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BiVPFsat.js → index-DbkyTMj-.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-IskAKXhx.js → index-Dej4AGOz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CYEzWoyZ.js → index-EpxWlmip.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Br0ZNdu1.js → index-GpvWtvw3.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DIlGxS2W.js → index-NQ0c4hJ1.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-sWUmvT8H.js → index-OjZUHz5z.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-OIbfsi-o.js → index-U-ytt84A.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BUYyhYP6.js → index-_0bfDTDu.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DxRhnsEC.js → index-jmMAqBAm.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DI9GJFcn.js → index-nLemnBZ2.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BStyjmLG.js → index-q65c1kp8.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BHsiSoGY.js → index-sJ1F5Txa.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-BcfVHmFK.js → index-xfS_WO9b.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-Cc1XOmNe.js → initDefaultProps-B-wqiSu7.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BehsX88u.js → motion-BK4_B4MD.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-BPx2YsqY.js → move-BU2TgDDO.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-BSFJgFQA.js → mtc-parser-DA3E4_EX.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-DBN5KUeo.js → omit-CaHz1e_q.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-BDK1yZ-9.js → pickAttrs-NXZ19amf.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-C4rMmKNJ.js → placementArrow-BCXI9AHO.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-BoeoOnxX.js → responsiveObserve-DdlZ9tLk.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-BKlr1bl9.js → slide-DCZm_Vc4.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-Ky1apWPI.js → statusUtils-CuEULKQr.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-DxxR7uXk.js → styleChecker-Bo_UXG8x.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-DmsUqVe9.js → useFlexGapSupport-B9PaTcFH.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-CwkG7sOg.js → useFs-DwSTGdVR.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-CddgeEfF.js → usePersonalDataHub-FswSxnDC.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-C_-H8i4Y.js → vnode-EUztvYTj.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-aAsHUMNE.js → zoom-D41MAgV-.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +1 -1
  154. package/src/commands/eval.js +118 -18
  155. package/src/commands/memory.js +34 -15
  156. package/src/commands/sandbox.js +9 -0
  157. package/src/data/changelog.json +13 -0
  158. package/src/lib/causal-observability.js +6 -45
  159. package/src/lib/context-memory-kernel/durable-memory-port.js +49 -10
  160. package/src/lib/context-memory-kernel/memory-query-index.js +278 -0
  161. package/src/lib/context-memory-kernel/memory-service.js +17 -2
  162. package/src/lib/context-memory-kernel/segmented-memory-port.js +277 -9
  163. package/src/lib/eval/outcomes.js +20 -10
  164. package/src/lib/eval/runner.js +49 -5
  165. package/src/lib/eval/tasks.js +8 -3
  166. package/src/lib/eval/verify01-contracts.js +349 -0
  167. package/src/lib/eval/verify01-execution.js +605 -0
  168. package/src/lib/execution-support.js +58 -0
  169. package/src/lib/llm-pricing.js +98 -11
  170. package/src/lib/model-catalog-review.js +116 -0
  171. package/src/lib/model-context-catalog.js +23 -1
  172. package/src/lib/openai-responses.js +39 -0
  173. package/src/lib/process-execution-broker/index.js +8 -0
  174. package/src/lib/process-execution-broker/linux-subreaper-process.js +24 -2
  175. package/src/lib/process-execution-broker/process-ownership-journal.js +168 -7
  176. package/src/lib/process-execution-broker/process-ownership-quarantine.js +56 -1
  177. package/src/lib/process-execution-broker/process-recovery-cgroup.js +272 -0
  178. package/src/runtime/agent-core.js +9 -24
  179. package/src/runtime/permission-authority-host.js +14 -0
  180. package/src/assets/web-panel/assets/devWarning-CkMEODFC.js +0 -1
  181. package/src/assets/web-panel/assets/index-BjE5qaKn.js +0 -1
  182. package/src/assets/web-panel/assets/index-CsFH-2Zk.js +0 -1
@@ -132,9 +132,14 @@ function summarize(rows) {
132
132
  /** Read-only measurement. Declarations and local Eval files are not attestations. */
133
133
  export function buildOutcomeReport(
134
134
  { plan, history, observations = [], maintenance = null },
135
- { now = Date.now(), expectedPlanDigest } = {},
135
+ { now = Date.now(), expectedPlanDigest, expectedExecutionCommit } = {},
136
136
  ) {
137
137
  const samples = validateOutcomePlan(plan);
138
+ const executionCommit = expectedExecutionCommit ?? plan.commitSha;
139
+ assert(
140
+ /^[a-f0-9]{40}$/u.test(executionCommit),
141
+ "invalid execution source SHA",
142
+ );
138
143
  assert(Number.isFinite(now), "invalid report time");
139
144
  const planDigest = outcomeDigest(plan);
140
145
  assert(
@@ -182,10 +187,12 @@ export function buildOutcomeReport(
182
187
  else reasons.push(`missing_or_invalid_${key}`);
183
188
  }
184
189
  const observedAt = epoch(observation.observedAt);
185
- if (!(
186
- observedAt <= Math.min(now, epoch(plan.window.end)) &&
187
- observedAt - (row.elapsedMs ?? 0) >= epoch(plan.window.start)
188
- ))
190
+ if (
191
+ !(
192
+ observedAt <= Math.min(now, epoch(plan.window.end)) &&
193
+ observedAt - (row.elapsedMs ?? 0) >= epoch(plan.window.start)
194
+ )
195
+ )
189
196
  reasons.push("observation_outside_window");
190
197
  const run = runs.get(observation.runId);
191
198
  const stoppedBeforeTask =
@@ -210,13 +217,15 @@ export function buildOutcomeReport(
210
217
  Math.max(1, now - epoch(plan.window.start)),
211
218
  ).filter((reason) => reason !== "execution_not_successful");
212
219
  reasons.push(...integrity);
213
- if (run.label !== plan.commitSha) reasons.push("commit_mismatch");
220
+ if (run.label !== executionCommit) reasons.push("commit_mismatch");
214
221
  if (outcomeDigest(run.comparison) !== sample.comparisonDigest)
215
222
  reasons.push("comparison_mismatch");
216
- if (!(
217
- epoch(run.ranAt) >= epoch(plan.window.start) &&
218
- epoch(run.ranAt) <= epoch(plan.window.end)
219
- ))
223
+ if (
224
+ !(
225
+ epoch(run.ranAt) >= epoch(plan.window.start) &&
226
+ epoch(run.ranAt) <= epoch(plan.window.end)
227
+ )
228
+ )
220
229
  reasons.push("run_outside_window");
221
230
  }
222
231
  const result = run?.results?.find((item) => item?.id === sample.taskId);
@@ -310,6 +319,7 @@ export function buildOutcomeReport(
310
319
  improvementVerdict: "NOT_EVALUATED",
311
320
  planDigest,
312
321
  commitSha: plan.commitSha,
322
+ executionCommitSha: executionCommit,
313
323
  currency: plan.currency,
314
324
  window: plan.window,
315
325
  task: summarize(tasks),
@@ -20,11 +20,13 @@ import fs from "fs";
20
20
  import os from "os";
21
21
  import path from "path";
22
22
  import crypto from "crypto";
23
+ import { performance } from "node:perf_hooks";
23
24
 
24
25
  export const _deps = {
25
26
  mkdtempSync: fs.mkdtempSync,
26
27
  rmSync: fs.rmSync,
27
28
  now: () => Date.now(),
29
+ monotonicNow: () => performance.now(),
28
30
  };
29
31
 
30
32
  /**
@@ -100,6 +102,26 @@ export async function runEvalSuite(tasks, opts = {}) {
100
102
  const recorder = opts.recorder || null;
101
103
  for (const task of tasks) {
102
104
  const started = _deps.now();
105
+ const deadline =
106
+ task?.totalTimeoutMs === undefined
107
+ ? null
108
+ : _deps.monotonicNow() + task.totalTimeoutMs;
109
+ let phase = "setup";
110
+ const budget = {
111
+ remainingMs(stage = phase) {
112
+ if (deadline === null) return task.timeoutMs;
113
+ const remaining = Math.floor(deadline - _deps.monotonicNow());
114
+ if (remaining <= 0) {
115
+ const error = new Error(
116
+ `task total time budget exhausted during ${stage}`,
117
+ );
118
+ error.code = "EVAL_TOTAL_TIMEOUT";
119
+ error.phase = stage;
120
+ throw error;
121
+ }
122
+ return remaining;
123
+ },
124
+ };
103
125
  let dir = null;
104
126
  const rec = {
105
127
  id: task?.id || "(unnamed)",
@@ -132,17 +154,24 @@ export async function runEvalSuite(tasks, opts = {}) {
132
154
  }
133
155
  dir = _deps.mkdtempSync(path.join(base, `cc-eval-${task.id}-`));
134
156
  if (typeof task.setup === "function") {
135
- await task.setup(dir);
157
+ await task.setup(dir, budget);
136
158
  }
137
159
  // Baseline AFTER setup, BEFORE the agent — so the diff is exactly the
138
160
  // agent's edits (not the task's starting files).
139
- const before = snapshotWorkspace(dir);
161
+ phase = "baseline";
162
+ const capture = task.snapshotWorkspace || snapshotWorkspace;
163
+ const before = capture(dir, budget, "baseline");
164
+ budget.remainingMs();
140
165
  let agentResult;
166
+ phase = "agent";
141
167
  try {
142
168
  agentResult = await runAgent({
143
169
  prompt: task.prompt,
144
170
  cwd: dir,
145
- timeoutMs: task.timeoutMs,
171
+ timeoutMs: budget.remainingMs(),
172
+ ...(task.costBudgetUsd === undefined
173
+ ? {}
174
+ : { costBudgetUsd: task.costBudgetUsd }),
146
175
  });
147
176
  } catch (agentErr) {
148
177
  // An agent crash is a task failure, not a harness failure — record it
@@ -159,6 +188,8 @@ export async function runEvalSuite(tasks, opts = {}) {
159
188
  rec.totalCostUsd = Number.isFinite(agentResult?.totalCostUsd)
160
189
  ? agentResult.totalCostUsd
161
190
  : null;
191
+ task.recordExecution?.(agentResult);
192
+ budget.remainingMs();
162
193
  if (agentResult?.evaluationMetrics !== undefined) {
163
194
  rec.evaluationMetrics = agentResult.evaluationMetrics;
164
195
  }
@@ -169,7 +200,12 @@ export async function runEvalSuite(tasks, opts = {}) {
169
200
  // workspace themselves). `unrelatedChanges` = files touched outside the
170
201
  // task's declared legitimate surface; null when the task doesn't declare
171
202
  // `expectedFiles` (→ excluded from the suite's 无关改动率).
172
- const changed = diffSnapshots(before, snapshotWorkspace(dir));
203
+ phase = "after-snapshot";
204
+ const changed = diffSnapshots(
205
+ before,
206
+ capture(dir, budget, "after-snapshot"),
207
+ );
208
+ budget.remainingMs();
173
209
  rec.changedFiles = changed;
174
210
  if (Array.isArray(task.expectedFiles)) {
175
211
  const expected = new Set(
@@ -179,7 +215,9 @@ export async function runEvalSuite(tasks, opts = {}) {
179
215
  } else {
180
216
  rec.unrelatedChanges = null; // not measured
181
217
  }
182
- const verdict = await task.check(dir, agentResult);
218
+ phase = "check";
219
+ const verdict = await task.check(dir, agentResult, budget);
220
+ budget.remainingMs();
183
221
  rec.artifactCheckPassed = verdict?.pass === true;
184
222
  // A useful artifact survives a provider/transport failure, but it is not
185
223
  // evidence that the Agent completed the task successfully.
@@ -188,6 +226,12 @@ export async function runEvalSuite(tasks, opts = {}) {
188
226
  } catch (err) {
189
227
  // A harness-level error (bad task def / setup threw) — mark failed.
190
228
  rec.error = rec.error || err.message;
229
+ rec.failurePhase = err.phase || phase;
230
+ task.recordFailure?.({
231
+ phase: rec.failurePhase,
232
+ code: err.code || null,
233
+ error: err.message,
234
+ });
191
235
  rec.pass = false;
192
236
  } finally {
193
237
  rec.ms = _deps.now() - started;
@@ -12,6 +12,7 @@
12
12
  import fs from "fs";
13
13
  import path from "path";
14
14
  import executionBroker from "../process-execution-broker/index.js";
15
+ import { loadVerify01Suite, VERIFY01_SUITES } from "./verify01-execution.js";
15
16
 
16
17
  export const _deps = {
17
18
  execFileSync: (...args) => executionBroker.execFileSync(...args),
@@ -634,8 +635,12 @@ export const BUILTIN_TASKS = [
634
635
  },
635
636
  ];
636
637
 
637
- /** Look up a suite by name (only "builtin" for now). */
638
- export function getSuite(name = "builtin") {
638
+ /** Frozen project suites require explicit plan/reviewer/checkout bindings. */
639
+ export function getSuite(name = "builtin", options = {}) {
639
640
  if (name === "builtin" || !name) return BUILTIN_TASKS;
640
- throw new Error(`unknown eval suite: "${name}" (available: builtin)`);
641
+ if (VERIFY01_SUITES.includes(name))
642
+ return loadVerify01Suite(options.verify01);
643
+ throw new Error(
644
+ `unknown eval suite: "${name}" (available: builtin, ${VERIFY01_SUITES.join(", ")})`,
645
+ );
641
646
  }
@@ -0,0 +1,349 @@
1
+ import fs from "node:fs";
2
+ import {
3
+ createEvalComparison,
4
+ EVAL_EXECUTION_PROTOCOL,
5
+ evalDigest,
6
+ evalHistoryRecordIssues,
7
+ } from "./evidence.js";
8
+ import {
9
+ buildOutcomeReport,
10
+ outcomeDigest,
11
+ validateOutcomePlan,
12
+ } from "./outcomes.js";
13
+ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
14
+ const MAX_BYTES = 16 * 1024 * 1024;
15
+ function requireValue(condition, message) {
16
+ if (!condition) throw new Error(message);
17
+ }
18
+ function index(rows, key, label) {
19
+ requireValue(Array.isArray(rows), `${label} must be an array`);
20
+ const result = new Map();
21
+ for (const row of rows) {
22
+ requireValue(
23
+ typeof row?.[key] === "string" &&
24
+ row[key].length > 0 &&
25
+ !result.has(row[key]),
26
+ `${label}: missing or duplicate ${key}`,
27
+ );
28
+ result.set(row[key], row);
29
+ }
30
+ return result;
31
+ }
32
+ function relativeFile(value) {
33
+ requireValue(
34
+ typeof value === "string" &&
35
+ value.length > 0 &&
36
+ !/[\\:*?<>|"\u0000]/u.test(value) &&
37
+ !value.startsWith("/") &&
38
+ value.split("/").every((part) => part && !/[. ]$/u.test(part)),
39
+ "review paths must be exact relative files",
40
+ );
41
+ return value;
42
+ }
43
+ function readBytes(file) {
44
+ const descriptor = fs.openSync(file, "r");
45
+ try {
46
+ const before = fs.fstatSync(descriptor, { bigint: true });
47
+ requireValue(
48
+ before.isFile() && before.size <= BigInt(MAX_BYTES),
49
+ "input must be a regular file within 16 MiB",
50
+ );
51
+ const bytes = Buffer.alloc(Number(before.size) + 1);
52
+ let count = 0;
53
+ while (count < bytes.length) {
54
+ const size = fs.readSync(
55
+ descriptor,
56
+ bytes,
57
+ count,
58
+ bytes.length - count,
59
+ null,
60
+ );
61
+ if (!size) break;
62
+ count += size;
63
+ }
64
+ const after = fs.fstatSync(descriptor, { bigint: true });
65
+ requireValue(
66
+ count === Number(before.size) &&
67
+ ["dev", "ino", "size", "mtimeNs", "ctimeNs"].every(
68
+ (key) => before[key] === after[key],
69
+ ),
70
+ "input changed during read",
71
+ );
72
+ return bytes.subarray(0, count);
73
+ } finally {
74
+ fs.closeSync(descriptor);
75
+ }
76
+ }
77
+ const readJson = (file) => JSON.parse(readBytes(file).toString("utf8"));
78
+
79
+ export function validateVerify01Bundle({
80
+ plan,
81
+ catalog,
82
+ bindings,
83
+ expectedPlanDigest,
84
+ }) {
85
+ const samples = validateOutcomePlan(plan);
86
+ requireValue(
87
+ DIGEST.test(expectedPlanDigest || "") &&
88
+ outcomeDigest(plan) === expectedPlanDigest,
89
+ "frozen plan digest mismatch",
90
+ );
91
+ requireValue(
92
+ catalog?.schema === "chainlesschain.verify01-task-catalog/v1" &&
93
+ catalog.projectCommit === plan.commitSha,
94
+ "catalog project SHA mismatch",
95
+ );
96
+ const tasks = index(catalog.tasks, "id", "catalog tasks");
97
+ requireValue(
98
+ tasks.size === 36 && samples.size === 45,
99
+ "VERIFY-01 requires all 36 tasks and 45 samples",
100
+ );
101
+ const taskSamples = [...samples.values()].filter(
102
+ (sample) => sample.kind === "task",
103
+ );
104
+ requireValue(
105
+ taskSamples.length === 36 &&
106
+ new Set(taskSamples.map((sample) => sample.taskId)).size === 36,
107
+ "task population is incomplete or duplicated",
108
+ );
109
+ for (const task of tasks.values()) {
110
+ requireValue(
111
+ task.status === "NOT_RUN" &&
112
+ typeof task.prompt === "string" &&
113
+ task.prompt.length > 0,
114
+ "frozen task definition changed",
115
+ );
116
+ requireValue(
117
+ Array.isArray(task.sourcePaths) &&
118
+ Array.isArray(task.expectedFiles) &&
119
+ task.expectedFiles.length > 0,
120
+ "task paths are required",
121
+ );
122
+ [...task.sourcePaths, ...task.expectedFiles].forEach(relativeFile);
123
+ }
124
+ for (const sample of samples.values()) {
125
+ requireValue(
126
+ tasks.has(sample.taskId),
127
+ "sample task is absent from catalog",
128
+ );
129
+ const comparison = bindings?.comparisons?.[sample.stratum];
130
+ requireValue(
131
+ comparison &&
132
+ outcomeDigest(comparison) === sample.comparisonDigest &&
133
+ comparison.corpusDigest === outcomeDigest(catalog),
134
+ "catalog/comparison digest mismatch",
135
+ );
136
+ const rebuilt = createEvalComparison({
137
+ ...comparison,
138
+ context: comparison.declared,
139
+ ...comparison.runtime,
140
+ });
141
+ requireValue(
142
+ outcomeDigest(rebuilt) === outcomeDigest(comparison),
143
+ "invalid frozen comparison",
144
+ );
145
+ }
146
+ return { tasks, samples };
147
+ }
148
+
149
+ /** Review is operator configuration, not proof of independent human review. */
150
+ export function validateVerify01Review(
151
+ bundle,
152
+ { review, expectedReviewDigest, projectCommit, readReviewedFile },
153
+ ) {
154
+ const { tasks, samples } = validateVerify01Bundle(bundle);
155
+ requireValue(
156
+ DIGEST.test(expectedReviewDigest || "") &&
157
+ outcomeDigest(review) === expectedReviewDigest,
158
+ "review digest mismatch",
159
+ );
160
+ requireValue(
161
+ projectCommit === bundle.catalog.projectCommit &&
162
+ review.projectCommit === projectCommit,
163
+ "review/project SHA mismatch",
164
+ );
165
+ requireValue(
166
+ review.planDigest === bundle.expectedPlanDigest &&
167
+ review.catalogDigest === outcomeDigest(bundle.catalog),
168
+ "review frozen identity mismatch",
169
+ );
170
+ const reviewed = index(review.tasks, "taskId", "review tasks");
171
+ requireValue(
172
+ reviewed.size === tasks.size &&
173
+ [...tasks.keys()].every((id) => reviewed.has(id)),
174
+ "review tasks omitted or outside catalog",
175
+ );
176
+ const protectedPaths = new Set();
177
+ for (const [id, entry] of reviewed) {
178
+ const task = tasks.get(id);
179
+ requireValue(
180
+ Array.isArray(entry.allowedChangedPaths) &&
181
+ new Set(entry.allowedChangedPaths).size ===
182
+ entry.allowedChangedPaths.length,
183
+ "review allowed paths missing or duplicated",
184
+ );
185
+ const declared = new Set([...task.expectedFiles, ...task.sourcePaths]);
186
+ requireValue(
187
+ task.expectedFiles.every((file) =>
188
+ entry.allowedChangedPaths.includes(file),
189
+ ),
190
+ "review omits expected deliverable",
191
+ );
192
+ for (const file of entry.allowedChangedPaths)
193
+ requireValue(
194
+ declared.has(relativeFile(file)),
195
+ "review expands task change surface",
196
+ );
197
+ for (const kind of ["setup", "check"]) {
198
+ const artifact = entry[kind];
199
+ relativeFile(artifact?.path);
200
+ requireValue(
201
+ DIGEST.test(artifact?.digest || ""),
202
+ `review ${kind} digest required`,
203
+ );
204
+ requireValue(
205
+ typeof readReviewedFile === "function" &&
206
+ evalDigest(readReviewedFile(artifact.path)) === artifact.digest,
207
+ `reviewed ${kind} file changed`,
208
+ );
209
+ protectedPaths.add(artifact.path.toLowerCase());
210
+ }
211
+ }
212
+ for (const entry of reviewed.values())
213
+ requireValue(
214
+ entry.allowedChangedPaths.every(
215
+ (file) => !protectedPaths.has(file.toLowerCase()),
216
+ ),
217
+ "reviewed evaluator must not be an allowed task edit",
218
+ );
219
+ return { tasks, samples, reviewed };
220
+ }
221
+
222
+ /** Validate imported existing Eval records; never mint terminal/provider facts. */
223
+ export function validateVerify01Collection(
224
+ bundle,
225
+ preparation,
226
+ { sampleIds, history, observations, sourceCommit, now = Date.now() },
227
+ ) {
228
+ const { samples, reviewed } = validateVerify01Review(bundle, preparation);
229
+ requireValue(
230
+ /^[a-f0-9]{40}$/u.test(sourceCommit || ""),
231
+ "collection requires an independently supplied tested source SHA",
232
+ );
233
+ requireValue(
234
+ Array.isArray(sampleIds) &&
235
+ sampleIds.length > 0 &&
236
+ new Set(sampleIds).size === sampleIds.length &&
237
+ sampleIds.every((id) => samples.has(id)),
238
+ "selected samples missing, duplicate or outside plan",
239
+ );
240
+ const observed = index(observations, "sampleId", "observations");
241
+ requireValue(
242
+ observed.size === sampleIds.length &&
243
+ sampleIds.every((id) => observed.has(id)),
244
+ "selected observations omitted or unexpected",
245
+ );
246
+ requireValue(
247
+ Array.isArray(history?.issues) && history.issues.length === 0,
248
+ "Eval history contains parse issues",
249
+ );
250
+ const runs = index(history?.runs, "runId", "Eval history");
251
+ const used = new Set();
252
+ const report = buildOutcomeReport(
253
+ { plan: bundle.plan, history, observations },
254
+ {
255
+ now,
256
+ expectedPlanDigest: bundle.expectedPlanDigest,
257
+ expectedExecutionCommit: sourceCommit,
258
+ },
259
+ );
260
+ for (const id of sampleIds) {
261
+ const sample = samples.get(id);
262
+ const observation = observed.get(id);
263
+ if (
264
+ sample.kind === "first-run" &&
265
+ observation.runId === null &&
266
+ observation.firstRun?.stages?.tool?.passed === false
267
+ ) {
268
+ const row = report.rows.find((item) => item.sampleId === id);
269
+ const failureReasons = new Set([
270
+ "task_not_successful",
271
+ "first_run_not_completed",
272
+ "budget_exceeded",
273
+ "manual_repair",
274
+ ...(observation.cost === null ? ["missing_or_invalid_cost"] : []),
275
+ ]);
276
+ requireValue(
277
+ row.failureCause &&
278
+ row.reasons.every((reason) => failureReasons.has(reason)),
279
+ "invalid first-run early-stop evidence",
280
+ );
281
+ continue;
282
+ }
283
+ const run = runs.get(observation.runId);
284
+ requireValue(
285
+ run && run.label === sourceCommit,
286
+ "collected run SHA mismatch or missing run",
287
+ );
288
+ requireValue(
289
+ outcomeDigest(run.comparison) === sample.comparisonDigest,
290
+ "collected comparison mismatch",
291
+ );
292
+ const issues = evalHistoryRecordIssues(
293
+ run,
294
+ now,
295
+ Math.max(1, now - Date.parse(bundle.plan.window.start)),
296
+ ).filter((issue) => issue !== "execution_not_successful");
297
+ requireValue(
298
+ issues.length === 0,
299
+ `invalid Eval record: ${issues.join(",")}`,
300
+ );
301
+ const result = run.results.find((row) => row.id === sample.taskId);
302
+ requireValue(
303
+ result?.executionEvidence?.terminalVerified === true &&
304
+ result.executionEvidence.protocol === EVAL_EXECUTION_PROTOCOL,
305
+ "collected task has no verified terminal",
306
+ );
307
+ const key = JSON.stringify([run.runId, sample.taskId]);
308
+ requireValue(!used.has(key), "task execution reused across samples");
309
+ used.add(key);
310
+ const cost = result.totalCostUsd;
311
+ requireValue(
312
+ (cost === null || (Number.isFinite(cost) && cost >= 0)) &&
313
+ observation.cost === cost,
314
+ "unknown or mismatched cost must not become zero",
315
+ );
316
+ requireValue(
317
+ Array.isArray(result.changedFiles) &&
318
+ new Set(result.changedFiles).size === result.changedFiles.length,
319
+ "changed-file inventory missing or duplicated",
320
+ );
321
+ const allowed = reviewed.get(sample.taskId).allowedChangedPaths;
322
+ requireValue(
323
+ result.changedFiles.every((file) => allowed.includes(relativeFile(file))),
324
+ "collected task changed an unreviewed path",
325
+ );
326
+ requireValue(
327
+ Array.isArray(result.unrelatedChanges) &&
328
+ result.unrelatedChanges.length === 0,
329
+ "collected task has unreviewed edits",
330
+ );
331
+ }
332
+ for (const run of runs.values())
333
+ for (const result of run.results)
334
+ requireValue(
335
+ used.has(JSON.stringify([run.runId, result.id])),
336
+ "unbound Eval result outside selected samples",
337
+ );
338
+ return {
339
+ ...report,
340
+ executionSource: {
341
+ declaredCommit: sourceCommit,
342
+ declarationOnly: true,
343
+ identityVerified: false,
344
+ },
345
+ projectCommit: preparation.projectCommit,
346
+ };
347
+ }
348
+
349
+ export { requireValue, relativeFile, readBytes, readJson };