@iowarp/clio-coder 0.4.8 → 0.4.9

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 (513) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +7 -6
  3. package/dist/{acp-JWPQZM2D.js → acp-ZWZCPS2A.js} +13 -13
  4. package/dist/{agents-4GCDIRVX.js → agents-LYSOWZUE.js} +53 -52
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-SYAKTDQE.js → auth-WBQGKWQ5.js} +27 -27
  7. package/dist/{background-OW67WMYR.js → background-BUMOBAQN.js} +4 -4
  8. package/dist/{builtins-TKS63VNV.js → builtins-ODRJOEDI.js} +7 -7
  9. package/dist/{chunk-JLBVCROW.js → chunk-2DRRZ57Q.js} +33 -24
  10. package/dist/chunk-2JBZYUPY.js +105 -0
  11. package/dist/chunk-2KUBKL63.js +336 -0
  12. package/dist/{chunk-K45LHSCI.js → chunk-2VBWFXYE.js} +7 -3
  13. package/dist/{chunk-XTLJDC2X.js → chunk-2X2R3UTH.js} +23 -18
  14. package/dist/{chunk-5HULHKT2.js → chunk-37LW32LZ.js} +5 -5
  15. package/dist/{chunk-W7KNI3F5.js → chunk-3AND2EFU.js} +5 -5
  16. package/dist/{chunk-36XSBPXL.js → chunk-3RDHGNU7.js} +95 -27
  17. package/dist/{chunk-BIY22UUK.js → chunk-3SUDBGEI.js} +11 -10
  18. package/dist/{chunk-3IQOZRQ6.js → chunk-3TQN67I2.js} +7 -7
  19. package/dist/{chunk-KWJXCL2X.js → chunk-3U4BL2EV.js} +3 -3
  20. package/dist/{chunk-RBES4TCZ.js → chunk-3UQADNG2.js} +3 -3
  21. package/dist/{chunk-V4ZKOKRB.js → chunk-434LRQ6Z.js} +61 -53
  22. package/dist/{chunk-MWMW53WW.js → chunk-4ATBOFRP.js} +649 -193
  23. package/dist/{chunk-QGIC5SX5.js → chunk-4DNL43EZ.js} +3 -3
  24. package/dist/{chunk-GVU4CXPJ.js → chunk-4HFJKRGZ.js} +113 -54
  25. package/dist/{chunk-5A6XR3RJ.js → chunk-555E2WVV.js} +16 -2
  26. package/dist/{chunk-LZDLYSUN.js → chunk-5RTEFNBP.js} +3 -3
  27. package/dist/{chunk-HMGAKB7E.js → chunk-64XJW7NT.js} +15 -15
  28. package/dist/{chunk-EXKUF426.js → chunk-7FBCRWVT.js} +280 -280
  29. package/dist/{chunk-K3W6BF5C.js → chunk-7JSOSVLP.js} +2 -2
  30. package/dist/{chunk-WFTSK7N3.js → chunk-7N3OLLSL.js} +4 -4
  31. package/dist/{chunk-JRA6OBHY.js → chunk-A6DULIMH.js} +17 -5
  32. package/dist/{chunk-R5NRX5N4.js → chunk-AB3QXXBC.js} +2 -2
  33. package/dist/chunk-ACCECAH4.js +49 -0
  34. package/dist/{chunk-GJBJHJNY.js → chunk-AM6CEP2K.js} +5 -5
  35. package/dist/{chunk-MUXNDNMZ.js → chunk-AY4XE6GN.js} +19 -13
  36. package/dist/{chunk-MATCRH3M.js → chunk-BBA2TAWV.js} +9 -9
  37. package/dist/{chunk-PMUUAABD.js → chunk-BMNVVKEW.js} +9 -9
  38. package/dist/{chunk-TOPICHGR.js → chunk-CTGZCEI6.js} +2 -2
  39. package/dist/{chunk-L75H5B3B.js → chunk-DIAJYJYG.js} +2 -2
  40. package/dist/{chunk-JIMWEYWO.js → chunk-EHZRAB4U.js} +2 -2
  41. package/dist/{chunk-YXANQGCX.js → chunk-EM2DIQAJ.js} +6 -6
  42. package/dist/{chunk-JCVIL6TY.js → chunk-ETF4ROKH.js} +4 -4
  43. package/dist/{chunk-5W4FRA5Q.js → chunk-F2YM3JY4.js} +483 -253
  44. package/dist/{chunk-YGIV24MF.js → chunk-FEBQWHJT.js} +21 -16
  45. package/dist/{chunk-PGEFOTJB.js → chunk-FPS4R2RN.js} +5 -4
  46. package/dist/{chunk-XC5POIL4.js → chunk-G5R53COU.js} +1 -1
  47. package/dist/chunk-GHXGMFQ5.js +40 -0
  48. package/dist/{chunk-QLKCCC2J.js → chunk-GJDRMBDI.js} +14 -14
  49. package/dist/{chunk-2ZWLMA3T.js → chunk-GREYLTZ5.js} +7 -7
  50. package/dist/{chunk-YXFKLMX2.js → chunk-H2WSCZZT.js} +22 -6
  51. package/dist/{chunk-FNVPQQYT.js → chunk-H6IUCY6Q.js} +2 -2
  52. package/dist/{chunk-5C2OQHLR.js → chunk-H72DCH3E.js} +92 -203
  53. package/dist/{chunk-JYKUMHCQ.js → chunk-H7TXJR23.js} +21 -21
  54. package/dist/chunk-HBJQQTKM.js +40 -0
  55. package/dist/chunk-HCVKSGNZ.js +990 -0
  56. package/dist/{chunk-ARRUMZ7X.js → chunk-I47EJPYL.js} +3 -3
  57. package/dist/{chunk-YKIIWURD.js → chunk-IALGWTLO.js} +3 -3
  58. package/dist/{chunk-FB3KTE2J.js → chunk-IALZJE37.js} +4 -4
  59. package/dist/{chunk-RAUOKUZV.js → chunk-IC7JXLOM.js} +15 -10
  60. package/dist/{chunk-LLCGGVSW.js → chunk-IOSVTTCD.js} +7 -7
  61. package/dist/{chunk-DBREN25X.js → chunk-IPTPMLA6.js} +8 -3
  62. package/dist/{chunk-V552WL53.js → chunk-IZZI3SKQ.js} +3 -67
  63. package/dist/{chunk-UDAK6GR2.js → chunk-JIYWMQZ5.js} +2 -2
  64. package/dist/{chunk-O3HSB2YL.js → chunk-JKU34ACI.js} +2 -2
  65. package/dist/{chunk-6X7VOCDY.js → chunk-JTR3VSV3.js} +3 -3
  66. package/dist/{chunk-O2QJDRWP.js → chunk-JU6MAMRJ.js} +4 -4
  67. package/dist/chunk-JURMQWVJ.js +15 -0
  68. package/dist/{chunk-STC6CWUZ.js → chunk-K3XN4LZ4.js} +5 -5
  69. package/dist/{chunk-ATB3Q7YO.js → chunk-KIVFXGBM.js} +27 -2
  70. package/dist/{chunk-WJWNZXRM.js → chunk-KOAHT3N2.js} +2 -2
  71. package/dist/chunk-KP5BPXR3.js +73 -0
  72. package/dist/{chunk-K53E2PTW.js → chunk-KRJQG47M.js} +3 -3
  73. package/dist/{chunk-IILXVWJY.js → chunk-KW6OJ7IY.js} +19 -21
  74. package/dist/{chunk-A46ILRS2.js → chunk-L3NBWLSN.js} +4 -4
  75. package/dist/{chunk-2U2U5POA.js → chunk-L4RUTLRL.js} +5 -5
  76. package/dist/{chunk-QYSAZMSH.js → chunk-LGTVWPRN.js} +2 -2
  77. package/dist/{chunk-KGP3UQGJ.js → chunk-LSQW6KZO.js} +5 -5
  78. package/dist/{chunk-P4JS3MH5.js → chunk-LWJYOHT3.js} +8 -8
  79. package/dist/{chunk-U3TPUXOQ.js → chunk-M6YLF66Z.js} +74 -40
  80. package/dist/{chunk-5D2FNBMG.js → chunk-MJ4QEJVT.js} +2 -2
  81. package/dist/{chunk-RM3XJX7P.js → chunk-MO65K5CH.js} +5 -5
  82. package/dist/{chunk-H5DPSUBB.js → chunk-MTOZEQHL.js} +3 -3
  83. package/dist/{chunk-6R5MBXBJ.js → chunk-NBPA5QM6.js} +2 -2
  84. package/dist/{chunk-H77XBUBM.js → chunk-NMBEW4PP.js} +3 -3
  85. package/dist/{chunk-QWUSS2QP.js → chunk-NPLLK3HO.js} +67 -87
  86. package/dist/{chunk-K5UJD6MM.js → chunk-NSYGPIVW.js} +5 -5
  87. package/dist/{context-EZZPT2ZV.js → chunk-NXTV5OI5.js} +30 -84
  88. package/dist/{chunk-F7Y6QTPL.js → chunk-NYDG4QP4.js} +4 -4
  89. package/dist/{chunk-PFZJMXIY.js → chunk-OA2GDACN.js} +2 -2
  90. package/dist/{chunk-Q32C6AWI.js → chunk-PJI57EC6.js} +4 -4
  91. package/dist/{chunk-EFXMQYI6.js → chunk-PJJBUGMR.js} +52 -52
  92. package/dist/{chunk-ICYIUNO4.js → chunk-PNJE7JPS.js} +18 -3
  93. package/dist/chunk-PP23PZEV.js +1347 -0
  94. package/dist/chunk-PPIFDSBK.js +409 -0
  95. package/dist/{chunk-RFULVPBX.js → chunk-PTFISXQO.js} +6 -5
  96. package/dist/{chunk-JV25I7ID.js → chunk-QB33Z5S7.js} +5 -5
  97. package/dist/{chunk-D55WO5J7.js → chunk-QGNII5VC.js} +8 -8
  98. package/dist/{chunk-RKFNU5UA.js → chunk-QI72X67S.js} +104 -27
  99. package/dist/chunk-QKHZZFKH.js +98 -0
  100. package/dist/{chunk-5UG6EZI3.js → chunk-RDKX2PME.js} +4 -4
  101. package/dist/{chunk-B5ZTR6KZ.js → chunk-RL7LJYN4.js} +1 -1
  102. package/dist/{chunk-BE4I3UJ2.js → chunk-RQROVOV3.js} +15 -13
  103. package/dist/{chunk-TEHVMHOK.js → chunk-S34A7BSP.js} +3 -3
  104. package/dist/{chunk-4P6M2TTE.js → chunk-SJETVJHX.js} +2 -2
  105. package/dist/{chunk-OPC4DQD6.js → chunk-SJMNU4ZS.js} +2 -2
  106. package/dist/{chunk-2JSCCEKO.js → chunk-SLLG2G44.js} +2 -2
  107. package/dist/{chunk-EPYATQMG.js → chunk-SQAZN2V3.js} +42 -16
  108. package/dist/{chunk-E2NSPYLC.js → chunk-SQBT46OF.js} +5 -5
  109. package/dist/{chunk-WTZVSMQZ.js → chunk-TCUOGIL2.js} +5 -5
  110. package/dist/{chunk-RRZFRIJP.js → chunk-TIWPKCVO.js} +5 -5
  111. package/dist/{chunk-QLAGXTTV.js → chunk-UIU7MGZ3.js} +5 -1
  112. package/dist/{chunk-WLHX3MM5.js → chunk-V4XJWDHR.js} +21 -11
  113. package/dist/{chunk-PJ5H5B7A.js → chunk-VPWGADBG.js} +18 -18
  114. package/dist/{chunk-GEYX2NZ5.js → chunk-VWFCAK34.js} +6 -6
  115. package/dist/{chunk-44U2OUSM.js → chunk-W72LLZAV.js} +2 -2
  116. package/dist/{chunk-ORRNGQDV.js → chunk-WGRDABW7.js} +4 -4
  117. package/dist/{chunk-RNLAPBJL.js → chunk-XFLSL7BT.js} +2 -2
  118. package/dist/{chunk-2SXGG2IV.js → chunk-XJZEDCNT.js} +6 -6
  119. package/dist/{chunk-UB33F3YW.js → chunk-XLLEL3K7.js} +5 -5
  120. package/dist/{chunk-2GPGAE5W.js → chunk-XNIZBOFV.js} +15 -1
  121. package/dist/{chunk-WS4FOGLY.js → chunk-XNZWWDC3.js} +2 -2
  122. package/dist/{chunk-P7GTE4FX.js → chunk-XRECG65F.js} +2 -2
  123. package/dist/chunk-XTQ7MEJG.js +457 -0
  124. package/dist/{chunk-GEVQNST4.js → chunk-XZWSP67B.js} +2 -2
  125. package/dist/{chunk-OEMFEL26.js → chunk-Y3M2T5RO.js} +3 -3
  126. package/dist/{chunk-HP7KJ5O2.js → chunk-YPQOPFP7.js} +6 -6
  127. package/dist/{chunk-MEHBW2SP.js → chunk-YQYINEJI.js} +6 -6
  128. package/dist/{chunk-RXI7K4J5.js → chunk-ZF6CV4WZ.js} +1338 -217
  129. package/dist/{chunk-3XE4NRLF.js → chunk-ZKJU55MX.js} +4 -2
  130. package/dist/{chunk-526ABLHD.js → chunk-ZKQ63XZ5.js} +12 -35
  131. package/dist/{chunk-PAQVETLA.js → chunk-ZKVMDNAN.js} +5 -5
  132. package/dist/cli/index.js +47 -37
  133. package/dist/{clio-BPBAPZGA.js → clio-JUDCLNHC.js} +7 -7
  134. package/dist/clio-context-tools-FT672MNZ.js +136 -0
  135. package/dist/{code-nav-KBQ3RIFK.js → code-nav-7OVCTP2Z.js} +28 -26
  136. package/dist/{components-6DKAXWFN.js → components-OZXZMDWU.js} +5 -5
  137. package/dist/{config-FWL5JK2H.js → config-P3ZQVF63.js} +80 -75
  138. package/dist/{config-graph-ACDB26L2.js → config-graph-GKAOBAS5.js} +74 -70
  139. package/dist/{configure-ZIZ4YV62.js → configure-25LRYZJG.js} +45 -44
  140. package/dist/context-72VQV7JX.js +73 -0
  141. package/dist/{context-VIL5MFRH.js → context-COWRWXP3.js} +74 -70
  142. package/dist/{context-Z3GOBHDK.js → context-WB3D474G.js} +12 -12
  143. package/dist/{context-clear-ZPB3L7MN.js → context-clear-Y4LYMWC6.js} +70 -66
  144. package/dist/{context-working-set-2GLBVF7L.js → context-working-set-TMZYVC7A.js} +15 -14
  145. package/dist/data-tool-KMBWKKWR.js +2987 -0
  146. package/dist/{detail-VSBWYSGZ.js → detail-4GLROGY5.js} +71 -67
  147. package/dist/{dispatch-runner-EEEHGKX4.js → dispatch-runner-TR3LBP5P.js} +92 -88
  148. package/dist/{docs-VMMWFVHL.js → docs-ZK777W2G.js} +3 -3
  149. package/dist/{doctor-V5L4IQGP.js → doctor-WC4OV2OB.js} +61 -59
  150. package/dist/{eval-VJYJ2BV3.js → eval-FUNWJNUJ.js} +45 -45
  151. package/dist/{evals-J2H5V6DD.js → evals-L73EBHSU.js} +4 -4
  152. package/dist/{evidence-Y35YSXH6.js → evidence-AVJ2RTHX.js} +80 -76
  153. package/dist/{evidence-POWAEBEW.js → evidence-P4NZOAK7.js} +70 -66
  154. package/dist/{evidence-XCCCLS36.js → evidence-Y55WKYHH.js} +79 -75
  155. package/dist/{evolve-GPG72VB6.js → evolve-MAWKRYWF.js} +75 -71
  156. package/dist/{extensions-YIZ7W3DA.js → extensions-PYQH3H47.js} +8 -8
  157. package/dist/{fleet-2MDCQ2VK.js → fleet-M4H2QBWT.js} +84 -80
  158. package/dist/{fleet-W2AF3TOJ.js → fleet-ULBXXRDR.js} +123 -119
  159. package/dist/{fleet-commands-WS56G26H.js → fleet-commands-7NNC4JZU.js} +17 -16
  160. package/dist/{fleet-decisions-MYGZ3JW7.js → fleet-decisions-EHEY7KPU.js} +9 -9
  161. package/dist/{fleet-graph-ELTBXBAV.js → fleet-graph-LQ2AHZT3.js} +15 -15
  162. package/dist/{fleet-inspect-45IK73L4.js → fleet-inspect-5IGBIIYZ.js} +76 -72
  163. package/dist/{fleet-preflight-T5NCZKHE.js → fleet-preflight-UTTNOKMG.js} +7 -2
  164. package/dist/{fleet-validate-VG4JBLA4.js → fleet-validate-YGILJKA6.js} +20 -20
  165. package/dist/{fleet-verify-VTSABAYO.js → fleet-verify-AUWTCDKR.js} +70 -66
  166. package/dist/{fleet-view-XC7WMKSS.js → fleet-view-TGUFCY5A.js} +73 -69
  167. package/dist/{init-VTJNNTIP.js → init-GFN2Z7NF.js} +94 -90
  168. package/dist/{interop-IU6BNA7C.js → interop-EF5JUWWK.js} +21 -21
  169. package/dist/{inventory-QPQUTUUZ.js → inventory-I6VJDDYF.js} +73 -69
  170. package/dist/{library-Q3NWL5CM.js → library-3J5IO2OJ.js} +13 -13
  171. package/dist/{library-LF7DLU6S.js → library-IJTOFTDS.js} +16 -15
  172. package/dist/{library-HUTAS57T.js → library-Z3KZSHPE.js} +27 -27
  173. package/dist/{library-import-PPW4YUC5.js → library-import-IMKFLDHX.js} +21 -21
  174. package/dist/{library-inventory-DIRVFRZU.js → library-inventory-CQP5D6GU.js} +13 -13
  175. package/dist/{library-validation-XHUZ3INE.js → library-validation-33UTX7AI.js} +11 -11
  176. package/dist/mcp-5FWZKUS6.js +26 -0
  177. package/dist/{memory-Z2LSKNV6.js → memory-36CWN67Y.js} +75 -71
  178. package/dist/{models-3FTREYPY.js → models-KQ6PQJJQ.js} +49 -49
  179. package/dist/{monitor-HF2MQRB3.js → monitor-XX6ZD6KC.js} +83 -79
  180. package/dist/{orchestrator-UYPA6W4S.js → orchestrator-SK6HDAOP.js} +1337 -772
  181. package/dist/{panes-736XB73K.js → panes-L27QRXUH.js} +12 -12
  182. package/dist/{panes-C4P3PIWT.js → panes-LXZIWNOZ.js} +4 -4
  183. package/dist/{paths-JQ4QYIYB.js → paths-7DJDU4P4.js} +5 -5
  184. package/dist/{preload-XSLRYH3Y.js → preload-K2TDYI4Y.js} +70 -66
  185. package/dist/{reset-V7QSPZYE.js → reset-73VU3XNT.js} +10 -10
  186. package/dist/{resources-OJGDFHYT.js → resources-3BYJYVYL.js} +16 -16
  187. package/dist/{run-T354SMDW.js → run-AR7PY6GW.js} +132 -128
  188. package/dist/run-script-H2KUDIII.js +41 -0
  189. package/dist/{settings-MWZXO6RV.js → settings-3VMBMWID.js} +4 -4
  190. package/dist/{share-Y5ZKJPND.js → share-HVWH4FPF.js} +21 -21
  191. package/dist/{skills-4GLZC4LN.js → skills-5TYEY75Q.js} +22 -22
  192. package/dist/{skills-eval-L5T7GODM.js → skills-eval-CK3MD63Z.js} +96 -87
  193. package/dist/{skills-inventory-LASKXEZI.js → skills-inventory-KSFYG3I6.js} +16 -16
  194. package/dist/{slash-commands-OIMRU36D.js → slash-commands-DMVHML7P.js} +47 -44
  195. package/dist/{steer-KMAM2Y2C.js → steer-XCD6V3EW.js} +4 -4
  196. package/dist/{support-AWC3XKPX.js → support-JAZL6VBR.js} +7 -7
  197. package/dist/{system-CD75NYBU.js → system-3TDQRMZZ.js} +26 -26
  198. package/dist/{targets-VSZX2J2S.js → targets-EZKHAYRN.js} +66 -65
  199. package/dist/{tasks-AN567LYH.js → tasks-SNEFHWYW.js} +12 -12
  200. package/dist/{terminal-lease-6KTWNHVY.js → terminal-lease-BNLFA4OF.js} +8 -7
  201. package/dist/{tools-AGRK3V5J.js → tools-7IM6BDCE.js} +12 -12
  202. package/dist/{trace-P4MQZD33.js → trace-C3MBGD4S.js} +8 -8
  203. package/dist/{tui-primitives-A6MUW32V.js → tui-primitives-36BY2774.js} +2 -2
  204. package/dist/{uninstall-BRUTEPIC.js → uninstall-WWLOSZ42.js} +10 -10
  205. package/dist/{upgrade-SBCGHQGJ.js → upgrade-ETK2JNSJ.js} +37 -47
  206. package/dist/{usage-BIDVTO6V.js → usage-S2HOB7BZ.js} +93 -89
  207. package/dist/{verifiers-LTGCAMXS.js → verifiers-QDTEVH7R.js} +24 -22
  208. package/dist/{verify-OZU4LLNP.js → verify-SUKUK6XM.js} +15 -14
  209. package/dist/web/client/assets/{abnfDiagram-VCTEODGH-C5wfoHm3.js → abnfDiagram-VCTEODGH-BznNOe_I.js} +1 -1
  210. package/dist/web/client/assets/{arc-oH91sfLl.js → arc-Pry-7G1_.js} +1 -1
  211. package/dist/web/client/assets/architecture-7GRP2DOG-BQO9DL_y.js +1 -0
  212. package/dist/web/client/assets/architectureDiagram-5GKGNRK7-CKPbdvyx.js +36 -0
  213. package/dist/web/client/assets/{blockDiagram-I7D4REHJ-wi0_CYHL.js → blockDiagram-I7D4REHJ-prINbpbM.js} +1 -1
  214. package/dist/web/client/assets/{c4Diagram-7LVT6UL2-DV7NYc2W.js → c4Diagram-7LVT6UL2-DkVRKtyU.js} +1 -1
  215. package/dist/web/client/assets/channel-c4EeUUqA.js +1 -0
  216. package/dist/web/client/assets/{chunk-4HAMMTFA-Bhsegh3F.js → chunk-4HAMMTFA-CV0Z1ApC.js} +1 -1
  217. package/dist/web/client/assets/{chunk-75Z2AOVW-RQCckcQG.js → chunk-75Z2AOVW-D34Nohxq.js} +1 -1
  218. package/dist/web/client/assets/chunk-DU6HZSFF-Das_cS-O.js +125 -0
  219. package/dist/web/client/assets/{chunk-F27PBJKO-BcNqv2x1.js → chunk-F27PBJKO-CmRojxkG.js} +1 -1
  220. package/dist/web/client/assets/{chunk-GMAD6QVW-Bq8JWiZT.js → chunk-GMAD6QVW-ClYZmc73.js} +1 -1
  221. package/dist/web/client/assets/{chunk-GVQU2GXP-DbchrAeJ.js → chunk-GVQU2GXP-B2BiHFt-.js} +1 -1
  222. package/dist/web/client/assets/{chunk-IMKFNOWR-DrpvjocK.js → chunk-IMKFNOWR-BGApZ8nP.js} +1 -1
  223. package/dist/web/client/assets/{chunk-L3NEJ4N5-DHLmTnCe.js → chunk-L3NEJ4N5-DIzCgpkY.js} +1 -1
  224. package/dist/web/client/assets/{chunk-OSK3NFVY-CsRbtN9n.js → chunk-OSK3NFVY-BPT-yePv.js} +1 -1
  225. package/dist/web/client/assets/{chunk-P2QGCYS3-aqPbxoMh.js → chunk-P2QGCYS3-BC1WTc2t.js} +1 -1
  226. package/dist/web/client/assets/{chunk-POPQ4Y6H-Dl5vw0h0.js → chunk-POPQ4Y6H-BSjzBmZU.js} +1 -1
  227. package/dist/web/client/assets/{chunk-PWAF6VOD-D7OBRSdO.js → chunk-PWAF6VOD-BIjLs86Z.js} +1 -1
  228. package/dist/web/client/assets/{chunk-SHT3W25Y-CdKCIwuB.js → chunk-SHT3W25Y-CduDz2cm.js} +1 -1
  229. package/dist/web/client/assets/{chunk-SVP7TREG-B94Nu_1-.js → chunk-SVP7TREG-XUn4pPAP.js} +1 -1
  230. package/dist/web/client/assets/{chunk-TICWLB2K-jjRQI_hk.js → chunk-TICWLB2K-DcBy2DKy.js} +1 -1
  231. package/dist/web/client/assets/{chunk-XXDRQBXY-azkbKE37.js → chunk-XXDRQBXY-DqAYeljN.js} +1 -1
  232. package/dist/web/client/assets/classDiagram-ZZMXUADV-C0HR7YKN.js +1 -0
  233. package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-C0HR7YKN.js +1 -0
  234. package/dist/web/client/assets/cose-bilkent-JH36ORCC-CVh1icwb.js +1 -0
  235. package/dist/web/client/assets/{cynefin-OW5HDTMX--i9RDU5f.js → cynefin-OW5HDTMX-BecPbyM6.js} +1 -1
  236. package/dist/web/client/assets/{cynefinDiagram-5FMLGOSQ-cRcvyBdp.js → cynefinDiagram-5FMLGOSQ-BzMzFwyT.js} +1 -1
  237. package/dist/web/client/assets/{dagre-GXQ25YYZ-C9mZmAPe.js → dagre-GXQ25YYZ-CAWJmRMG.js} +1 -1
  238. package/dist/web/client/assets/{diagram-S7CK7UJ4-Oj_zlLDY.js → diagram-S7CK7UJ4--lp0ALmn.js} +1 -1
  239. package/dist/web/client/assets/{diagram-UQ7AKVKN-BWKbbfcR.js → diagram-UQ7AKVKN-gKUnsjcj.js} +1 -1
  240. package/dist/web/client/assets/{diagram-VSXAHHWV-C3N3f7DO.js → diagram-VSXAHHWV-BoN5D1Gh.js} +1 -1
  241. package/dist/web/client/assets/{diagram-VX7I27RA-CtDKDAWe.js → diagram-VX7I27RA-BMtuswQ6.js} +1 -1
  242. package/dist/web/client/assets/{diagram-Z3DM3KII-B8bkBRCz.js → diagram-Z3DM3KII-DtU8LXrA.js} +1 -1
  243. package/dist/web/client/assets/dist-v5Q1xZ2K.js +1 -0
  244. package/dist/web/client/assets/{ebnfDiagram-PWID7BFC-CskW-Whx.js → ebnfDiagram-PWID7BFC-DDcnv9BH.js} +1 -1
  245. package/dist/web/client/assets/{erDiagram-RLTQ6QDP-C-83cgCW.js → erDiagram-RLTQ6QDP-DvRb4iDL.js} +1 -1
  246. package/dist/web/client/assets/eventmodeling-NTZA5JFV-01h4SbTc.js +1 -0
  247. package/dist/web/client/assets/flowDiagram-HODETNUW-Bll_YZ6T.js +1 -0
  248. package/dist/web/client/assets/framework-YGoR34M4.js +9 -0
  249. package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-DdFZ9hvH.js +292 -0
  250. package/dist/web/client/assets/{gitGraph-4MIJSDKK-B40cQtBE.js → gitGraph-4MIJSDKK-DjD_AAMj.js} +1 -1
  251. package/dist/web/client/assets/{gitGraphDiagram-WWUBYQGX-CH-7P7Di.js → gitGraphDiagram-WWUBYQGX-CDyN9n2u.js} +1 -1
  252. package/dist/web/client/assets/index-CVcy0FAn.js +75 -0
  253. package/dist/web/client/assets/{info-A6RAGUB7-eCCE9D_Q.js → info-A6RAGUB7-C_XK8Hq0.js} +1 -1
  254. package/dist/web/client/assets/{infoDiagram-27XIBGKW-DRnvqMjM.js → infoDiagram-27XIBGKW-DIe4tJ1i.js} +1 -1
  255. package/dist/web/client/assets/{ishikawaDiagram-5VMMS53U-DBA_55wp.js → ishikawaDiagram-5VMMS53U-CVl5unKI.js} +1 -1
  256. package/dist/web/client/assets/{journeyDiagram-3NMN7TZE-C-ewpNl7.js → journeyDiagram-3NMN7TZE-CPEB1Vt8.js} +1 -1
  257. package/dist/web/client/assets/{kanban-definition-UXKFOSKX-B1taGsu0.js → kanban-definition-UXKFOSKX-j-9WXjYQ.js} +1 -1
  258. package/dist/web/client/assets/{line-lZ0kyxDI.js → line-BIDAcEtX.js} +1 -1
  259. package/dist/web/client/assets/{linear-DIc8FgZj.js → linear-SzVmGSw4.js} +1 -1
  260. package/dist/web/client/assets/{mermaid-parser.core-SXolxpXw.js → mermaid-parser.core-Ux4vssh0.js} +3 -3
  261. package/dist/web/client/assets/{mermaid.core-DXgQtkNg.js → mermaid.core-CDuwVKeh.js} +4 -4
  262. package/dist/web/client/assets/{mindmap-definition-YA3MSWOX-DXJas9K7.js → mindmap-definition-YA3MSWOX-5MlQEeQ6.js} +1 -1
  263. package/dist/web/client/assets/{packet-AYTQ26CC-OqVl_07o.js → packet-AYTQ26CC-DRO66c9Q.js} +1 -1
  264. package/dist/web/client/assets/{pegDiagram-XKGWAZYB-CPE_zdfN.js → pegDiagram-XKGWAZYB-BakZnSjM.js} +1 -1
  265. package/dist/web/client/assets/{pie-WAS4IAKB-DAxnMBLe.js → pie-WAS4IAKB-BEzcmhz8.js} +1 -1
  266. package/dist/web/client/assets/{pieDiagram-E7YTZNPT-Uwjpufxv.js → pieDiagram-E7YTZNPT-DpmqgoPt.js} +1 -1
  267. package/dist/web/client/assets/prism-core-BtsZdCS6.js +1 -0
  268. package/dist/web/client/assets/{quadrantDiagram-AXDQQJYC-Bjs4yjgs.js → quadrantDiagram-AXDQQJYC-DuMPwwV2.js} +1 -1
  269. package/dist/web/client/assets/{radar-RG4KPBEZ-CuCKjHM3.js → radar-RG4KPBEZ-Djm3oXl5.js} +1 -1
  270. package/dist/web/client/assets/{railroad-74A4TZTK-CnQK-Cc1.js → railroad-74A4TZTK-Cpvkwsao.js} +1 -1
  271. package/dist/web/client/assets/railroad-abnf-HS5TGJTU-CpRQ3ruG.js +1 -0
  272. package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-1Rm5a5eJ.js +1 -0
  273. package/dist/web/client/assets/railroad-peg-WCYAUIDC-C8344cTh.js +1 -0
  274. package/dist/web/client/assets/{railroadDiagram-O6MQD6OU-BDDIPNLL.js → railroadDiagram-O6MQD6OU-CgMS4B6R.js} +1 -1
  275. package/dist/web/client/assets/{requirementDiagram-BXWQKSXE-B5Ydyxc1.js → requirementDiagram-BXWQKSXE-CX5eoNdN.js} +1 -1
  276. package/dist/web/client/assets/rolldown-runtime-hePW80VL.js +1 -0
  277. package/dist/web/client/assets/{sankeyDiagram-P5KCCOFB-Bw2Qym75.js → sankeyDiagram-P5KCCOFB-CODBX2N3.js} +1 -1
  278. package/dist/web/client/assets/{sequenceDiagram-WJ2MYXX4-BZf36nO0.js → sequenceDiagram-WJ2MYXX4-eUhhF8OR.js} +1 -1
  279. package/dist/web/client/assets/src-B6xuSHsQ.js +1 -0
  280. package/dist/web/client/assets/{stateDiagram-D77RDMKH-DnH6JRkp.js → stateDiagram-D77RDMKH-vR6l0NC2.js} +1 -1
  281. package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-BYUm8jLY.js +1 -0
  282. package/dist/web/client/assets/{swimlanes-42K2YHIH-D9PZmtZg.js → swimlanes-42K2YHIH-v9Tw_zX7.js} +1 -1
  283. package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-B2jdCvhD.js +8 -0
  284. package/dist/web/client/assets/{timeline-definition-24CTP7MA-CrkZZBo7.js → timeline-definition-24CTP7MA-DxianbhU.js} +1 -1
  285. package/dist/web/client/assets/{treeView-Q6P3EWNA-C9zDShoC.js → treeView-Q6P3EWNA-DLxnZb9R.js} +1 -1
  286. package/dist/web/client/assets/{treemap-WGGIJYW6-B-plj9yK.js → treemap-WGGIJYW6-I7UnZ6xJ.js} +1 -1
  287. package/dist/web/client/assets/{vennDiagram-4TSXK5OY-VeOdaphN.js → vennDiagram-4TSXK5OY-Ar7M8Mrj.js} +1 -1
  288. package/dist/web/client/assets/{wardley-WFR3VGLG-Wl1P_m6L.js → wardley-WFR3VGLG-B8ZSHeDu.js} +1 -1
  289. package/dist/web/client/assets/{wardleyDiagram-VM6X3IG4-B85-R9t2.js → wardleyDiagram-VM6X3IG4-Qks2FmIn.js} +1 -1
  290. package/dist/web/client/assets/{xychartDiagram-S5SC5T6Z-BrD8OW8m.js → xychartDiagram-S5SC5T6Z-BBBjRtiE.js} +1 -1
  291. package/dist/web/client/index.html +3 -1
  292. package/dist/web/reads-worker.js +17 -17
  293. package/dist/web/server.js +25 -25
  294. package/dist/{web-EU6ATJWA.js → web-EMGUGGEI.js} +3 -3
  295. package/dist/{web-fetch-U22Q7HV4.js → web-fetch-6BRRVQON.js} +22 -5
  296. package/dist/{wiki-generate-LZRLFG6I.js → wiki-generate-XHSJTDOP.js} +104 -100
  297. package/dist/{with-panes-X5CZOGML.js → with-panes-Z6BTEHMZ.js} +11 -11
  298. package/dist/worker/entry.js +101 -87
  299. package/docs/README.md +1 -1
  300. package/docs/architecture/artifact-placement.md +12 -1
  301. package/docs/architecture/library.md +1 -1
  302. package/docs/architecture/prompt-envelope-and-tools.md +37 -27
  303. package/docs/architecture/safety-model.md +19 -6
  304. package/docs/architecture/session-lifecycle.md +10 -4
  305. package/docs/architecture/tui-design.md +37 -14
  306. package/docs/guide/commands-and-modes.md +39 -19
  307. package/docs/guide/configuration-and-targets.md +7 -5
  308. package/docs/guide/configuration-reference.md +116 -13
  309. package/docs/guide/environment-variables.md +2 -5
  310. package/docs/guide/fleet-dispatch.md +3 -2
  311. package/docs/guide/glossary.md +1 -1
  312. package/docs/guide/installation-and-lifecycle.md +2 -2
  313. package/docs/guide/resource-library.md +1 -1
  314. package/docs/guide/tool-usage.md +166 -64
  315. package/docs/guide/troubleshooting.md +1 -1
  316. package/docs/process/documentation-guide.md +1 -0
  317. package/docs/process/fleet-demo-runbook.md +6 -6
  318. package/docs/process/scientific-validation.md +22 -2
  319. package/docs/process/tool-audit-v0.4.9.md +357 -0
  320. package/package.json +1 -1
  321. package/src/cli/argv.ts +31 -0
  322. package/src/cli/clio.ts +17 -13
  323. package/src/cli/config.ts +4 -0
  324. package/src/cli/doctor-panes.ts +1 -1
  325. package/src/cli/doctor.ts +3 -1
  326. package/src/cli/index.ts +14 -1
  327. package/src/cli/mcp.ts +106 -0
  328. package/src/cli/skills-eval.ts +8 -2
  329. package/src/cli/upgrade.ts +34 -38
  330. package/src/cli/verifiers.ts +1 -1
  331. package/src/core/bash-exec.ts +27 -4
  332. package/src/core/config.ts +2 -1
  333. package/src/core/defaults.ts +10 -1
  334. package/src/core/event-bus.ts +1 -1
  335. package/src/core/run-records.ts +438 -0
  336. package/src/core/safe-exec.ts +506 -56
  337. package/src/core/skill-activation.ts +5 -3
  338. package/src/core/termination.ts +3 -3
  339. package/src/core/tool-names.ts +33 -12
  340. package/src/domains/context/clio-md.ts +1 -1
  341. package/src/domains/context/worker/pressure.ts +6 -2
  342. package/src/domains/context/working-set/path-index.ts +7 -2
  343. package/src/domains/dispatch/code-step.ts +7 -2
  344. package/src/domains/dispatch/contract.ts +7 -0
  345. package/src/domains/dispatch/execution-role.ts +3 -3
  346. package/src/domains/dispatch/execution-scheduler.ts +204 -79
  347. package/src/domains/dispatch/extension.ts +131 -14
  348. package/src/domains/dispatch/fleet-preflight.ts +18 -3
  349. package/src/domains/dispatch/fleet-run.ts +1 -0
  350. package/src/domains/dispatch/gate-decisions.ts +3 -3
  351. package/src/domains/dispatch/heartbeat.ts +1 -1
  352. package/src/domains/dispatch/host-verification.ts +16 -14
  353. package/src/domains/dispatch/receipt-findings.ts +3 -4
  354. package/src/domains/dispatch/reservation-store.ts +7 -9
  355. package/src/domains/dispatch/route-facts.ts +1 -1
  356. package/src/domains/dispatch/state.ts +3 -3
  357. package/src/domains/dispatch/types.ts +1 -1
  358. package/src/domains/evidence/build.ts +35 -7
  359. package/src/domains/gateway/mcp/client.ts +923 -0
  360. package/src/domains/gateway/mcp/config.ts +456 -0
  361. package/src/domains/gateway/mcp/index.ts +88 -0
  362. package/src/domains/gateway/mcp/protocol.ts +273 -0
  363. package/src/domains/gateway/mcp/trust.ts +263 -0
  364. package/src/domains/lifecycle/doctor.ts +17 -3
  365. package/src/domains/mux/contract.ts +5 -9
  366. package/src/domains/mux/detect.ts +1 -1
  367. package/src/domains/mux/extension.ts +1 -1
  368. package/src/domains/mux/protocol.ts +5 -7
  369. package/src/domains/mux/socket-client.ts +3 -3
  370. package/src/domains/observability/accountability.ts +2 -2
  371. package/src/domains/observability/contract.ts +7 -3
  372. package/src/domains/observability/evidence-index.ts +2 -2
  373. package/src/domains/observability/projection.ts +10 -0
  374. package/src/domains/prompts/compiler.ts +41 -23
  375. package/src/domains/prompts/fragments/identity/docs-routing.md +2 -2
  376. package/src/domains/prompts/fragments/operating/skills.md +12 -10
  377. package/src/domains/providers/index.ts +5 -1
  378. package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +42 -10
  379. package/src/domains/providers/probe/http.ts +44 -59
  380. package/src/domains/providers/probe/reasoning.ts +2 -0
  381. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +20 -31
  382. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +9 -4
  383. package/src/domains/safety/action-classifier.ts +17 -1
  384. package/src/domains/safety/call-target.ts +14 -0
  385. package/src/domains/safety/contract.ts +1 -1
  386. package/src/domains/safety/finish-contract.ts +9 -3
  387. package/src/domains/safety/loop-detector.ts +1 -1
  388. package/src/domains/safety/policy-engine.ts +7 -0
  389. package/src/domains/safety/protected-artifacts.ts +3 -4
  390. package/src/domains/safety/rejection-feedback.ts +1 -1
  391. package/src/domains/safety/scope.ts +2 -3
  392. package/src/domains/safety/validation-contract.ts +3 -2
  393. package/src/domains/scheduling/budget.ts +5 -3
  394. package/src/domains/scheduling/contract.ts +2 -1
  395. package/src/domains/scheduling/extension.ts +3 -3
  396. package/src/domains/session/compaction/branch-summary.ts +1 -1
  397. package/src/domains/session/compaction/compact.ts +25 -2
  398. package/src/domains/session/compaction/cut-point.ts +1 -1
  399. package/src/domains/session/compaction/tokens.ts +5 -10
  400. package/src/domains/session/contract.ts +1 -1
  401. package/src/domains/session/cwd-fallback.ts +2 -2
  402. package/src/domains/session/handoff.ts +5 -1
  403. package/src/domains/session/history.ts +6 -0
  404. package/src/domains/session/manager.ts +14 -7
  405. package/src/domains/session/retry.ts +2 -1
  406. package/src/domains/session/session-artifacts.ts +12 -7
  407. package/src/domains/session/task-board.ts +2 -3
  408. package/src/engine/apis/openai-completions.ts +8 -0
  409. package/src/engine/loop-guard.ts +7 -0
  410. package/src/engine/provider-error-body.ts +65 -0
  411. package/src/engine/session.ts +118 -29
  412. package/src/engine/worker-runtime.ts +3 -0
  413. package/src/entry/boot-options.ts +2 -0
  414. package/src/entry/orchestrator.ts +18 -2
  415. package/src/interactive/chat-loop-policy.ts +1 -0
  416. package/src/interactive/chat-loop.ts +8 -4
  417. package/src/interactive/chat-panel.ts +23 -9
  418. package/src/interactive/chat-renderer.ts +33 -11
  419. package/src/interactive/clio-editor.ts +13 -5
  420. package/src/interactive/dispatch-board.ts +70 -30
  421. package/src/interactive/editor-submit.ts +30 -25
  422. package/src/interactive/footer/widgets.ts +12 -9
  423. package/src/interactive/interactive-presentation.ts +2 -3
  424. package/src/interactive/mux-bridge.ts +3 -7
  425. package/src/interactive/overlay-general-openers.ts +14 -7
  426. package/src/interactive/overlays/cwd-fallback.ts +1 -1
  427. package/src/interactive/overlays/library-model.ts +114 -35
  428. package/src/interactive/overlays/library.ts +52 -5
  429. package/src/interactive/overlays/list-overlay.ts +4 -1
  430. package/src/interactive/overlays/session-selector.ts +28 -23
  431. package/src/interactive/overlays/settings.ts +20 -1
  432. package/src/interactive/overlays/tree-selector.ts +47 -10
  433. package/src/interactive/panes-runtime.ts +1 -1
  434. package/src/interactive/renderers/compaction-summary.ts +1 -1
  435. package/src/interactive/renderers/provider-error.ts +118 -0
  436. package/src/interactive/renderers/retry-status.ts +59 -23
  437. package/src/interactive/renderers/tool-execution.ts +67 -7
  438. package/src/interactive/renderers/worker-answer.ts +198 -0
  439. package/src/interactive/renderers/worker-entry.ts +57 -163
  440. package/src/interactive/slash-commands.ts +26 -1
  441. package/src/interactive/slash-spec.ts +2 -2
  442. package/src/interactive/theme/labels.ts +66 -30
  443. package/src/interactive/turn-persistence.ts +6 -1
  444. package/src/interactive/turn-recovery.ts +2 -1
  445. package/src/interactive/turn-runtime.ts +22 -5
  446. package/src/interactive/view/artifacts.ts +3 -2
  447. package/src/interactive/view/view-overlay.ts +96 -20
  448. package/src/tools/agent-tools.ts +21 -7
  449. package/src/tools/artifact.ts +16 -8
  450. package/src/tools/bash.ts +90 -11
  451. package/src/tools/bootstrap.ts +42 -4
  452. package/src/tools/builtin-tool-catalog.ts +72 -7
  453. package/src/tools/context/index.ts +27 -31
  454. package/src/tools/context/library.ts +3 -1
  455. package/src/tools/context/surface.ts +12 -26
  456. package/src/tools/core-bootstrap.ts +72 -1
  457. package/src/tools/data/csv.ts +1189 -0
  458. package/src/tools/data/index.ts +308 -0
  459. package/src/tools/data/json.ts +1799 -0
  460. package/src/tools/data/jsonl.ts +561 -0
  461. package/src/tools/data/shared.ts +452 -0
  462. package/src/tools/edit-diff.ts +0 -7
  463. package/src/tools/edit.ts +115 -18
  464. package/src/tools/file-mutation-queue.ts +114 -4
  465. package/src/tools/find.ts +108 -29
  466. package/src/tools/gateway/caps.ts +11 -0
  467. package/src/tools/gateway/clio-context-surface.ts +41 -0
  468. package/src/tools/gateway/clio-context-tools.ts +77 -0
  469. package/src/tools/gateway/data-surface.ts +138 -0
  470. package/src/tools/gateway/data-tool.ts +201 -0
  471. package/src/tools/gateway/index.ts +342 -0
  472. package/src/tools/gateway/mcp-capabilities.ts +469 -0
  473. package/src/tools/grep.ts +88 -33
  474. package/src/tools/harness-extensions.ts +3 -0
  475. package/src/tools/ignore-policy.ts +7 -5
  476. package/src/tools/ls.ts +111 -20
  477. package/src/tools/policy.ts +35 -13
  478. package/src/tools/presentation.ts +6 -0
  479. package/src/tools/read.ts +634 -156
  480. package/src/tools/registry.ts +94 -6
  481. package/src/tools/run-script.ts +997 -0
  482. package/src/tools/spawn-hygiene.ts +157 -5
  483. package/src/tools/surface.ts +163 -0
  484. package/src/tools/verify/authoring.ts +8 -3
  485. package/src/tools/verify/catalog.ts +14 -1
  486. package/src/tools/verify/numeric.ts +367 -59
  487. package/src/tools/verify/perf.ts +171 -9
  488. package/src/tools/verify/scripts.ts +178 -26
  489. package/src/tools/web-fetch-surface.ts +22 -0
  490. package/src/tools/web-fetch.ts +26 -1
  491. package/src/tools/write.ts +45 -19
  492. package/dist/chunk-B6UM3OZC.js +0 -15
  493. package/dist/chunk-GJ24ODAX.js +0 -196
  494. package/dist/chunk-LZCCBLRC.js +0 -57
  495. package/dist/web/client/assets/architecture-7GRP2DOG-EGozsYEO.js +0 -1
  496. package/dist/web/client/assets/architectureDiagram-5GKGNRK7-z9FokbJl.js +0 -36
  497. package/dist/web/client/assets/channel-CiUWbHN9.js +0 -1
  498. package/dist/web/client/assets/chunk-DU6HZSFF-C5USiOAy.js +0 -125
  499. package/dist/web/client/assets/classDiagram-ZZMXUADV-CMODalmo.js +0 -1
  500. package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-CMODalmo.js +0 -1
  501. package/dist/web/client/assets/cose-bilkent-JH36ORCC-RbQL23qS.js +0 -1
  502. package/dist/web/client/assets/dist-D0_q-A2b.js +0 -1
  503. package/dist/web/client/assets/eventmodeling-NTZA5JFV-DjVq8wKU.js +0 -1
  504. package/dist/web/client/assets/flowDiagram-HODETNUW-BUiCBGXt.js +0 -1
  505. package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-B2lb8lvF.js +0 -292
  506. package/dist/web/client/assets/index-FSIC94pi.js +0 -83
  507. package/dist/web/client/assets/prism-core-BngLtbUd.js +0 -1
  508. package/dist/web/client/assets/railroad-abnf-HS5TGJTU-BcW01NZG.js +0 -1
  509. package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-B7YCEDDd.js +0 -1
  510. package/dist/web/client/assets/railroad-peg-WCYAUIDC-DjNZbSTZ.js +0 -1
  511. package/dist/web/client/assets/src-yeptRXpt.js +0 -1
  512. package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-C7QtHeK4.js +0 -1
  513. package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-CBZlPFky.js +0 -8
