@iowarp/clio-coder 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/NOTICE +33 -0
- package/README.md +12 -3
- package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
- package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
- package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
- package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
- package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
- package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
- package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
- package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
- package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
- package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
- package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
- package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
- package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
- package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
- package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
- package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
- package/dist/chunk-BKFM6EJV.js +462 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
- package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/chunk-C2LTL2W6.js +2447 -0
- package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
- package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
- package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
- package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
- package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
- package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
- package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/chunk-GKF55TAZ.js +391 -0
- package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
- package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
- package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
- package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
- package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
- package/dist/chunk-HZHHCK24.js +1631 -0
- package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
- package/dist/chunk-IBEBSCYA.js +564 -0
- package/dist/chunk-IQ7KR472.js +362 -0
- package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
- package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
- package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
- package/dist/chunk-KMVISBZR.js +132 -0
- package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
- package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
- package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
- package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
- package/dist/chunk-NHLBIGRH.js +1506 -0
- package/dist/chunk-NQQH3YT7.js +302 -0
- package/dist/chunk-NYS75XW5.js +15 -0
- package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
- package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
- package/dist/chunk-OQBA45DZ.js +97 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
- package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
- package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
- package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
- package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
- package/dist/chunk-SUCTJL45.js +45 -0
- package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
- package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
- package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
- package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
- package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
- package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
- package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
- package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
- package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
- package/dist/chunk-VO67MWHC.js +75 -0
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
- package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
- package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
- package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
- package/dist/chunk-X75E3D2N.js +686 -0
- package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
- package/dist/chunk-YJX4SHTD.js +40 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/chunk-Z2RR6MAK.js +127 -0
- package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
- package/dist/cli/index.js +47 -36
- package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
- package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
- package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
- package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
- package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
- package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
- package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
- package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
- package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
- package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
- package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
- package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
- package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
- package/dist/doctor-QOA5FNY5.js +313 -0
- package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
- package/dist/eval-inventory-SXH7PDKX.js +316 -0
- package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
- package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
- package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
- package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
- package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
- package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
- package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
- package/dist/fleet-inspect-VLY4S7QM.js +442 -0
- package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
- package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
- package/dist/fleet-verify-JFEL2L3H.js +175 -0
- package/dist/fleet-view-ZCON35AG.js +102 -0
- package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
- package/dist/install-XGLBQY5E.js +13 -0
- package/dist/interop-OZBKXAYL.js +114 -0
- package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
- package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
- package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
- package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
- package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
- package/dist/panes-HMABYVO4.js +58 -0
- package/dist/panes-KY6W3V2E.js +103 -0
- package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
- package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
- package/dist/resources-BB3MVJMD.js +111 -0
- package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
- package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
- package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
- package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
- package/dist/skills-inventory-S4MXPJFV.js +126 -0
- package/dist/slash-commands-ZSGASKJC.js +77 -0
- package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
- package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
- package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
- package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
- package/dist/tools-DAF3DI3C.js +27 -0
- package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
- package/dist/tui-primitives-2AKXQNZK.js +13 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
- package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
- package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
- package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
- package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
- package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
- package/dist/with-panes-MKB46MPQ.js +782 -0
- package/dist/worker/entry.js +106 -75
- package/docs/README.md +3 -2
- package/docs/acp.md +24 -3
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +9 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +62 -3
- package/docs/commands-and-modes.md +31 -2
- package/docs/configuration-and-targets.md +69 -12
- package/docs/context-engine.md +63 -4
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +3 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +12 -11
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +27 -1
- package/docs/fleet-dispatch.md +25 -4
- package/docs/installation-and-lifecycle.md +15 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +55 -4
- package/docs/proactive-memory.md +127 -14
- package/docs/prompt-envelope-and-tools.md +19 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +19 -3
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +18 -8
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +88 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +5 -2
- package/src/cli/acp.ts +6 -2
- package/src/cli/agents.ts +1 -1
- package/src/cli/argv.ts +25 -0
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/configure.ts +23 -21
- package/src/cli/doctor-panes.ts +124 -0
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor-toolchain.ts +57 -0
- package/src/cli/doctor.ts +22 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +93 -16
- package/src/cli/evidence-detail.ts +88 -0
- package/src/cli/evidence-inventory.ts +183 -0
- package/src/cli/evidence.ts +30 -5
- package/src/cli/extensions.ts +5 -1
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +810 -0
- package/src/cli/fleet.ts +179 -39
- package/src/cli/index.ts +14 -2
- package/src/cli/interop-inspect.ts +128 -0
- package/src/cli/interop.ts +34 -0
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +5 -2
- package/src/cli/run.ts +58 -0
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/targets.ts +44 -13
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +85 -5
- package/src/cli/usage.ts +63 -14
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/core/bus-events.ts +33 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/config.ts +67 -0
- package/src/core/defaults.ts +124 -8
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +80 -6
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +164 -35
- package/src/domains/config/classify.ts +6 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +52 -14
- package/src/domains/dispatch/capacity-lease.ts +118 -9
- package/src/domains/dispatch/contract.ts +11 -0
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/extension.ts +378 -82
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-run.ts +87 -4
- package/src/domains/dispatch/gate-decisions.ts +11 -1
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +22 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/reservation-store.ts +139 -11
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +598 -0
- package/src/domains/dispatch/state.ts +49 -1
- package/src/domains/dispatch/types.ts +13 -0
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/dispatch/worker-spawn.ts +25 -11
- package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
- package/src/domains/dispatch/write-boundary.ts +62 -1
- package/src/domains/eval/artifacts/store.ts +62 -0
- package/src/domains/eval/compare/behavioral.ts +224 -0
- package/src/domains/eval/compare/compare.ts +342 -2
- package/src/domains/eval/compare/envelope.ts +128 -0
- package/src/domains/eval/compare/gates.ts +24 -6
- package/src/domains/eval/compare/thresholds.ts +30 -3
- package/src/domains/eval/execution-provenance.ts +240 -0
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/metrics/aggregate.ts +136 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
- package/src/domains/eval/metrics/tracked.ts +413 -0
- package/src/domains/eval/provenance.ts +117 -0
- package/src/domains/eval/reports/comparison.ts +128 -0
- package/src/domains/eval/reports/junit.ts +17 -3
- package/src/domains/eval/reports/markdown.ts +3 -3
- package/src/domains/eval/reports/text.ts +14 -0
- package/src/domains/eval/run-compare.ts +20 -0
- package/src/domains/eval/runners/clio-run.ts +127 -0
- package/src/domains/eval/runners/external-command.ts +28 -3
- package/src/domains/eval/schema/adapter.ts +111 -0
- package/src/domains/eval/schema/artifact.ts +20 -0
- package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
- package/src/domains/eval/schema/behavioral.ts +520 -0
- package/src/domains/eval/schema/execution-envelope.ts +194 -0
- package/src/domains/eval/schema/serving.ts +105 -0
- package/src/domains/eval/schema/suite.ts +38 -8
- package/src/domains/eval/schema/validate.ts +58 -3
- package/src/domains/eval/schema/verdict.ts +237 -0
- package/src/domains/eval/suites/resolve.ts +2 -0
- package/src/domains/eval/suites/run.ts +264 -33
- package/src/domains/eval/verifiers/command.ts +2 -1
- package/src/domains/eval/workspaces/temp-copy.ts +145 -13
- package/src/domains/evidence/build.ts +2 -13
- package/src/domains/evidence/eval.ts +2 -12
- package/src/domains/evidence/findings-markdown.ts +33 -0
- package/src/domains/evidence/run-trust.ts +7 -113
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/evidence/trust-projection.ts +2 -2
- package/src/domains/extensions/compatibility.ts +285 -0
- package/src/domains/extensions/discovery.ts +38 -3
- package/src/domains/extensions/resources.ts +1 -1
- package/src/domains/extensions/state.ts +12 -3
- package/src/domains/extensions/types.ts +2 -0
- package/src/domains/lifecycle/doctor.ts +69 -1
- package/src/domains/memory/index.ts +14 -1
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +82 -17
- package/src/domains/memory/task-memory-spend.ts +131 -0
- package/src/domains/memory/task-memory-status.ts +7 -0
- package/src/domains/memory/task-memory-telemetry.ts +3 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +97 -21
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/mux/contract.ts +434 -0
- package/src/domains/mux/detect.ts +158 -0
- package/src/domains/mux/extension.ts +47 -0
- package/src/domains/mux/index.ts +96 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +164 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +49 -0
- package/src/domains/mux/socket-client.ts +816 -0
- package/src/domains/mux/types.ts +222 -0
- package/src/domains/mux/viewer-command.ts +59 -0
- package/src/domains/mux/yazi/assets/init.lua +2 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
- package/src/domains/mux/yazi/assets/yazi.toml +17 -0
- package/src/domains/mux/yazi/event-stream.ts +180 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +228 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +22 -1
- package/src/domains/observability/index.ts +9 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +234 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/providers/endpoint-capacity.ts +228 -0
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +20 -3
- package/src/domains/providers/index.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +32 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
- package/src/domains/providers/runtime-resolution.ts +8 -1
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
- package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/prompts/loader.ts +95 -33
- package/src/domains/resources/skills/loader.ts +33 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/safety/call-target.ts +52 -0
- package/src/domains/safety/run-effects.ts +35 -4
- package/src/domains/session/context-accounting.ts +52 -1
- package/src/domains/session/context-ledger.ts +37 -13
- package/src/domains/session/index.ts +6 -0
- package/src/domains/session/prompt-cache.ts +140 -0
- package/src/domains/session/prompt-manifest.ts +42 -0
- package/src/domains/toolchain/archive.ts +175 -0
- package/src/domains/toolchain/contract.ts +28 -0
- package/src/domains/toolchain/extension.ts +47 -0
- package/src/domains/toolchain/index.ts +39 -0
- package/src/domains/toolchain/install.ts +327 -0
- package/src/domains/toolchain/manifest.ts +8 -0
- package/src/domains/toolchain/paths.ts +34 -0
- package/src/domains/toolchain/registry.ts +265 -0
- package/src/domains/toolchain/remove.ts +218 -0
- package/src/domains/toolchain/resolve.ts +182 -0
- package/src/domains/toolchain/types.ts +113 -0
- package/src/domains/toolchain/version.ts +88 -0
- package/src/engine/acp/adapter.ts +18 -3
- package/src/engine/acp/server.ts +413 -70
- package/src/engine/acp/types.ts +19 -1
- package/src/engine/ai.ts +35 -0
- package/src/engine/apis/llamacpp-residency.ts +55 -3
- package/src/engine/apis/lmstudio.ts +25 -5
- package/src/engine/apis/ollama-native.ts +2 -1
- package/src/engine/apis/openai-completions.ts +80 -17
- package/src/engine/apis/residency-lock.ts +3 -1
- package/src/engine/apis/residency.ts +34 -1
- package/src/engine/claude/sdk-module.ts +98 -0
- package/src/engine/claude/sdk-runtime.ts +19 -11
- package/src/engine/provider-payload.ts +29 -1
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-runtime.ts +2 -13
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +279 -35
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/chat-loop-messages.ts +26 -7
- package/src/interactive/chat-loop.ts +318 -41
- package/src/interactive/chat-panel.ts +62 -8
- package/src/interactive/clio-editor.ts +45 -8
- package/src/interactive/context-activity.ts +5 -1
- package/src/interactive/context-meter.ts +1 -1
- package/src/interactive/context-overlay.ts +41 -10
- package/src/interactive/cost-overlay.ts +66 -6
- package/src/interactive/council-grid.ts +1 -3
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +102 -20
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +177 -7
- package/src/interactive/interactive-input-runtime.ts +15 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +63 -10
- package/src/interactive/memory-overlay.ts +9 -0
- package/src/interactive/modal-marker.ts +170 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +58 -2
- package/src/interactive/overlay-general-openers.ts +17 -0
- package/src/interactive/overlay-key-routing.ts +52 -3
- package/src/interactive/overlay-lifecycle.ts +56 -7
- package/src/interactive/overlay-model-selectors.ts +40 -3
- package/src/interactive/overlay-permission-lifecycle.ts +112 -24
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +1 -0
- package/src/interactive/overlays/ask-user.ts +227 -49
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +1 -0
- package/src/interactive/overlays/cwd-fallback.ts +1 -0
- package/src/interactive/overlays/decisions.ts +11 -11
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +1 -0
- package/src/interactive/overlays/handoff-review.ts +1 -0
- package/src/interactive/overlays/help-reference.ts +6 -0
- package/src/interactive/overlays/interop.ts +1 -0
- package/src/interactive/overlays/library-install-confirm.ts +1 -0
- package/src/interactive/overlays/library-tabs.ts +28 -0
- package/src/interactive/overlays/list-overlay.ts +10 -1
- package/src/interactive/overlays/message-picker.ts +1 -0
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +1 -0
- package/src/interactive/overlays/prompts.ts +12 -1
- package/src/interactive/overlays/session-selector.ts +1 -0
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +614 -45
- package/src/interactive/overlays/side-question.ts +1 -0
- package/src/interactive/overlays/skills-hub.ts +3 -11
- package/src/interactive/overlays/tree-selector.ts +1 -0
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +292 -0
- package/src/interactive/permission-hint.ts +34 -2
- package/src/interactive/permission-overlay.ts +159 -9
- package/src/interactive/prewarm.ts +197 -0
- package/src/interactive/render-trace.ts +162 -15
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/tool-execution.ts +4 -0
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/side-question.ts +58 -1
- package/src/interactive/slash-commands.ts +251 -15
- package/src/interactive/status/controller.ts +11 -0
- package/src/interactive/status/state-machine.ts +54 -2
- package/src/interactive/status/types.ts +7 -0
- package/src/interactive/tasks-overlay.ts +1 -0
- package/src/interactive/terminal-lease.ts +2 -0
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +346 -33
- package/src/interactive/turn-persistence.ts +14 -4
- package/src/interactive/turn-prewarm.ts +364 -0
- package/src/interactive/turn-queues.ts +7 -4
- package/src/interactive/turn-runtime.ts +8 -1
- package/src/interactive/turn-state.ts +23 -0
- package/src/interactive/view/artifacts.ts +109 -1
- package/src/interactive/view/view-overlay.ts +29 -3
- package/src/interactive/watch-pane.ts +152 -0
- package/src/interactive/worker-progress.ts +7 -1
- package/src/interactive/worker-receipts.ts +19 -1
- package/src/interactive/worker-stream.ts +5 -0
- package/src/interactive/yazi-bridge.ts +444 -0
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +15 -0
- package/src/tools/compete-worktrees.ts +83 -2
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +14 -3
- package/src/tools/dispatch-arguments.ts +20 -20
- package/src/tools/dispatch-plan.ts +17 -9
- package/src/tools/dispatch-run-events.ts +134 -19
- package/src/tools/dispatch-runner.ts +29 -7
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +1 -1
- package/src/tools/executables.ts +17 -14
- package/src/tools/observation.ts +54 -4
- package/src/tools/panes-surface.ts +38 -0
- package/src/tools/panes.ts +112 -0
- package/src/tools/policy.ts +10 -1
- package/src/tools/presentation.ts +1 -0
- package/src/tools/registry.ts +16 -0
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HLE42MG7.js +0 -37
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-JOZYP4GM.js +0 -279
- package/dist/doctor-M7YEDGAE.js +0 -91
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
import { isExecutionRole } from "./execution-role.js";
|
|
22
22
|
import { COMPETE_STANCES, type CompeteStance } from "./gate-role-prompts.js";
|
|
23
23
|
import { type DispatchIntent, isDispatchIntent } from "./intent.js";
|
|
24
|
+
import { classifyDispatchIntentCompatibility, dispatchIntentRefusals } from "./intent-compatibility.js";
|
|
24
25
|
import { isRoutingIntent, type RoutingIntent } from "./routing-intent.js";
|
|
25
26
|
import type {
|
|
26
27
|
DispatchRequestOrigin,
|
|
@@ -478,14 +479,21 @@ export function validateJobSpec(spec: unknown): Validated {
|
|
|
478
479
|
errors.push("writeRoots must be a non-empty array of non-empty strings");
|
|
479
480
|
}
|
|
480
481
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
482
|
+
// One owner for the typed-intent migration rules (#163). Every dispatch
|
|
483
|
+
// producer reaches a worker through this validator, so classifying here is
|
|
484
|
+
// what makes the compatibility table true of the fleet, CLI, ACP, and
|
|
485
|
+
// extension paths rather than only of the model-facing tool.
|
|
486
|
+
if ("intent" in spec) {
|
|
487
|
+
for (const refusal of dispatchIntentRefusals(
|
|
488
|
+
classifyDispatchIntentCompatibility({
|
|
489
|
+
intent: spec.intent,
|
|
490
|
+
...(spec.writeRoots !== undefined ? { writeRoots: spec.writeRoots } : {}),
|
|
491
|
+
...(spec.autonomy !== undefined ? { autonomy: spec.autonomy } : {}),
|
|
492
|
+
...(typeof spec.cwd === "string" && spec.cwd.length > 0 ? { cwd: spec.cwd } : {}),
|
|
493
|
+
}),
|
|
494
|
+
)) {
|
|
495
|
+
errors.push(refusal.message);
|
|
496
|
+
}
|
|
489
497
|
}
|
|
490
498
|
|
|
491
499
|
if ("requestOrigin" in spec && spec.requestOrigin !== undefined) {
|
|
@@ -696,6 +704,8 @@ function isValidProtectedArtifactRemap(value: unknown): value is ProtectedArtifa
|
|
|
696
704
|
|
|
697
705
|
const VALID_GATE_ROLES = new Set(["builder", "reviewer", "candidate", "judge", "member", "synthesis"]);
|
|
698
706
|
const VALID_GATE_VERDICTS = new Set(["pass", "fail", "revise"]);
|
|
707
|
+
const VALID_WORKTREE_BACKENDS = new Set(["herdr", "native"]);
|
|
708
|
+
const VALID_WORKTREE_FALLBACKS = new Set(["mux-unavailable", "mux-operation-failed"]);
|
|
699
709
|
const VALID_PLAN_TOPOLOGIES = new Set([
|
|
700
710
|
"parallel",
|
|
701
711
|
"sequential",
|
|
@@ -724,6 +734,20 @@ function isValidGate(value: unknown): value is RunGateProvenance {
|
|
|
724
734
|
if (value.verdict !== undefined && (typeof value.verdict !== "string" || !VALID_GATE_VERDICTS.has(value.verdict))) {
|
|
725
735
|
return false;
|
|
726
736
|
}
|
|
737
|
+
if (value.worktree !== undefined) {
|
|
738
|
+
if (!isPlainObject(value.worktree)) return false;
|
|
739
|
+
if (typeof value.worktree.backend !== "string" || !VALID_WORKTREE_BACKENDS.has(value.worktree.backend)) return false;
|
|
740
|
+
if (typeof value.worktree.path !== "string" || !path.isAbsolute(value.worktree.path)) return false;
|
|
741
|
+
if (typeof value.worktree.branch !== "string" || value.worktree.branch.length === 0) return false;
|
|
742
|
+
if (value.worktree.workspaceId !== undefined && typeof value.worktree.workspaceId !== "string") return false;
|
|
743
|
+
if (
|
|
744
|
+
value.worktree.fallback !== undefined &&
|
|
745
|
+
(typeof value.worktree.fallback !== "string" || !VALID_WORKTREE_FALLBACKS.has(value.worktree.fallback))
|
|
746
|
+
) {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
if (value.worktree.backend === "herdr" && typeof value.worktree.workspaceId !== "string") return false;
|
|
750
|
+
}
|
|
727
751
|
return true;
|
|
728
752
|
}
|
|
729
753
|
|
|
@@ -734,6 +758,7 @@ function cloneGate(gate: RunGateProvenance): RunGateProvenance {
|
|
|
734
758
|
cycle: gate.cycle,
|
|
735
759
|
...(gate.subjects !== undefined ? { subjects: gate.subjects.map((subject) => ({ ...subject })) } : {}),
|
|
736
760
|
...(gate.verdict !== undefined ? { verdict: gate.verdict } : {}),
|
|
761
|
+
...(gate.worktree !== undefined ? { worktree: { ...gate.worktree } } : {}),
|
|
737
762
|
};
|
|
738
763
|
}
|
|
739
764
|
|
|
@@ -26,10 +26,12 @@
|
|
|
26
26
|
|
|
27
27
|
import { type ChildProcess, spawn } from "node:child_process";
|
|
28
28
|
import { join } from "node:path";
|
|
29
|
+
import { performance } from "node:perf_hooks";
|
|
29
30
|
import { withClioAgentEnvironment } from "../../core/agent-environment.js";
|
|
30
31
|
import { enableClioCompileCache, workerCompileCacheEnvironment } from "../../core/compile-cache.js";
|
|
31
32
|
import { resolvePackageRoot } from "../../core/package-root.js";
|
|
32
33
|
import type { WorkerSpec } from "../../worker/spec-contract.js";
|
|
34
|
+
import type { HeartbeatStamp } from "./heartbeat.js";
|
|
33
35
|
import {
|
|
34
36
|
type AgentLedgerBody,
|
|
35
37
|
type ApprovedWorkerIdentity,
|
|
@@ -71,7 +73,7 @@ export interface SpawnedWorker {
|
|
|
71
73
|
promise: Promise<SpawnedWorkerResult>;
|
|
72
74
|
events: AsyncIterableIterator<unknown>;
|
|
73
75
|
abort(): void;
|
|
74
|
-
heartbeatAt:
|
|
76
|
+
heartbeatAt: HeartbeatStamp;
|
|
75
77
|
/**
|
|
76
78
|
* Write one JSON line to the worker's open stdin (the same line protocol
|
|
77
79
|
* that carried the spec). Returns false when the worker has exited, its
|
|
@@ -134,15 +136,14 @@ export interface WorkerProcessOptions {
|
|
|
134
136
|
/** How long bulk output may precede the announce before the peer is refused. */
|
|
135
137
|
attestationGraceMs?: number;
|
|
136
138
|
/**
|
|
137
|
-
*
|
|
138
|
-
* a wall-clock instant
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* two wall-clock reads taken either side of an interval orders them backward
|
|
142
|
-
* on any host that resyncs its clock in between. A test injects the steppable
|
|
143
|
-
* clock from tests/harness/clock.ts here and asserts on that instead.
|
|
139
|
+
* Wall clock behind the heartbeat anchor, defaulting to `Date.now`. The
|
|
140
|
+
* anchor stays a wall-clock instant because the ledger and evidence record
|
|
141
|
+
* serialize the derived heartbeat as ISO-8601 for an operator to read. This
|
|
142
|
+
* clock is read once; later heartbeat instants add a monotonic span to it.
|
|
144
143
|
*/
|
|
145
144
|
now?: () => number;
|
|
145
|
+
/** Monotonic clock used for heartbeat spans, defaulting to `performance.now`. */
|
|
146
|
+
monotonicNow?: () => number;
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
/**
|
|
@@ -192,6 +193,7 @@ export function spawnWorkerProcess(
|
|
|
192
193
|
const shutdownGraceMs = opts?.shutdownGraceMs ?? DEFAULT_SHUTDOWN_GRACE_MS;
|
|
193
194
|
const attestationGraceMs = opts?.attestationGraceMs ?? DEFAULT_ATTESTATION_GRACE_MS;
|
|
194
195
|
const now = opts?.now ?? Date.now;
|
|
196
|
+
const monotonicNow = opts?.monotonicNow ?? (() => performance.now());
|
|
195
197
|
const approved = opts?.approvedIdentity ?? approvedIdentityForSpec(spec);
|
|
196
198
|
|
|
197
199
|
const child: ChildProcess = spawn(command, [...args], {
|
|
@@ -204,7 +206,19 @@ export function spawnWorkerProcess(
|
|
|
204
206
|
});
|
|
205
207
|
const pid = child.pid ?? null;
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
// One wall anchor plus a monotonic span keeps the persisted/display instant
|
|
210
|
+
// readable without ever asking a later wall-clock read how much time passed.
|
|
211
|
+
const heartbeatWallAnchor = now();
|
|
212
|
+
const heartbeatMonotonicAnchor = monotonicNow();
|
|
213
|
+
const heartbeatAt: HeartbeatStamp = {
|
|
214
|
+
current: heartbeatWallAnchor,
|
|
215
|
+
monotonic: heartbeatMonotonicAnchor,
|
|
216
|
+
};
|
|
217
|
+
const stampHeartbeat = (): void => {
|
|
218
|
+
const stamp = monotonicNow();
|
|
219
|
+
heartbeatAt.monotonic = stamp;
|
|
220
|
+
heartbeatAt.current = heartbeatWallAnchor + (stamp - heartbeatMonotonicAnchor);
|
|
221
|
+
};
|
|
208
222
|
|
|
209
223
|
const queue = createBoundedEventQueue();
|
|
210
224
|
const waiters: Array<(r: IteratorResult<unknown>) => void> = [];
|
|
@@ -233,7 +247,7 @@ export function spawnWorkerProcess(
|
|
|
233
247
|
}
|
|
234
248
|
|
|
235
249
|
function push(value: unknown): void {
|
|
236
|
-
|
|
250
|
+
stampHeartbeat();
|
|
237
251
|
const w = waiters.shift();
|
|
238
252
|
if (w) {
|
|
239
253
|
w({ value, done: false });
|
|
@@ -378,7 +392,7 @@ export function spawnWorkerProcess(
|
|
|
378
392
|
if (!announceAccepted) failAttestation(`Invalid worker attestation: ${frame.reason}`);
|
|
379
393
|
return;
|
|
380
394
|
}
|
|
381
|
-
|
|
395
|
+
stampHeartbeat();
|
|
382
396
|
if (frame.value.kind === "announce") {
|
|
383
397
|
if (announceAccepted || announceFailed) return;
|
|
384
398
|
const verdict = verifyWorkerAttestation(frame.value.attestation, approved);
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
enforceWriteBoundary,
|
|
27
27
|
type WorkspaceSnapshot,
|
|
28
28
|
type WriteBoundaryAttribution,
|
|
29
|
+
type WriteBoundaryAttributionDowngrade,
|
|
29
30
|
type WriteBoundaryVerdict,
|
|
30
31
|
writeWriteBoundaryVerdict,
|
|
31
32
|
} from "./write-boundary.js";
|
|
@@ -45,7 +46,7 @@ export interface WriteBoundaryEnforcerInput {
|
|
|
45
46
|
* argument names. Absent entirely means the caller offers no record at all,
|
|
46
47
|
* and every change outside the declaration is blamed on the window.
|
|
47
48
|
*/
|
|
48
|
-
recordedWritesFor?(stepId: string): ReadonlyArray<string> | null;
|
|
49
|
+
recordedWritesFor?(stepId: string): ReadonlyArray<string> | WriteBoundaryAttribution | null;
|
|
49
50
|
/** Called once per closed window with the sealed verdict and where it landed. */
|
|
50
51
|
onVerdict?(verdict: WriteBoundaryVerdict, path: string): void;
|
|
51
52
|
}
|
|
@@ -91,16 +92,32 @@ export function createWriteBoundaryEnforcer(input: WriteBoundaryEnforcerInput):
|
|
|
91
92
|
const recordedWritesFor = input.recordedWritesFor;
|
|
92
93
|
if (recordedWritesFor === undefined) return undefined;
|
|
93
94
|
const recorded = new Set<string>();
|
|
95
|
+
const downgrades: WriteBoundaryAttributionDowngrade[] = [];
|
|
94
96
|
let complete = true;
|
|
95
97
|
for (const stepId of stepIds) {
|
|
96
98
|
const observed = recordedWritesFor(stepId);
|
|
97
99
|
if (observed === null) {
|
|
98
100
|
complete = false;
|
|
101
|
+
downgrades.push({
|
|
102
|
+
reason: "write_record_unavailable",
|
|
103
|
+
tool: null,
|
|
104
|
+
toolCallId: null,
|
|
105
|
+
runId: null,
|
|
106
|
+
stepId,
|
|
107
|
+
});
|
|
99
108
|
continue;
|
|
100
109
|
}
|
|
101
|
-
|
|
110
|
+
if (!("recorded" in observed)) {
|
|
111
|
+
for (const target of observed) recorded.add(target);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
for (const target of observed.recorded) recorded.add(target);
|
|
115
|
+
if (!observed.complete) complete = false;
|
|
116
|
+
for (const downgrade of observed.downgrades ?? []) {
|
|
117
|
+
downgrades.push({ ...downgrade, stepId: downgrade.stepId ?? stepId });
|
|
118
|
+
}
|
|
102
119
|
}
|
|
103
|
-
return { recorded: [...recorded].sort(), complete };
|
|
120
|
+
return { recorded: [...recorded].sort(), complete, downgrades };
|
|
104
121
|
};
|
|
105
122
|
return {
|
|
106
123
|
begin(window, stepIds) {
|
|
@@ -283,6 +283,49 @@ export interface WriteBoundaryAttribution {
|
|
|
283
283
|
* change outside the allowlist, and the verdict says it did.
|
|
284
284
|
*/
|
|
285
285
|
complete: boolean;
|
|
286
|
+
/** Durable causes for an incomplete record. Empty only when complete is true. */
|
|
287
|
+
downgrades?: ReadonlyArray<WriteBoundaryAttributionDowngrade>;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export type WriteBoundaryAttributionDowngradeReason =
|
|
291
|
+
| "opaque_tool_succeeded"
|
|
292
|
+
| "incomplete_tool_telemetry"
|
|
293
|
+
| "code_step_untracked"
|
|
294
|
+
| "write_record_unavailable";
|
|
295
|
+
|
|
296
|
+
/** Why one step could not offer a closed write record. */
|
|
297
|
+
export interface WriteBoundaryAttributionDowngrade {
|
|
298
|
+
reason: WriteBoundaryAttributionDowngradeReason;
|
|
299
|
+
/** Tool whose successful call opened the record, or null for a non-tool cause. */
|
|
300
|
+
tool: string | null;
|
|
301
|
+
/** Exact worker call when telemetry supplied one, or null for a non-tool cause. */
|
|
302
|
+
toolCallId: string | null;
|
|
303
|
+
/** Run that observed the cause, when one reached dispatch. */
|
|
304
|
+
runId: string | null;
|
|
305
|
+
/** Fleet step whose record was downgraded. */
|
|
306
|
+
stepId: string | null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** One operator-facing explanation shared by live and durable surfaces. */
|
|
310
|
+
export function describeWriteBoundaryAttributionDowngrade(downgrade: WriteBoundaryAttributionDowngrade): string {
|
|
311
|
+
if (downgrade.reason === "opaque_tool_succeeded") {
|
|
312
|
+
const tool = downgrade.tool ?? "unknown";
|
|
313
|
+
const call = downgrade.toolCallId === null ? "" : ` (call ${downgrade.toolCallId})`;
|
|
314
|
+
return `a successful '${tool}' call${call} can write paths its arguments do not name`;
|
|
315
|
+
}
|
|
316
|
+
if (downgrade.reason === "incomplete_tool_telemetry") {
|
|
317
|
+
return downgrade.runId === null
|
|
318
|
+
? "tool telemetry was incomplete"
|
|
319
|
+
: `run '${downgrade.runId}' reported incomplete tool telemetry`;
|
|
320
|
+
}
|
|
321
|
+
if (downgrade.reason === "code_step_untracked") {
|
|
322
|
+
return downgrade.stepId === null
|
|
323
|
+
? "a code step ran through the untracked command runner"
|
|
324
|
+
: `code step '${downgrade.stepId}' ran through the untracked command runner`;
|
|
325
|
+
}
|
|
326
|
+
return downgrade.stepId === null
|
|
327
|
+
? "no usable write record was available"
|
|
328
|
+
: `step '${downgrade.stepId}' supplied no usable write record`;
|
|
286
329
|
}
|
|
287
330
|
|
|
288
331
|
export interface WriteBoundaryVerdict {
|
|
@@ -307,6 +350,8 @@ export interface WriteBoundaryVerdict {
|
|
|
307
350
|
unattributed: ReadonlyArray<string>;
|
|
308
351
|
/** Whether every step in the window offered an enumerable write record. */
|
|
309
352
|
attributionComplete: boolean;
|
|
353
|
+
/** Why attribution was incomplete, including the causal tool call when known. */
|
|
354
|
+
attributionDowngrades: ReadonlyArray<WriteBoundaryAttributionDowngrade>;
|
|
310
355
|
rolledBack: ReadonlyArray<WriteBoundaryRollback>;
|
|
311
356
|
unrecoverable: ReadonlyArray<WriteBoundaryUnrecoverable>;
|
|
312
357
|
status: WriteBoundaryStatus;
|
|
@@ -417,6 +462,19 @@ export function enforceWriteBoundary(input: EnforceWriteBoundaryInput): WriteBou
|
|
|
417
462
|
const changes = diffWorkspace(input.snapshot);
|
|
418
463
|
const outside = changes.filter((change) => !writeBoundaryCovers(allow, change.path));
|
|
419
464
|
const attributionComplete = input.attribution?.complete === true;
|
|
465
|
+
const attributionDowngrades: ReadonlyArray<WriteBoundaryAttributionDowngrade> = attributionComplete
|
|
466
|
+
? []
|
|
467
|
+
: input.attribution?.downgrades !== undefined && input.attribution.downgrades.length > 0
|
|
468
|
+
? input.attribution.downgrades.map((entry) => ({ ...entry }))
|
|
469
|
+
: [
|
|
470
|
+
{
|
|
471
|
+
reason: "write_record_unavailable",
|
|
472
|
+
tool: null,
|
|
473
|
+
toolCallId: null,
|
|
474
|
+
runId: null,
|
|
475
|
+
stepId: input.stepIds.length === 1 ? (input.stepIds[0] ?? null) : null,
|
|
476
|
+
},
|
|
477
|
+
];
|
|
420
478
|
const recorded = new Set<string>();
|
|
421
479
|
for (const target of input.attribution?.recorded ?? []) {
|
|
422
480
|
const relativeTarget = repoRelative(input.snapshot.root, target);
|
|
@@ -457,7 +515,9 @@ export function enforceWriteBoundary(input: EnforceWriteBoundaryInput): WriteBou
|
|
|
457
515
|
.join("; ")}.`,
|
|
458
516
|
attributionComplete
|
|
459
517
|
? "Each was blamed on this window because a run in it recorded writing that path."
|
|
460
|
-
:
|
|
518
|
+
: `Attribution was incomplete because ${attributionDowngrades
|
|
519
|
+
.map(describeWriteBoundaryAttributionDowngrade)
|
|
520
|
+
.join("; ")}, so every change outside the declaration was blamed on this window.`,
|
|
461
521
|
"If the change was legitimate, widen the step's `writes:` declaration to cover it.",
|
|
462
522
|
];
|
|
463
523
|
const concurrentDetail =
|
|
@@ -482,6 +542,7 @@ export function enforceWriteBoundary(input: EnforceWriteBoundaryInput): WriteBou
|
|
|
482
542
|
violations: violations.map((change) => change.path),
|
|
483
543
|
unattributed: unattributed.map((change) => change.path),
|
|
484
544
|
attributionComplete,
|
|
545
|
+
attributionDowngrades,
|
|
485
546
|
rolledBack,
|
|
486
547
|
unrecoverable,
|
|
487
548
|
status,
|
|
@@ -3,6 +3,11 @@ import { join } from "node:path";
|
|
|
3
3
|
import { assertSafeId } from "../../../core/safe-id.js";
|
|
4
4
|
import { safeResourceWrite } from "../../../core/safe-resource-write.js";
|
|
5
5
|
import type { EvalArtifactV4, EvalTokenAccountingV4 } from "../schema/artifact.js";
|
|
6
|
+
import { assertEvalBehaviorReferencesVerdictV1, parseEvalBehaviorVerdictV1 } from "../schema/behavioral.js";
|
|
7
|
+
import { parseEvalBehaviorMetricsV1 } from "../schema/behavioral-metrics.js";
|
|
8
|
+
import { parseEvalExecutionEnvelopeV1, parseEvalExecutionMatrixDimensionsV1 } from "../schema/execution-envelope.js";
|
|
9
|
+
import { parseEvalServingConfigurationV1 } from "../schema/serving.js";
|
|
10
|
+
import { parseEvalVerdictEnvelopeV1 } from "../schema/verdict.js";
|
|
6
11
|
import { evalRoot } from "../store.js";
|
|
7
12
|
import { redactArtifactForStorage } from "./redact.js";
|
|
8
13
|
|
|
@@ -45,6 +50,14 @@ export function parseEvalArtifactV4(value: unknown, source: string): EvalArtifac
|
|
|
45
50
|
const summary = asRecord(value.summary, `${source}.summary`);
|
|
46
51
|
const matrix = asRecord(value.matrix, `${source}.matrix`);
|
|
47
52
|
const suite = asRecord(value.suite, `${source}.suite`);
|
|
53
|
+
const servingConfiguration =
|
|
54
|
+
value.servingConfiguration === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: parseEvalServingConfigurationV1(value.servingConfiguration, `${source}.servingConfiguration`);
|
|
57
|
+
const aggregates =
|
|
58
|
+
value.aggregates === undefined
|
|
59
|
+
? undefined
|
|
60
|
+
: (readArray(value, source, "aggregates") as NonNullable<EvalArtifactV4["aggregates"]>);
|
|
48
61
|
return {
|
|
49
62
|
version: 4,
|
|
50
63
|
evalId: readString(value, source, "evalId"),
|
|
@@ -62,7 +75,11 @@ export function parseEvalArtifactV4(value: unknown, source: string): EvalArtifac
|
|
|
62
75
|
target: readString(matrix, `${source}.matrix`, "target"),
|
|
63
76
|
model: readNullableString(matrix, `${source}.matrix`, "model"),
|
|
64
77
|
thinking: readNullableString(matrix, `${source}.matrix`, "thinking"),
|
|
78
|
+
...(matrix.dimensions === undefined
|
|
79
|
+
? {}
|
|
80
|
+
: { dimensions: parseEvalExecutionMatrixDimensionsV1(matrix.dimensions, `${source}.matrix.dimensions`) }),
|
|
65
81
|
},
|
|
82
|
+
...(servingConfiguration === undefined ? {} : { servingConfiguration }),
|
|
66
83
|
summary: {
|
|
67
84
|
runs: readNumber(summary, `${source}.summary`, "runs"),
|
|
68
85
|
passed: readNumber(summary, `${source}.summary`, "passed"),
|
|
@@ -71,6 +88,7 @@ export function parseEvalArtifactV4(value: unknown, source: string): EvalArtifac
|
|
|
71
88
|
tokens: parseTokenAccounting(summary.tokens, `${source}.summary.tokens`),
|
|
72
89
|
wallTimeMs: readNumber(summary, `${source}.summary`, "wallTimeMs"),
|
|
73
90
|
},
|
|
91
|
+
...(aggregates === undefined ? {} : { aggregates }),
|
|
74
92
|
results: readArray(value, source, "results").map((entry, index) => parseResult(entry, `${source}.results[${index}]`)),
|
|
75
93
|
};
|
|
76
94
|
}
|
|
@@ -108,6 +126,46 @@ function parseTokenAccounting(value: unknown, source: string): EvalTokenAccounti
|
|
|
108
126
|
function parseResult(value: unknown, source: string): EvalArtifactV4["results"][number] {
|
|
109
127
|
const record = asRecord(value, source);
|
|
110
128
|
const target = asRecord(record.target, `${source}.target`);
|
|
129
|
+
const verdict =
|
|
130
|
+
record.verdict === undefined ? undefined : parseEvalVerdictEnvelopeV1(record.verdict, `${source}.verdict`);
|
|
131
|
+
const behavioral =
|
|
132
|
+
record.behavioral === undefined ? undefined : parseEvalBehaviorVerdictV1(record.behavioral, `${source}.behavioral`);
|
|
133
|
+
const behavioralMetrics =
|
|
134
|
+
record.behavioralMetrics === undefined
|
|
135
|
+
? undefined
|
|
136
|
+
: parseEvalBehaviorMetricsV1(record.behavioralMetrics, `${source}.behavioralMetrics`);
|
|
137
|
+
const executionEnvelope =
|
|
138
|
+
record.executionEnvelope === undefined
|
|
139
|
+
? undefined
|
|
140
|
+
: parseEvalExecutionEnvelopeV1(record.executionEnvelope, `${source}.executionEnvelope`);
|
|
141
|
+
if (behavioral !== undefined && verdict === undefined) {
|
|
142
|
+
throw new Error(`${source}.behavioral: sibling document requires a verdict`);
|
|
143
|
+
}
|
|
144
|
+
if (behavioral !== undefined && verdict !== undefined) {
|
|
145
|
+
assertEvalBehaviorReferencesVerdictV1(behavioral, verdict, `${source}.behavioral`);
|
|
146
|
+
}
|
|
147
|
+
if (behavioralMetrics !== undefined) {
|
|
148
|
+
if (behavioral === undefined) throw new Error(`${source}.behavioralMetrics: requires a behavioral verdict`);
|
|
149
|
+
if (behavioralMetrics.scenarioId !== readString(record, source, "taskId")) {
|
|
150
|
+
throw new Error(`${source}.behavioralMetrics.scenarioId: conflicts with result taskId`);
|
|
151
|
+
}
|
|
152
|
+
if (
|
|
153
|
+
behavioralMetrics.target.id !== readString(target, `${source}.target`, "id") ||
|
|
154
|
+
behavioralMetrics.target.model !== readNullableString(target, `${source}.target`, "model")
|
|
155
|
+
) {
|
|
156
|
+
throw new Error(`${source}.behavioralMetrics.target: conflicts with result target`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (executionEnvelope !== undefined) {
|
|
160
|
+
if (behavioral === undefined) throw new Error(`${source}.executionEnvelope: requires a behavioral verdict`);
|
|
161
|
+
if (
|
|
162
|
+
executionEnvelope.target !== readString(target, `${source}.target`, "id") ||
|
|
163
|
+
executionEnvelope.corpus.id !== behavioral.corpus.id ||
|
|
164
|
+
executionEnvelope.corpus.version !== behavioral.corpus.version
|
|
165
|
+
) {
|
|
166
|
+
throw new Error(`${source}.executionEnvelope: conflicts with result target or behavioral corpus`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
111
169
|
return {
|
|
112
170
|
assignmentId: readNullableString(record, source, "assignmentId"),
|
|
113
171
|
terminalReceiptDigest: readNullableDigest(record, source, "terminalReceiptDigest"),
|
|
@@ -122,6 +180,10 @@ function parseResult(value: unknown, source: string): EvalArtifactV4["results"][
|
|
|
122
180
|
failureClass: readNullableString(record, source, "failureClass"),
|
|
123
181
|
metrics: asRecord(record.metrics, `${source}.metrics`) as Record<string, number | string | boolean | null>,
|
|
124
182
|
artifacts: asRecord(record.artifacts, `${source}.artifacts`) as Record<string, string | string[] | null>,
|
|
183
|
+
...(verdict === undefined ? {} : { verdict }),
|
|
184
|
+
...(behavioral === undefined ? {} : { behavioral }),
|
|
185
|
+
...(behavioralMetrics === undefined ? {} : { behavioralMetrics }),
|
|
186
|
+
...(executionEnvelope === undefined ? {} : { executionEnvelope }),
|
|
125
187
|
};
|
|
126
188
|
}
|
|
127
189
|
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { EvalArtifactResultV4, EvalArtifactV4 } from "../schema/artifact.js";
|
|
2
|
+
import {
|
|
3
|
+
EVAL_BEHAVIOR_METRIC_DEFINITIONS_V1,
|
|
4
|
+
type EvalBehaviorMetricDefinitionV1,
|
|
5
|
+
type EvalBehaviorMetricFamilyV1,
|
|
6
|
+
type EvalBehaviorMetricNameV1,
|
|
7
|
+
type EvalBehaviorMetricSourceV1,
|
|
8
|
+
} from "../schema/behavioral-metrics.js";
|
|
9
|
+
import type { EvalExecutionMatrixDimensionV1 } from "../schema/execution-envelope.js";
|
|
10
|
+
import {
|
|
11
|
+
compareEvalExecutionEnvelopesV1,
|
|
12
|
+
type EvalEnvelopeComparabilityV1,
|
|
13
|
+
type EvalEnvelopeMismatchV1,
|
|
14
|
+
} from "./envelope.js";
|
|
15
|
+
|
|
16
|
+
export type EvalMetricChangeV1 = "improved" | "regressed" | "unchanged" | "incomparable";
|
|
17
|
+
|
|
18
|
+
export interface EvalBehaviorMetricDistributionV1 {
|
|
19
|
+
observations: number;
|
|
20
|
+
measured: number;
|
|
21
|
+
unmeasured: number;
|
|
22
|
+
mean: number | null;
|
|
23
|
+
min: number | null;
|
|
24
|
+
max: number | null;
|
|
25
|
+
p90: number | null;
|
|
26
|
+
variance: number | null;
|
|
27
|
+
standardDeviation: number | null;
|
|
28
|
+
source: EvalBehaviorMetricSourceV1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface EvalBehaviorMetricComparisonV1 {
|
|
32
|
+
scenarioId: string;
|
|
33
|
+
role: string;
|
|
34
|
+
target: { id: string; model: string | null };
|
|
35
|
+
metric: EvalBehaviorMetricNameV1;
|
|
36
|
+
family: EvalBehaviorMetricFamilyV1;
|
|
37
|
+
direction: "higher" | "lower";
|
|
38
|
+
hardGate: boolean;
|
|
39
|
+
baseline: EvalBehaviorMetricDistributionV1;
|
|
40
|
+
candidate: EvalBehaviorMetricDistributionV1;
|
|
41
|
+
change: EvalMetricChangeV1;
|
|
42
|
+
meanDelta: number | null;
|
|
43
|
+
varianceChange: EvalMetricChangeV1;
|
|
44
|
+
varianceDelta: number | null;
|
|
45
|
+
comparability: EvalEnvelopeComparabilityV1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface EvalBehaviorHardGateV1 {
|
|
49
|
+
pass: boolean;
|
|
50
|
+
envelopeFailures: EvalEnvelopeMismatchV1[];
|
|
51
|
+
failures: Array<{
|
|
52
|
+
scenarioId: string;
|
|
53
|
+
role: string;
|
|
54
|
+
target: { id: string; model: string | null };
|
|
55
|
+
metric: EvalBehaviorMetricNameV1;
|
|
56
|
+
change: "regressed" | "incomparable";
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface BehaviorGroup {
|
|
61
|
+
scenarioId: string;
|
|
62
|
+
role: string;
|
|
63
|
+
target: { id: string; model: string | null };
|
|
64
|
+
results: EvalArtifactResultV4[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function compareEvalBehaviorMetricsV1(
|
|
68
|
+
baseline: EvalArtifactV4,
|
|
69
|
+
candidate: EvalArtifactV4,
|
|
70
|
+
): {
|
|
71
|
+
comparisons: EvalBehaviorMetricComparisonV1[];
|
|
72
|
+
hardGate: EvalBehaviorHardGateV1;
|
|
73
|
+
envelopeMismatches: EvalEnvelopeMismatchV1[];
|
|
74
|
+
} {
|
|
75
|
+
const baselineGroups = behaviorGroups(baseline);
|
|
76
|
+
const candidateGroups = behaviorGroups(candidate);
|
|
77
|
+
const keys = new Set([...baselineGroups.keys(), ...candidateGroups.keys()]);
|
|
78
|
+
const comparisons: EvalBehaviorMetricComparisonV1[] = [];
|
|
79
|
+
const envelopeMismatches: EvalEnvelopeMismatchV1[] = [];
|
|
80
|
+
const baselineDimensions = baseline.matrix.dimensions ?? ([] as EvalExecutionMatrixDimensionV1[]);
|
|
81
|
+
const candidateDimensions = candidate.matrix.dimensions ?? ([] as EvalExecutionMatrixDimensionV1[]);
|
|
82
|
+
for (const key of [...keys].sort((left, right) => left.localeCompare(right))) {
|
|
83
|
+
const baselineGroup = baselineGroups.get(key);
|
|
84
|
+
const candidateGroup = candidateGroups.get(key);
|
|
85
|
+
const identity = baselineGroup ?? candidateGroup;
|
|
86
|
+
if (identity === undefined) continue;
|
|
87
|
+
const envelopeMismatch = compareEvalExecutionEnvelopesV1(
|
|
88
|
+
identity,
|
|
89
|
+
baselineGroup?.results ?? [],
|
|
90
|
+
candidateGroup?.results ?? [],
|
|
91
|
+
baselineDimensions,
|
|
92
|
+
candidateDimensions,
|
|
93
|
+
);
|
|
94
|
+
if (envelopeMismatch !== null) envelopeMismatches.push(envelopeMismatch);
|
|
95
|
+
const comparability: EvalEnvelopeComparabilityV1 = {
|
|
96
|
+
comparable: envelopeMismatch === null,
|
|
97
|
+
mismatchedFields: envelopeMismatch?.fields ?? [],
|
|
98
|
+
};
|
|
99
|
+
for (const definition of EVAL_BEHAVIOR_METRIC_DEFINITIONS_V1) {
|
|
100
|
+
const baselineDistribution = behaviorDistribution(baselineGroup?.results ?? [], definition);
|
|
101
|
+
const candidateDistribution = behaviorDistribution(candidateGroup?.results ?? [], definition);
|
|
102
|
+
comparisons.push({
|
|
103
|
+
scenarioId: identity.scenarioId,
|
|
104
|
+
role: identity.role,
|
|
105
|
+
target: identity.target,
|
|
106
|
+
metric: definition.name,
|
|
107
|
+
family: definition.family,
|
|
108
|
+
direction: definition.direction,
|
|
109
|
+
hardGate: definition.hardGate,
|
|
110
|
+
baseline: baselineDistribution,
|
|
111
|
+
candidate: candidateDistribution,
|
|
112
|
+
change:
|
|
113
|
+
envelopeMismatch === null
|
|
114
|
+
? classifyChange(baselineDistribution.mean, candidateDistribution.mean, definition.direction)
|
|
115
|
+
: "incomparable",
|
|
116
|
+
meanDelta: subtractNullable(candidateDistribution.mean, baselineDistribution.mean),
|
|
117
|
+
varianceChange:
|
|
118
|
+
envelopeMismatch === null
|
|
119
|
+
? classifyChange(baselineDistribution.variance, candidateDistribution.variance, "lower")
|
|
120
|
+
: "incomparable",
|
|
121
|
+
varianceDelta: subtractNullable(candidateDistribution.variance, baselineDistribution.variance),
|
|
122
|
+
comparability,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const failures = comparisons.flatMap((comparison) =>
|
|
127
|
+
comparison.hardGate &&
|
|
128
|
+
(comparison.change === "regressed" ||
|
|
129
|
+
(comparison.change === "incomparable" && comparison.baseline.mean !== null && comparison.candidate.mean === null))
|
|
130
|
+
? [
|
|
131
|
+
{
|
|
132
|
+
scenarioId: comparison.scenarioId,
|
|
133
|
+
role: comparison.role,
|
|
134
|
+
target: comparison.target,
|
|
135
|
+
metric: comparison.metric,
|
|
136
|
+
change: comparison.change,
|
|
137
|
+
},
|
|
138
|
+
]
|
|
139
|
+
: [],
|
|
140
|
+
);
|
|
141
|
+
return {
|
|
142
|
+
comparisons,
|
|
143
|
+
hardGate: {
|
|
144
|
+
pass: failures.length === 0 && envelopeMismatches.length === 0,
|
|
145
|
+
failures,
|
|
146
|
+
envelopeFailures: envelopeMismatches,
|
|
147
|
+
},
|
|
148
|
+
envelopeMismatches,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function classifyChange(
|
|
153
|
+
baseline: number | null,
|
|
154
|
+
candidate: number | null,
|
|
155
|
+
direction: "higher" | "lower",
|
|
156
|
+
): EvalMetricChangeV1 {
|
|
157
|
+
if (baseline === null || candidate === null) return "incomparable";
|
|
158
|
+
if (baseline === candidate) return "unchanged";
|
|
159
|
+
if (direction === "higher") return candidate > baseline ? "improved" : "regressed";
|
|
160
|
+
return candidate < baseline ? "improved" : "regressed";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function behaviorGroups(artifact: EvalArtifactV4): Map<string, BehaviorGroup> {
|
|
164
|
+
const groups = new Map<string, BehaviorGroup>();
|
|
165
|
+
for (const result of artifact.results) {
|
|
166
|
+
const behavioral = result.behavioralMetrics;
|
|
167
|
+
if (behavioral === undefined) continue;
|
|
168
|
+
const key = groupKey(behavioral.scenarioId, behavioral.role, behavioral.target);
|
|
169
|
+
const group = groups.get(key) ?? {
|
|
170
|
+
scenarioId: behavioral.scenarioId,
|
|
171
|
+
role: behavioral.role,
|
|
172
|
+
target: behavioral.target,
|
|
173
|
+
results: [],
|
|
174
|
+
};
|
|
175
|
+
group.results.push(result);
|
|
176
|
+
groups.set(key, group);
|
|
177
|
+
}
|
|
178
|
+
return groups;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function behaviorDistribution(
|
|
182
|
+
results: ReadonlyArray<EvalArtifactResultV4>,
|
|
183
|
+
definition: EvalBehaviorMetricDefinitionV1,
|
|
184
|
+
): EvalBehaviorMetricDistributionV1 {
|
|
185
|
+
const observations = results.map((result) => result.behavioralMetrics?.metrics[definition.name].value ?? null);
|
|
186
|
+
const values = observations.flatMap((value) => (value === null ? [] : [value]));
|
|
187
|
+
if (values.length === 0) {
|
|
188
|
+
return {
|
|
189
|
+
observations: observations.length,
|
|
190
|
+
measured: 0,
|
|
191
|
+
unmeasured: observations.length,
|
|
192
|
+
mean: null,
|
|
193
|
+
min: null,
|
|
194
|
+
max: null,
|
|
195
|
+
p90: null,
|
|
196
|
+
variance: null,
|
|
197
|
+
standardDeviation: null,
|
|
198
|
+
source: definition.source,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const ordered = [...values].sort((left, right) => left - right);
|
|
202
|
+
const mean = ordered.reduce((sum, value) => sum + value, 0) / ordered.length;
|
|
203
|
+
const variance = ordered.reduce((sum, value) => sum + (value - mean) ** 2, 0) / ordered.length;
|
|
204
|
+
return {
|
|
205
|
+
observations: observations.length,
|
|
206
|
+
measured: values.length,
|
|
207
|
+
unmeasured: observations.length - values.length,
|
|
208
|
+
mean,
|
|
209
|
+
min: ordered[0] ?? null,
|
|
210
|
+
max: ordered.at(-1) ?? null,
|
|
211
|
+
p90: ordered[Math.max(0, Math.ceil(ordered.length * 0.9) - 1)] ?? null,
|
|
212
|
+
variance,
|
|
213
|
+
standardDeviation: Math.sqrt(variance),
|
|
214
|
+
source: definition.source,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function groupKey(scenarioId: string, role: string, target: { id: string; model: string | null }): string {
|
|
219
|
+
return JSON.stringify([scenarioId, role, target.id, target.model]);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function subtractNullable(left: number | null, right: number | null): number | null {
|
|
223
|
+
return left === null || right === null ? null : left - right;
|
|
224
|
+
}
|