@@ -4,17 +4,54 @@
4
4
  * names a reference file of the same shape and a tolerance. This module
5
5
  * decides pass or fail and writes the structured report; it reads no file and
6
6
  * runs nothing.
7
+ *
8
+ * The verdict is a statement about the declared tolerance only. A payload
9
+ * that passes agrees with the reference within the named bounds; whether the
10
+ * reference itself is scientifically right is not established by this module.
7
11
  */
8
12
 
9
13
  export type NumericToleranceKind = "relative" | "absolute" | "ulp";
10
14
 
15
+ /**
16
+ * How the named bounds combine. `all` (the default) requires every named
17
+ * bound to hold, which is the strict conjunction; `any` passes when at least
18
+ * one named bound holds, which is the common `|a-e| <= abs OR |a-e| <= rel*|e|`
19
+ * formula when both are named. The two rules are not interchangeable, so the
20
+ * report always states which one judged the payload.
21
+ */
22
+ export type NumericToleranceCombine = "all" | "any";
23
+
24
+ /**
25
+ * How a pair with a NaN or an infinity on either side is judged. `fail` (the
26
+ * default) rejects every such pair as not finite. `match` accepts NaN against
27
+ * NaN and an infinity against the same-signed infinity, and rejects every
28
+ * other pairing.
29
+ */
30
+ export type NumericNonFinitePolicy = "fail" | "match";
31
+
32
+ export const DEFAULT_NUMERIC_COMBINE: NumericToleranceCombine = "all";
33
+ export const DEFAULT_NUMERIC_NON_FINITE: NumericNonFinitePolicy = "fail";
34
+
35
+ /**
36
+ * The largest admissible `ulp` bound. `ulpDistance` reports a distance past
37
+ * the safe-integer range as Infinity, so a bound within the range judges
38
+ * exactly: Infinity exceeds it only when the true distance does. A larger
39
+ * bound would turn that sentinel into a spurious failure, so the normalizer
40
+ * refuses it.
41
+ */
42
+ export const MAX_ULP_TOLERANCE = Number.MAX_SAFE_INTEGER;
43
+
11
44
  export interface NumericTolerance {
12
45
  /** |actual - expected| / |expected| must not exceed this. Zero expected passes only on exact equality. */
13
46
  relative?: number;
14
47
  /** |actual - expected| must not exceed this. */
15
48
  absolute?: number;
16
- /** Distance in representable doubles between actual and expected must not exceed this integer. */
49
+ /** Distance in representable doubles between actual and expected must not exceed this integer, at most MAX_ULP_TOLERANCE. */
17
50
  ulp?: number;
51
+ /** Combination rule for the named bounds; absent means `all`. */
52
+ combine?: NumericToleranceCombine;
53
+ /** Non-finite pairing policy; absent means `fail`. */
54
+ nonFinite?: NumericNonFinitePolicy;
18
55
  }
19
56
 
20
57
  export type NumericValue = number | number[];
@@ -28,37 +65,110 @@ export type NumericFailureReason =
28
65
  | "not-finite"
29
66
  | NumericToleranceKind;
30
67
 
68
+ /**
69
+ * A number as the report writes it. JSON has no spelling for NaN or the
70
+ * infinities: `JSON.stringify` writes each as null, and null already means
71
+ * "undefined" in a deviation (a relative deviation against zero, a ulp
72
+ * distance to a non-finite value). So a non-finite value is written by name,
73
+ * the protobuf JSON convention, and a serialized report reads back with every
74
+ * distinction intact. `reportedNumberValue` restores the number.
75
+ */
76
+ export type ReportedNumber = number | "NaN" | "Infinity" | "-Infinity";
77
+
78
+ function reportedNumber(value: number): ReportedNumber {
79
+ if (Number.isNaN(value)) return "NaN";
80
+ if (value === Number.POSITIVE_INFINITY) return "Infinity";
81
+ if (value === Number.NEGATIVE_INFINITY) return "-Infinity";
82
+ return value;
83
+ }
84
+
85
+ /** The number a `ReportedNumber` names. */
86
+ export function reportedNumberValue(value: ReportedNumber): number {
87
+ return typeof value === "number" ? value : Number(value);
88
+ }
89
+
31
90
  export interface NumericDeviation {
32
91
  /** Array index of the worst element; absent for a scalar. */
33
92
  index?: number;
34
- actual: number;
35
- expected: number;
36
- absolute: number;
37
- /** Relative deviation, or null when it is undefined (expected is zero and actual is not). */
38
- relative: number | null;
39
- /** Distance in representable doubles, or null when either side is not finite. */
40
- ulp: number | null;
93
+ actual: ReportedNumber;
94
+ expected: ReportedNumber;
95
+ /** |actual - expected|; `"Infinity"` when the difference overflows or the pair is a mismatched non-finite. */
96
+ absolute: ReportedNumber;
97
+ /**
98
+ * Relative deviation; `"Infinity"` when the quotient overflows; null when
99
+ * it is undefined (expected is zero and actual is not, or the pair is a
100
+ * mismatched non-finite).
101
+ */
102
+ relative: ReportedNumber | null;
103
+ /** Distance in representable doubles; `"Infinity"` past the safe-integer range; null when either side is not finite. */
104
+ ulp: ReportedNumber | null;
105
+ /**
106
+ * Present when either side is not finite. `matched` means the non-finite
107
+ * policy accepted the pair (NaN against NaN, or same-signed infinities);
108
+ * the deviation fields then read zero because the rule, not arithmetic,
109
+ * declared the pair equal. `mismatched` keeps the infinite deviation.
110
+ */
111
+ nonFinite?: "matched" | "mismatched";
41
112
  }
42
113
 
43
114
  export interface NumericKeyReport {
44
115
  key: string;
45
116
  passed: boolean;
46
- /** The tolerances the worst element failed, in schema order; empty on pass. */
117
+ /** Why the key failed, in schema order; empty on pass. */
47
118
  failed: NumericFailureReason[];
48
- /** Worst deviation for the key, present whenever both sides had a comparable value. */
119
+ /** Named bounds the worst element satisfied; empty when nothing was comparable. */
120
+ held: NumericToleranceKind[];
121
+ /** Named bounds the worst element violated, listed even when `combine: any` let the key pass. */
122
+ violated: NumericToleranceKind[];
123
+ /**
124
+ * Worst deviation for the key, present whenever both sides had a comparable
125
+ * value. A failing element outranks a passing one with a violated bound
126
+ * (possible only under `combine: any`), which outranks a clean one; within
127
+ * a tier the largest absolute deviation is the worst. So a key that passed
128
+ * only by `any` names the element that needed it, not the clean element
129
+ * that happened to deviate most.
130
+ */
49
131
  worst?: NumericDeviation;
50
132
  /** One line a reader can act on. */
51
133
  detail: string;
52
134
  }
53
135
 
136
+ /** Identity of the reference payload the judgement read. */
137
+ export interface NumericReferenceProvenance {
138
+ /** The caller's label for the reference, for example `reference 'tests/ref.json'`. */
139
+ source: string;
140
+ /** The reference path when the caller supplied one; a sealed host path or a repository-relative catalog path. */
141
+ path?: string;
142
+ /** SHA-256 of the exact reference text. */
143
+ sha256: string;
144
+ bytes: number;
145
+ }
146
+
147
+ /** Identity of the payload text the judgement extracted from the command's stdout. */
148
+ export interface NumericPayloadProvenance {
149
+ sha256: string;
150
+ bytes: number;
151
+ }
152
+
54
153
  export interface NumericCompareReport {
55
154
  kind: "numeric-compare";
56
155
  passed: boolean;
156
+ /** The tolerance exactly as declared, defaults not filled in. */
57
157
  tolerance: NumericTolerance;
158
+ /** The combination rule that judged the payload, default applied. */
159
+ combine: NumericToleranceCombine;
160
+ /** The non-finite policy that judged the payload, default applied. */
161
+ nonFinite: NumericNonFinitePolicy;
162
+ /** The effective rule in words, for example `all of relative<=1e-6, absolute<=1e-9 must hold; non-finite values fail`. */
163
+ rule: string;
58
164
  keys: NumericKeyReport[];
59
165
  /** The keys that failed, sorted; empty on pass. */
60
166
  failedKeys: string[];
61
167
  summary: string;
168
+ /** Reference identity, present when the judgement read reference text. */
169
+ reference?: NumericReferenceProvenance;
170
+ /** Actual payload identity, present when the judgement extracted payload text. */
171
+ actual?: NumericPayloadProvenance;
62
172
  }
63
173
 
64
174
  export const NUMERIC_PAYLOAD_CAPS = Object.freeze({
@@ -66,13 +176,16 @@ export const NUMERIC_PAYLOAD_CAPS = Object.freeze({
66
176
  elements: 1_000_000,
67
177
  });
68
178
 
69
- /** True when the tolerance names at least one bound and every named bound is usable. */
179
+ const TOLERANCE_FIELDS = new Set(["relative", "absolute", "ulp", "combine", "nonFinite"]);
180
+ const TOLERANCE_KINDS: ReadonlyArray<NumericToleranceKind> = ["relative", "absolute", "ulp"];
181
+
182
+ /** True when the tolerance names at least one bound and every named field is usable. */
70
183
  export function normalizeNumericTolerance(value: unknown): NumericTolerance | Error {
71
184
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
72
185
  return new Error("tolerance must be an object with relative, absolute, or ulp");
73
186
  }
74
187
  const record = value as Record<string, unknown>;
75
- const unknown = Object.keys(record).filter((key) => key !== "relative" && key !== "absolute" && key !== "ulp");
188
+ const unknown = Object.keys(record).filter((key) => !TOLERANCE_FIELDS.has(key));
76
189
  if (unknown.length > 0) return new Error(`tolerance has unknown field(s): ${unknown.sort().join(", ")}`);
77
190
  const tolerance: NumericTolerance = {};
78
191
  for (const kind of ["relative", "absolute"] as const) {
@@ -88,11 +201,24 @@ export function normalizeNumericTolerance(value: unknown): NumericTolerance | Er
88
201
  if (typeof bound !== "number" || !Number.isInteger(bound) || bound < 0) {
89
202
  return new Error("tolerance.ulp must be a non-negative integer");
90
203
  }
204
+ if (bound > MAX_ULP_TOLERANCE) {
205
+ return new Error(`tolerance.ulp must not exceed ${MAX_ULP_TOLERANCE} (Number.MAX_SAFE_INTEGER)`);
206
+ }
91
207
  tolerance.ulp = bound;
92
208
  }
93
209
  if (tolerance.relative === undefined && tolerance.absolute === undefined && tolerance.ulp === undefined) {
94
210
  return new Error("tolerance must name at least one of relative, absolute, or ulp");
95
211
  }
212
+ if (Object.hasOwn(record, "combine")) {
213
+ const combine = record.combine;
214
+ if (combine !== "all" && combine !== "any") return new Error("tolerance.combine must be all or any");
215
+ tolerance.combine = combine;
216
+ }
217
+ if (Object.hasOwn(record, "nonFinite")) {
218
+ const policy = record.nonFinite;
219
+ if (policy !== "fail" && policy !== "match") return new Error("tolerance.nonFinite must be fail or match");
220
+ tolerance.nonFinite = policy;
221
+ }
96
222
  return tolerance;
97
223
  }
98
224
 
@@ -109,7 +235,9 @@ function orderedBits(value: number): bigint {
109
235
  * Distance in representable doubles between two finite numbers. Adjacent
110
236
  * doubles are 1 apart, +0 and -0 are 0 apart, and a sign crossing counts every
111
237
  * double in between. Returns Infinity when the distance exceeds the safe
112
- * integer range or either side is not finite.
238
+ * integer range or either side is not finite; every admissible bound is at
239
+ * most MAX_ULP_TOLERANCE, so that sentinel fails a bound only when the true
240
+ * distance does.
113
241
  */
114
242
  export function ulpDistance(actual: number, expected: number): number {
115
243
  if (!Number.isFinite(actual) || !Number.isFinite(expected)) return Number.POSITIVE_INFINITY;
@@ -118,7 +246,16 @@ export function ulpDistance(actual: number, expected: number): number {
118
246
  return magnitude > BigInt(Number.MAX_SAFE_INTEGER) ? Number.POSITIVE_INFINITY : Number(magnitude);
119
247
  }
120
248
 
121
- /** Parse command stdout or a reference file as a numeric payload, naming the fault when it is not one. */
249
+ /**
250
+ * Parse command stdout or a reference file as a numeric payload, naming the
251
+ * fault when it is not one.
252
+ *
253
+ * JSON has no spelling for NaN, so NaN never arrives through this parser. An
254
+ * infinity can: `JSON.parse` turns an overflowing literal such as `1e999` into
255
+ * `Infinity`, and a validator that prints an overflowed measurement produces
256
+ * exactly that. The payload keeps it, and the tolerance's `nonFinite` policy
257
+ * decides how it is judged.
258
+ */
122
259
  export function parseNumericPayload(text: string, label: string): NumericPayload | Error {
123
260
  let parsed: unknown;
124
261
  try {
@@ -153,11 +290,69 @@ export function parseNumericPayload(text: string, label: string): NumericPayload
153
290
  return Object.fromEntries(entries);
154
291
  }
155
292
 
156
- function deviation(actual: number, expected: number, index?: number): NumericDeviation {
293
+ function effectiveNumericCombine(tolerance: NumericTolerance): NumericToleranceCombine {
294
+ return tolerance.combine ?? DEFAULT_NUMERIC_COMBINE;
295
+ }
296
+
297
+ function effectiveNumericNonFinite(tolerance: NumericTolerance): NumericNonFinitePolicy {
298
+ return tolerance.nonFinite ?? DEFAULT_NUMERIC_NON_FINITE;
299
+ }
300
+
301
+ /** The named bounds, in schema order. */
302
+ function namedKinds(tolerance: NumericTolerance): NumericToleranceKind[] {
303
+ return TOLERANCE_KINDS.filter((kind) => tolerance[kind] !== undefined);
304
+ }
305
+
306
+ /** NaN pairs with NaN; an infinity pairs with the same-signed infinity; nothing else pairs. */
307
+ function nonFinitePairMatches(actual: number, expected: number): boolean {
308
+ if (Number.isNaN(actual) && Number.isNaN(expected)) return true;
309
+ return actual === expected && !Number.isFinite(actual);
310
+ }
311
+
312
+ /** A deviation as arithmetic produced it, before the report encodes its non-finite values by name. */
313
+ interface Deviation {
314
+ index?: number;
315
+ actual: number;
316
+ expected: number;
317
+ absolute: number;
318
+ relative: number | null;
319
+ ulp: number | null;
320
+ nonFinite?: "matched" | "mismatched";
321
+ }
322
+
323
+ function reportDeviation(item: Deviation): NumericDeviation {
324
+ return {
325
+ ...item,
326
+ actual: reportedNumber(item.actual),
327
+ expected: reportedNumber(item.expected),
328
+ absolute: reportedNumber(item.absolute),
329
+ relative: item.relative === null ? null : reportedNumber(item.relative),
330
+ ulp: item.ulp === null ? null : reportedNumber(item.ulp),
331
+ };
332
+ }
333
+
334
+ function deviation(
335
+ actual: number,
336
+ expected: number,
337
+ index: number | undefined,
338
+ nonFinite: NumericNonFinitePolicy,
339
+ ): Deviation {
157
340
  const finite = Number.isFinite(actual) && Number.isFinite(expected);
158
- const absolute = finite ? Math.abs(actual - expected) : Number.POSITIVE_INFINITY;
159
- let relative = !finite ? null : expected === 0 ? (absolute === 0 ? 0 : null) : absolute / Math.abs(expected);
160
- if (finite && !Number.isFinite(absolute)) {
341
+ if (!finite) {
342
+ const matched = nonFinite === "match" && nonFinitePairMatches(actual, expected);
343
+ return {
344
+ ...(index !== undefined ? { index } : {}),
345
+ actual,
346
+ expected,
347
+ absolute: matched ? 0 : Number.POSITIVE_INFINITY,
348
+ relative: matched ? 0 : null,
349
+ ulp: matched ? 0 : null,
350
+ nonFinite: matched ? "matched" : "mismatched",
351
+ };
352
+ }
353
+ const absolute = Math.abs(actual - expected);
354
+ let relative = expected === 0 ? (absolute === 0 ? 0 : null) : absolute / Math.abs(expected);
355
+ if (!Number.isFinite(absolute)) {
161
356
  // Finite subtraction overflows only across signs, where division first
162
357
  // is safe. Keep subtraction first for nearby values to preserve precision.
163
358
  relative = Math.abs(actual / expected - 1);
@@ -168,12 +363,12 @@ function deviation(actual: number, expected: number, index?: number): NumericDev
168
363
  expected,
169
364
  absolute,
170
365
  relative,
171
- ulp: finite ? ulpDistance(actual, expected) : null,
366
+ ulp: ulpDistance(actual, expected),
172
367
  };
173
368
  }
174
369
 
175
- /** Tolerances the deviation violates, in schema order. Every named tolerance must hold. */
176
- function violatedTolerances(item: NumericDeviation, tolerance: NumericTolerance): NumericToleranceKind[] {
370
+ /** Named bounds the deviation violates, in schema order. */
371
+ function violatedTolerances(item: Deviation, tolerance: NumericTolerance): NumericToleranceKind[] {
177
372
  const failed: NumericToleranceKind[] = [];
178
373
  if (tolerance.relative !== undefined && (item.relative === null || item.relative > tolerance.relative)) {
179
374
  failed.push("relative");
@@ -183,15 +378,104 @@ function violatedTolerances(item: NumericDeviation, tolerance: NumericTolerance)
183
378
  return failed;
184
379
  }
185
380
 
381
+ interface ElementJudgement {
382
+ failed: NumericFailureReason[];
383
+ held: NumericToleranceKind[];
384
+ violated: NumericToleranceKind[];
385
+ }
386
+
387
+ /**
388
+ * Judge one deviation under the combination rule. A mismatched non-finite
389
+ * pair fails as not finite before any bound is consulted; a matched pair
390
+ * passes by policy with no bound consulted at all.
391
+ */
392
+ function judgeDeviation(
393
+ item: Deviation,
394
+ tolerance: NumericTolerance,
395
+ combine: NumericToleranceCombine,
396
+ ): ElementJudgement {
397
+ if (item.nonFinite === "mismatched") return { failed: ["not-finite"], held: [], violated: [] };
398
+ if (item.nonFinite === "matched") return { failed: [], held: [], violated: [] };
399
+ const violated = violatedTolerances(item, tolerance);
400
+ const held = namedKinds(tolerance).filter((kind) => !violated.includes(kind));
401
+ const passed = combine === "all" ? violated.length === 0 : held.length > 0;
402
+ return { failed: passed ? [] : violated, held, violated };
403
+ }
404
+
405
+ /**
406
+ * Worst-first rank of an element's judgement: failing, then passing with a
407
+ * violated bound (which only `combine: any` allows), then clean. Ties inside
408
+ * a tier go to the larger absolute deviation.
409
+ */
410
+ function severity(judgement: ElementJudgement): 0 | 1 | 2 {
411
+ if (judgement.failed.length > 0) return 2;
412
+ return judgement.violated.length > 0 ? 1 : 0;
413
+ }
414
+
415
+ /**
416
+ * Six significant digits with trailing fraction zeros dropped: `1.00000` reads
417
+ * `1`, `1.50000e-9` reads `1.5e-9`. An integer keeps every digit, so `500000`
418
+ * never collapses to `5`.
419
+ */
186
420
  function formatNumber(value: number): string {
187
- return Number.isFinite(value) ? value.toPrecision(6).replace(/\.?0+(e|$)/u, "$1") : String(value);
421
+ if (!Number.isFinite(value)) return String(value);
422
+ const [mantissa = "", exponent] = value.toPrecision(6).split("e");
423
+ const trimmed = mantissa.includes(".") ? mantissa.replace(/\.?0+$/u, "") : mantissa;
424
+ return exponent === undefined ? trimmed : `${trimmed}e${exponent}`;
188
425
  }
189
426
 
190
- function describeDeviation(item: NumericDeviation): string {
427
+ function describeDeviation(item: Deviation): string {
191
428
  const where = item.index === undefined ? "" : `[${item.index}]`;
429
+ if (item.nonFinite === "matched") {
430
+ return `${where} actual=${String(item.actual)} expected=${String(item.expected)} (non-finite values match by policy)`;
431
+ }
192
432
  const relative = item.relative === null ? "undefined" : formatNumber(item.relative);
193
433
  const ulp = item.ulp === null ? "undefined" : String(item.ulp);
194
- return `${where} actual=${formatNumber(item.actual)} expected=${formatNumber(item.expected)} abs=${formatNumber(item.absolute)} rel=${relative} ulp=${ulp}`;
434
+ const zeroReference =
435
+ item.nonFinite === undefined && item.expected === 0 && item.actual !== 0
436
+ ? "; relative undefined: reference is zero"
437
+ : "";
438
+ return `${where} actual=${formatNumber(item.actual)} expected=${formatNumber(item.expected)} abs=${formatNumber(item.absolute)} rel=${relative} ulp=${ulp}${zeroReference}`;
439
+ }
440
+
441
+ /**
442
+ * A declared bound, printed exactly. The shortest round-trip spelling keeps
443
+ * every digit the catalog wrote; exponent form below 1e-3 and from 1e6 up
444
+ * keeps `1e-6` readable instead of `0.000001`.
445
+ */
446
+ function formatBound(value: number): string {
447
+ if (value === 0) return "0";
448
+ const magnitude = Math.abs(value);
449
+ return magnitude < 1e-3 || magnitude >= 1e6 ? value.toExponential() : String(value);
450
+ }
451
+
452
+ function describeBound(kind: NumericToleranceKind, tolerance: NumericTolerance): string {
453
+ return `${kind}<=${formatBound(tolerance[kind] ?? 0)}`;
454
+ }
455
+
456
+ /** The effective judgement rule in words, so a reader never has to infer the conjunction from the tolerance object. */
457
+ export function describeNumericRule(tolerance: NumericTolerance): string {
458
+ const bounds = namedKinds(tolerance).map((kind) => describeBound(kind, tolerance));
459
+ const combine = effectiveNumericCombine(tolerance);
460
+ const clause =
461
+ bounds.length === 1
462
+ ? `${bounds[0]} must hold`
463
+ : combine === "all"
464
+ ? `all of ${bounds.join(", ")} must hold`
465
+ : `any of ${bounds.join(", ")} may hold`;
466
+ const nonFinite =
467
+ effectiveNumericNonFinite(tolerance) === "match"
468
+ ? "NaN matches NaN and same-signed infinities match"
469
+ : "non-finite values fail";
470
+ return `${clause}; ${nonFinite}`;
471
+ }
472
+
473
+ function passedDetail(key: string, judgement: ElementJudgement, worst: Deviation): string {
474
+ if (worst.nonFinite === "matched")
475
+ return `${key}: non-finite values match by policy, worst${describeDeviation(worst)}`;
476
+ const partial =
477
+ judgement.violated.length > 0 ? ` by ${judgement.held.join(", ")} (${judgement.violated.join(", ")} violated)` : "";
478
+ return `${key}: within tolerance${partial}, worst${describeDeviation(worst)}`;
195
479
  }
196
480
 
197
481
  function compareElements(
@@ -199,87 +483,100 @@ function compareElements(
199
483
  actual: number[],
200
484
  expected: number[],
201
485
  tolerance: NumericTolerance,
486
+ combine: NumericToleranceCombine,
487
+ nonFinite: NumericNonFinitePolicy,
202
488
  ): NumericKeyReport {
203
- let worst: NumericDeviation | undefined;
204
- let worstFailed: NumericFailureReason[] = [];
489
+ let worst: Deviation | undefined;
490
+ let worstJudgement: ElementJudgement = { failed: [], held: [], violated: [] };
205
491
  for (let index = 0; index < expected.length; index += 1) {
206
492
  const item = deviation(
207
493
  actual[index] as number,
208
494
  expected[index] as number,
209
495
  expected.length === 1 && actual.length === 1 ? undefined : index,
496
+ nonFinite,
210
497
  );
211
- const failed: NumericFailureReason[] =
212
- !Number.isFinite(item.actual) || !Number.isFinite(item.expected)
213
- ? ["not-finite"]
214
- : violatedTolerances(item, tolerance);
215
- const worse =
216
- worst === undefined ||
217
- (failed.length > 0 && worstFailed.length === 0) ||
218
- (failed.length > 0 === worstFailed.length > 0 && item.absolute > worst.absolute);
498
+ const judgement = judgeDeviation(item, tolerance, combine);
499
+ const rank = severity(judgement);
500
+ const worstRank = severity(worstJudgement);
501
+ const worse = worst === undefined || rank > worstRank || (rank === worstRank && item.absolute > worst.absolute);
219
502
  if (worse) {
220
503
  worst = item;
221
- worstFailed = failed;
504
+ worstJudgement = judgement;
222
505
  }
223
506
  }
224
- if (worst === undefined) return { key, passed: true, failed: [], detail: `${key}: empty array matches` };
225
- const passed = worstFailed.length === 0;
507
+ if (worst === undefined) {
508
+ return { key, passed: true, failed: [], held: [], violated: [], detail: `${key}: empty array matches` };
509
+ }
510
+ const passed = worstJudgement.failed.length === 0;
226
511
  return {
227
512
  key,
228
513
  passed,
229
- failed: worstFailed,
230
- worst,
514
+ failed: worstJudgement.failed,
515
+ held: worstJudgement.held,
516
+ violated: worstJudgement.violated,
517
+ worst: reportDeviation(worst),
231
518
  detail: passed
232
- ? `${key}: within tolerance, worst${describeDeviation(worst)}`
233
- : `${key}: failed ${worstFailed.join(", ")} at worst${describeDeviation(worst)}`,
519
+ ? passedDetail(key, worstJudgement, worst)
520
+ : `${key}: failed ${worstJudgement.failed.join(", ")} at worst${describeDeviation(worst)}`,
234
521
  };
235
522
  }
236
523
 
524
+ function structuralFailure(key: string, reason: NumericFailureReason, detail: string): NumericKeyReport {
525
+ return { key, passed: false, failed: [reason], held: [], violated: [], detail };
526
+ }
527
+
237
528
  /**
238
529
  * Compare a command's payload against the reference. Every key on either side
239
530
  * is judged: a key missing on one side fails and names the side, a scalar
240
531
  * against an array fails, arrays compare elementwise and fail on length
241
- * mismatch, and any NaN or infinity fails as not finite. A value passes only
242
- * when it satisfies every tolerance the catalog named.
532
+ * mismatch, and a NaN or infinity fails as not finite unless the tolerance's
533
+ * `nonFinite` policy matches the pair. A comparable value passes when the
534
+ * named bounds hold under the tolerance's `combine` rule: every bound under
535
+ * `all` (the default), at least one under `any`.
243
536
  */
244
537
  export function compareNumeric(
245
538
  actual: NumericPayload,
246
539
  reference: NumericPayload,
247
540
  tolerance: NumericTolerance,
248
541
  ): NumericCompareReport {
542
+ const combine = effectiveNumericCombine(tolerance);
543
+ const nonFinite = effectiveNumericNonFinite(tolerance);
249
544
  const keys = [...new Set([...Object.keys(reference), ...Object.keys(actual)])].sort();
250
545
  const reports: NumericKeyReport[] = [];
251
546
  for (const key of keys) {
252
547
  const got = actual[key];
253
548
  const want = reference[key];
254
549
  if (got === undefined) {
255
- reports.push({ key, passed: false, failed: ["missing-actual"], detail: `${key}: missing from the command output` });
550
+ reports.push(structuralFailure(key, "missing-actual", `${key}: missing from the command output`));
256
551
  continue;
257
552
  }
258
553
  if (want === undefined) {
259
- reports.push({ key, passed: false, failed: ["missing-reference"], detail: `${key}: missing from the reference` });
554
+ reports.push(structuralFailure(key, "missing-reference", `${key}: missing from the reference`));
260
555
  continue;
261
556
  }
262
557
  if (Array.isArray(got) !== Array.isArray(want)) {
263
- reports.push({
264
- key,
265
- passed: false,
266
- failed: ["shape-mismatch"],
267
- detail: `${key}: ${Array.isArray(got) ? "array" : "scalar"} in the command output but ${Array.isArray(want) ? "array" : "scalar"} in the reference`,
268
- });
558
+ reports.push(
559
+ structuralFailure(
560
+ key,
561
+ "shape-mismatch",
562
+ `${key}: ${Array.isArray(got) ? "array" : "scalar"} in the command output but ${Array.isArray(want) ? "array" : "scalar"} in the reference`,
563
+ ),
564
+ );
269
565
  continue;
270
566
  }
271
567
  const gotList = Array.isArray(got) ? got : [got];
272
568
  const wantList = Array.isArray(want) ? want : [want];
273
569
  if (gotList.length !== wantList.length) {
274
- reports.push({
275
- key,
276
- passed: false,
277
- failed: ["length-mismatch"],
278
- detail: `${key}: ${gotList.length} element(s) in the command output but ${wantList.length} in the reference`,
279
- });
570
+ reports.push(
571
+ structuralFailure(
572
+ key,
573
+ "length-mismatch",
574
+ `${key}: ${gotList.length} element(s) in the command output but ${wantList.length} in the reference`,
575
+ ),
576
+ );
280
577
  continue;
281
578
  }
282
- reports.push(compareElements(key, gotList, wantList, tolerance));
579
+ reports.push(compareElements(key, gotList, wantList, tolerance, combine, nonFinite));
283
580
  }
284
581
  const failedKeys = reports.filter((report) => !report.passed).map((report) => report.key);
285
582
  const passed = failedKeys.length === 0;
@@ -287,6 +584,9 @@ export function compareNumeric(
287
584
  kind: "numeric-compare",
288
585
  passed,
289
586
  tolerance: { ...tolerance },
587
+ combine,
588
+ nonFinite,
589
+ rule: describeNumericRule(tolerance),
290
590
  keys: reports,
291
591
  failedKeys,
292
592
  summary: passed
@@ -297,7 +597,15 @@ export function compareNumeric(
297
597
 
298
598
  /** The report as lines for a tool result or a receipt tail. */
299
599
  export function renderNumericReport(report: NumericCompareReport): string {
300
- const lines = [report.summary, `tolerance: ${JSON.stringify(report.tolerance)}`];
600
+ const lines = [report.summary, `rule: ${report.rule}`, `tolerance: ${JSON.stringify(report.tolerance)}`];
601
+ if (report.reference !== undefined) {
602
+ lines.push(
603
+ `reference: ${report.reference.path ?? report.reference.source} sha256=${report.reference.sha256.slice(0, 12)} (${report.reference.bytes}B)`,
604
+ );
605
+ }
606
+ if (report.actual !== undefined) {
607
+ lines.push(`actual: sha256=${report.actual.sha256.slice(0, 12)} (${report.actual.bytes}B)`);
608
+ }
301
609
  for (const key of report.keys) lines.push(`- ${key.detail}`);
302
610
  return lines.join("\n");
303
611
  }