@poetic-ai/poetic 1.42.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/.github/SECURITY.md +47 -0
- package/.nvmrc +1 -0
- package/.poetic/README.md +37 -0
- package/.poetic/providers/catalog.json +12051 -0
- package/.poetic/providers/pricing.json +1272 -0
- package/.poetic/providers/registry.json +3369 -0
- package/CHANGELOG.md +552 -0
- package/CODE_OF_CONDUCT.md +40 -0
- package/CONTRIBUTING.md +23 -0
- package/INSTALL.md +454 -0
- package/LICENSE +21 -0
- package/README.md +474 -0
- package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
- package/dist/ExecutionTracker-UVONC4C6.js +16 -0
- package/dist/OptimizationConfig-7DFY2TST.js +17 -0
- package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
- package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
- package/dist/actions-LUJPINLJ.js +322 -0
- package/dist/agent-ingest-3DJUJ7FU.js +53 -0
- package/dist/aggregator-DNCBINFO.js +12 -0
- package/dist/ai-judge-5QT5QJVU.js +156 -0
- package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
- package/dist/allowlist-utils-23V7TJ3G.js +28 -0
- package/dist/anchored-turn-service-JULUCUIK.js +489 -0
- package/dist/api-transport-4TYTNLTJ.js +1087 -0
- package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
- package/dist/artifact-migrator-23L45ISD.js +267 -0
- package/dist/ask-HWVV6QFR.js +135 -0
- package/dist/auth-5KEDKAPP.js +67 -0
- package/dist/auth-7TT3JINV.js +78 -0
- package/dist/auth-E6XUNZ5M.js +68 -0
- package/dist/auth-H3XDZE22.js +134 -0
- package/dist/auth-OC4E6633.js +71 -0
- package/dist/auth-S4CTX4GQ.js +44 -0
- package/dist/auth-YLH3S7EY.js +69 -0
- package/dist/auth-liveness-TDDEZY3T.js +46 -0
- package/dist/auto-optimizer-VPRWOWGU.js +80 -0
- package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
- package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
- package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
- package/dist/autoloop-helpers-2KTK43GL.js +22 -0
- package/dist/autoloop-ledger-W7QO62PX.js +96 -0
- package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
- package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
- package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
- package/dist/autoloop-success-J2VKKBXQ.js +85 -0
- package/dist/autoloop-termination-summary-RN75F422.js +58 -0
- package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
- package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
- package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
- package/dist/backend-P3DAYRP7.js +29 -0
- package/dist/background-executor-CBN552V4.js +257 -0
- package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
- package/dist/backup-active-store-5WXG6SXT.js +17 -0
- package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
- package/dist/basic-competition-master-VCSBJVRN.js +344 -0
- package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
- package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
- package/dist/build-gate-YHGRB4QB.js +71 -0
- package/dist/change-summary-WY7J5TOX.js +33 -0
- package/dist/chunk-23A26CSN.js +123 -0
- package/dist/chunk-27UTJD3M.js +265 -0
- package/dist/chunk-2A5CILN3.js +310 -0
- package/dist/chunk-2AQUWJPW.js +225 -0
- package/dist/chunk-2BZ53J6J.js +2344 -0
- package/dist/chunk-2DY5KNVM.js +276 -0
- package/dist/chunk-2EIA4RBE.js +659 -0
- package/dist/chunk-2IUXIGQD.js +1064 -0
- package/dist/chunk-2N42MS2Z.js +2193 -0
- package/dist/chunk-2QJ3H3L7.js +42 -0
- package/dist/chunk-2QLYTVYX.js +791 -0
- package/dist/chunk-2VSQMRCB.js +18 -0
- package/dist/chunk-2XQXYBM2.js +130 -0
- package/dist/chunk-2YFUIER7.js +426 -0
- package/dist/chunk-34CNP2HB.js +148 -0
- package/dist/chunk-35P3W3JX.js +456 -0
- package/dist/chunk-36PEBZAF.js +18 -0
- package/dist/chunk-3AOKYKA7.js +22 -0
- package/dist/chunk-3BCUNHKF.js +475 -0
- package/dist/chunk-3FLXLLB7.js +26 -0
- package/dist/chunk-3FOZ2VHV.js +100 -0
- package/dist/chunk-3G6FZCRF.js +106 -0
- package/dist/chunk-3M57DADF.js +44 -0
- package/dist/chunk-3S62LLWJ.js +543 -0
- package/dist/chunk-3ZPQLGV7.js +2904 -0
- package/dist/chunk-44N5WZZH.js +45 -0
- package/dist/chunk-45FPSA3B.js +125 -0
- package/dist/chunk-4BJ3O4RQ.js +929 -0
- package/dist/chunk-4BOP7T6L.js +2321 -0
- package/dist/chunk-4BTDUT2S.js +42 -0
- package/dist/chunk-4CSS7WVI.js +143 -0
- package/dist/chunk-4CUY7AFY.js +247 -0
- package/dist/chunk-4GSN5O5J.js +62 -0
- package/dist/chunk-4HN6DF7V.js +1027 -0
- package/dist/chunk-4IAPOG5V.js +415 -0
- package/dist/chunk-4IYIZQWV.js +48 -0
- package/dist/chunk-4NXPXE62.js +84 -0
- package/dist/chunk-4RCCF5BR.js +712 -0
- package/dist/chunk-4V7NAQ4R.js +19527 -0
- package/dist/chunk-4VJITV4P.js +445 -0
- package/dist/chunk-4YX7J6QL.js +1859 -0
- package/dist/chunk-527OBWQB.js +338 -0
- package/dist/chunk-5D4A7E3D.js +448 -0
- package/dist/chunk-5DLKYTQX.js +4003 -0
- package/dist/chunk-5EERLVZB.js +139 -0
- package/dist/chunk-5H72XE4H.js +256 -0
- package/dist/chunk-5HDP7XZG.js +91 -0
- package/dist/chunk-5LAMRH4X.js +969 -0
- package/dist/chunk-5LTN43AS.js +1972 -0
- package/dist/chunk-5RBHQYDB.js +2206 -0
- package/dist/chunk-5WCQRDRB.js +588 -0
- package/dist/chunk-5WRLK5KW.js +700 -0
- package/dist/chunk-5ZCXC23G.js +595 -0
- package/dist/chunk-6BM72ZMG.js +31 -0
- package/dist/chunk-6EDAJH2I.js +68 -0
- package/dist/chunk-6EQKFDBH.js +457 -0
- package/dist/chunk-6MFRHTRI.js +115 -0
- package/dist/chunk-6TZJRKNW.js +321 -0
- package/dist/chunk-6V7HGQFZ.js +20 -0
- package/dist/chunk-6VWVO2TU.js +3746 -0
- package/dist/chunk-6Y5TWI7H.js +146 -0
- package/dist/chunk-6Y5U7UFY.js +91 -0
- package/dist/chunk-6ZLAK3XG.js +14 -0
- package/dist/chunk-72XCRQED.js +34 -0
- package/dist/chunk-72YTZMAM.js +589 -0
- package/dist/chunk-73BBJOKA.js +263 -0
- package/dist/chunk-73NCTWKL.js +188 -0
- package/dist/chunk-77I6G4CO.js +1 -0
- package/dist/chunk-7DHRDWFS.js +3104 -0
- package/dist/chunk-7DNSNKJV.js +78 -0
- package/dist/chunk-7FMJVYBS.js +307 -0
- package/dist/chunk-7GDRQBQC.js +419 -0
- package/dist/chunk-7GPCEFUV.js +270 -0
- package/dist/chunk-7IL4A2PP.js +948 -0
- package/dist/chunk-7MMLMXO6.js +3679 -0
- package/dist/chunk-7QCZSLBH.js +1 -0
- package/dist/chunk-7R2WLDOS.js +62 -0
- package/dist/chunk-7T7RUJI7.js +949 -0
- package/dist/chunk-A2WKSVX7.js +43 -0
- package/dist/chunk-A3YGID55.js +133 -0
- package/dist/chunk-A722DEVA.js +14 -0
- package/dist/chunk-ACDIT7OP.js +1376 -0
- package/dist/chunk-ACKIPAOJ.js +302 -0
- package/dist/chunk-APPNGGN7.js +365 -0
- package/dist/chunk-APV6MK5E.js +137 -0
- package/dist/chunk-ASEP3M2W.js +968 -0
- package/dist/chunk-AT4TNPWW.js +2931 -0
- package/dist/chunk-ATVKCSGT.js +250 -0
- package/dist/chunk-AURFMVCD.js +899 -0
- package/dist/chunk-AX6GWE7V.js +47 -0
- package/dist/chunk-AY5EWJPF.js +385 -0
- package/dist/chunk-BAV2HJXS.js +194 -0
- package/dist/chunk-BBHRN366.js +89 -0
- package/dist/chunk-BBPSTTPA.js +1004 -0
- package/dist/chunk-BDATUDDJ.js +992 -0
- package/dist/chunk-BKE5PG5L.js +20414 -0
- package/dist/chunk-BLPHWMDK.js +797 -0
- package/dist/chunk-BSE4R6XD.js +322 -0
- package/dist/chunk-BXGMAU4A.js +396 -0
- package/dist/chunk-BXI4NXL3.js +507 -0
- package/dist/chunk-BZU2O43F.js +1125 -0
- package/dist/chunk-C3L6YQ7P.js +147 -0
- package/dist/chunk-C57KJOUQ.js +121 -0
- package/dist/chunk-CCV7BPSY.js +118 -0
- package/dist/chunk-CD7ISXA4.js +826 -0
- package/dist/chunk-CE5OZBYY.js +21 -0
- package/dist/chunk-CFBIG37O.js +154 -0
- package/dist/chunk-CJC6GZ46.js +457 -0
- package/dist/chunk-CKCDGXIV.js +408 -0
- package/dist/chunk-CKNX3TTP.js +10338 -0
- package/dist/chunk-CLKSETWE.js +10 -0
- package/dist/chunk-CP7H3HSP.js +1552 -0
- package/dist/chunk-CPLEWXNZ.js +66 -0
- package/dist/chunk-CQM3A35X.js +844 -0
- package/dist/chunk-CS6P76D3.js +103 -0
- package/dist/chunk-CTLUBNCW.js +622 -0
- package/dist/chunk-CUSRN6RJ.js +632 -0
- package/dist/chunk-D5EP5D2W.js +26 -0
- package/dist/chunk-D5RYINO7.js +412 -0
- package/dist/chunk-DBFS4HMH.js +751 -0
- package/dist/chunk-DC4ZYMXJ.js +115 -0
- package/dist/chunk-DCBZP442.js +9243 -0
- package/dist/chunk-DCYF7EKG.js +26 -0
- package/dist/chunk-DDMAFNUK.js +5351 -0
- package/dist/chunk-DF5SLDE4.js +966 -0
- package/dist/chunk-DJFW7SMX.js +348 -0
- package/dist/chunk-DQFLLBJW.js +121 -0
- package/dist/chunk-DSFM56OA.js +1203 -0
- package/dist/chunk-DTY4APYV.js +218 -0
- package/dist/chunk-DXH5JBRS.js +437 -0
- package/dist/chunk-E3NTPHEO.js +194 -0
- package/dist/chunk-E74LUIID.js +302 -0
- package/dist/chunk-EI57M5BI.js +194 -0
- package/dist/chunk-EJ4ZAWLV.js +305 -0
- package/dist/chunk-EJGCZGUF.js +1483 -0
- package/dist/chunk-EK2U3YEG.js +486 -0
- package/dist/chunk-ELMFYNV7.js +109 -0
- package/dist/chunk-ENRGKNR5.js +25 -0
- package/dist/chunk-ETYDXCK7.js +679 -0
- package/dist/chunk-EYRH3W74.js +239 -0
- package/dist/chunk-F23DIWNN.js +1024 -0
- package/dist/chunk-F5JO7HAS.js +94 -0
- package/dist/chunk-F7ER6ANO.js +174 -0
- package/dist/chunk-FATUVIIN.js +374 -0
- package/dist/chunk-FC23CTXV.js +322 -0
- package/dist/chunk-FD4ERYEG.js +22 -0
- package/dist/chunk-FH7WOJAE.js +79 -0
- package/dist/chunk-FHOWVDF5.js +1342 -0
- package/dist/chunk-FKAUPHMR.js +96 -0
- package/dist/chunk-FONNFJXA.js +137 -0
- package/dist/chunk-FQ7FSZRW.js +75 -0
- package/dist/chunk-FRG57FPM.js +240 -0
- package/dist/chunk-FUVP64ER.js +31 -0
- package/dist/chunk-FYOILAN5.js +6818 -0
- package/dist/chunk-G35UYQ6Z.js +69 -0
- package/dist/chunk-G36W2T2S.js +1143 -0
- package/dist/chunk-G3L2L5XZ.js +49 -0
- package/dist/chunk-G4THLFV3.js +148 -0
- package/dist/chunk-GAFJEYLK.js +29 -0
- package/dist/chunk-GFGYB2ZU.js +1689 -0
- package/dist/chunk-GG6KJYW6.js +85 -0
- package/dist/chunk-GHHFDU2U.js +55 -0
- package/dist/chunk-GHTZSQB7.js +57 -0
- package/dist/chunk-GK37ILCX.js +1231 -0
- package/dist/chunk-GKN3HMN4.js +2809 -0
- package/dist/chunk-GNVDBVJP.js +156 -0
- package/dist/chunk-GPEL3FBM.js +924 -0
- package/dist/chunk-GPSNGPZS.js +1604 -0
- package/dist/chunk-GSGD5E4C.js +30 -0
- package/dist/chunk-GSUQJJXQ.js +331 -0
- package/dist/chunk-GSV226X6.js +110 -0
- package/dist/chunk-H2AYQIHW.js +224 -0
- package/dist/chunk-H66DXFS5.js +1374 -0
- package/dist/chunk-H6G7QRMQ.js +35 -0
- package/dist/chunk-H7JAGHZT.js +59 -0
- package/dist/chunk-H7ZEFECA.js +316 -0
- package/dist/chunk-HAC6EHZZ.js +79 -0
- package/dist/chunk-HIO33P3G.js +19 -0
- package/dist/chunk-HMVQIPH3.js +547 -0
- package/dist/chunk-HOYBYAOA.js +257 -0
- package/dist/chunk-HX5P3CSP.js +1784 -0
- package/dist/chunk-I46EG2XQ.js +65 -0
- package/dist/chunk-I4NPDSCB.js +279 -0
- package/dist/chunk-I5WRT7ZR.js +514 -0
- package/dist/chunk-IC7I6YIJ.js +301 -0
- package/dist/chunk-IDCSOZVN.js +78 -0
- package/dist/chunk-IFCBYECK.js +112 -0
- package/dist/chunk-IFZCPEY2.js +66 -0
- package/dist/chunk-IKFP2KUR.js +48 -0
- package/dist/chunk-IRFBN336.js +878 -0
- package/dist/chunk-IUXNGKA6.js +152 -0
- package/dist/chunk-IV2RVAN7.js +1356 -0
- package/dist/chunk-IZYIQQ7X.js +53 -0
- package/dist/chunk-J3UUR7DE.js +210 -0
- package/dist/chunk-J54VUAY2.js +566 -0
- package/dist/chunk-J62KPGII.js +464 -0
- package/dist/chunk-J6P3FWWW.js +130 -0
- package/dist/chunk-JKBHJQMT.js +434 -0
- package/dist/chunk-JLS65NUQ.js +14 -0
- package/dist/chunk-JOSYEJKY.js +141 -0
- package/dist/chunk-JPKSXKNB.js +94 -0
- package/dist/chunk-JQNJB2BB.js +2440 -0
- package/dist/chunk-JRVNSWSQ.js +2626 -0
- package/dist/chunk-JSWMRQYG.js +28 -0
- package/dist/chunk-JZKNBBIB.js +152 -0
- package/dist/chunk-K54Y7MLK.js +160 -0
- package/dist/chunk-K65546RE.js +183 -0
- package/dist/chunk-KM3F7SYE.js +702 -0
- package/dist/chunk-KNDYMVWN.js +102 -0
- package/dist/chunk-KNT72VR6.js +132 -0
- package/dist/chunk-KP6YILMU.js +482 -0
- package/dist/chunk-KQEBSK3T.js +274 -0
- package/dist/chunk-KT6VHSPF.js +84 -0
- package/dist/chunk-KTMW65UX.js +14 -0
- package/dist/chunk-KZ5CJVBP.js +1813 -0
- package/dist/chunk-L4427KOE.js +26 -0
- package/dist/chunk-L6OM4A22.js +189 -0
- package/dist/chunk-L7E6XCRA.js +1042 -0
- package/dist/chunk-L7JZLXQL.js +173 -0
- package/dist/chunk-LAMKBTXX.js +40 -0
- package/dist/chunk-LDCF2MKN.js +132 -0
- package/dist/chunk-LEIIWPWQ.js +78 -0
- package/dist/chunk-LFTQVYBB.js +31 -0
- package/dist/chunk-LG3PDRTR.js +2872 -0
- package/dist/chunk-LGHII5ET.js +23 -0
- package/dist/chunk-LH5QY22X.js +1205 -0
- package/dist/chunk-LIVJ6266.js +438 -0
- package/dist/chunk-LKRAR3IH.js +276 -0
- package/dist/chunk-LO23NABI.js +3063 -0
- package/dist/chunk-LO3X5NLS.js +326 -0
- package/dist/chunk-LPITVM7M.js +339 -0
- package/dist/chunk-LR5IJIGV.js +810 -0
- package/dist/chunk-LRGMHROI.js +79 -0
- package/dist/chunk-LUVKFFWR.js +315 -0
- package/dist/chunk-LWCBNGH6.js +35 -0
- package/dist/chunk-LWTN3WRV.js +260 -0
- package/dist/chunk-M3HQYKQX.js +308 -0
- package/dist/chunk-M6GVSPEH.js +1016 -0
- package/dist/chunk-MF5HP6XV.js +221 -0
- package/dist/chunk-MHLCBZJB.js +328 -0
- package/dist/chunk-MN6PL4AN.js +120 -0
- package/dist/chunk-MOEY65Z6.js +5678 -0
- package/dist/chunk-MQ4WA34C.js +206 -0
- package/dist/chunk-MWHF5V7U.js +223 -0
- package/dist/chunk-MWHLBPNU.js +211 -0
- package/dist/chunk-MWK5UZQ3.js +1068 -0
- package/dist/chunk-MYLH2S4G.js +64 -0
- package/dist/chunk-MZ5WYKNA.js +28 -0
- package/dist/chunk-N4VTRA7K.js +131 -0
- package/dist/chunk-N5DX4JAK.js +12 -0
- package/dist/chunk-N65O4XTH.js +5011 -0
- package/dist/chunk-NEQUQHOX.js +223 -0
- package/dist/chunk-NGK6PEOG.js +25 -0
- package/dist/chunk-NJVD4PWE.js +1033 -0
- package/dist/chunk-NM6PMYY4.js +768 -0
- package/dist/chunk-NN4PJDHP.js +708 -0
- package/dist/chunk-NP2V3L7K.js +226 -0
- package/dist/chunk-NRLY536M.js +260 -0
- package/dist/chunk-NRNE225N.js +1270 -0
- package/dist/chunk-NS2K2GTP.js +605 -0
- package/dist/chunk-NS33V3IM.js +51 -0
- package/dist/chunk-NSHASMZZ.js +71 -0
- package/dist/chunk-NWOYOA6H.js +378 -0
- package/dist/chunk-NWRUSEXG.js +322 -0
- package/dist/chunk-NZGDAWIP.js +1905 -0
- package/dist/chunk-O47UOKU3.js +395 -0
- package/dist/chunk-O4G2W3ST.js +9831 -0
- package/dist/chunk-O6V4PNLO.js +63 -0
- package/dist/chunk-OA4GPILI.js +624 -0
- package/dist/chunk-OGMSYL6J.js +227 -0
- package/dist/chunk-OIS7J26S.js +319 -0
- package/dist/chunk-OMX5VL43.js +79 -0
- package/dist/chunk-ON3G73BU.js +264 -0
- package/dist/chunk-OPYFYTWQ.js +220 -0
- package/dist/chunk-OQ6K46CK.js +1734 -0
- package/dist/chunk-OYZYO7TV.js +47 -0
- package/dist/chunk-OZ4REHIN.js +4386 -0
- package/dist/chunk-P47VN5F4.js +282 -0
- package/dist/chunk-P5I4X7A7.js +353 -0
- package/dist/chunk-P6VQROCO.js +594 -0
- package/dist/chunk-P7CQGPLS.js +30 -0
- package/dist/chunk-PCAGC5MR.js +1763 -0
- package/dist/chunk-PFTQBXS6.js +5181 -0
- package/dist/chunk-PGSPX4SU.js +15 -0
- package/dist/chunk-PIKLF7BM.js +432 -0
- package/dist/chunk-PJWJ3SAV.js +22 -0
- package/dist/chunk-PKIFMV72.js +100 -0
- package/dist/chunk-PL37JDNA.js +189 -0
- package/dist/chunk-PTH5E5XO.js +195 -0
- package/dist/chunk-PW6AXLQC.js +4128 -0
- package/dist/chunk-PYITM4N2.js +79 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-Q3RO7N35.js +45 -0
- package/dist/chunk-Q3WIC6GQ.js +2670 -0
- package/dist/chunk-Q5XIXSHX.js +271 -0
- package/dist/chunk-QGJDMEOV.js +34 -0
- package/dist/chunk-QNOB37UH.js +58 -0
- package/dist/chunk-QOCOVLUH.js +462 -0
- package/dist/chunk-QTCJ5CC5.js +172 -0
- package/dist/chunk-QVFV5IP2.js +232 -0
- package/dist/chunk-QVZMFDYG.js +29 -0
- package/dist/chunk-R35PEUKH.js +511 -0
- package/dist/chunk-R4UWBC35.js +200 -0
- package/dist/chunk-R6MLCREW.js +44 -0
- package/dist/chunk-R6W23LKN.js +254 -0
- package/dist/chunk-R7XDDX2A.js +4007 -0
- package/dist/chunk-RDFRCT64.js +168 -0
- package/dist/chunk-RE5VZDFQ.js +58 -0
- package/dist/chunk-RGROYC2G.js +638 -0
- package/dist/chunk-RGWHUI5E.js +68 -0
- package/dist/chunk-RHVG6UNL.js +205 -0
- package/dist/chunk-RI4EX2QE.js +18 -0
- package/dist/chunk-RJAAKDRX.js +17 -0
- package/dist/chunk-ROMHOSMQ.js +185 -0
- package/dist/chunk-RWREC3KJ.js +517 -0
- package/dist/chunk-RYNETRDJ.js +118 -0
- package/dist/chunk-RZY7RKM5.js +500 -0
- package/dist/chunk-S2MNWFAG.js +52 -0
- package/dist/chunk-S2VQCZO4.js +22 -0
- package/dist/chunk-S54MKU6V.js +117 -0
- package/dist/chunk-S5OIDFRM.js +302 -0
- package/dist/chunk-SCW4ZF6R.js +150 -0
- package/dist/chunk-SLS2N4PH.js +2213 -0
- package/dist/chunk-SNLBO4BF.js +247 -0
- package/dist/chunk-SP3LFU6B.js +60 -0
- package/dist/chunk-SQQTDDQA.js +537 -0
- package/dist/chunk-STV6LYYE.js +45 -0
- package/dist/chunk-SURZ2WFE.js +326 -0
- package/dist/chunk-SZ7DL357.js +1047 -0
- package/dist/chunk-T5E4NQCM.js +5742 -0
- package/dist/chunk-TAJPCXSB.js +13 -0
- package/dist/chunk-TAOOYK3P.js +358 -0
- package/dist/chunk-TDSEX5CF.js +24 -0
- package/dist/chunk-TFTGP7Z7.js +174 -0
- package/dist/chunk-TGON4N4O.js +197 -0
- package/dist/chunk-TGQZHDY2.js +2373 -0
- package/dist/chunk-TJJZ2OKV.js +6783 -0
- package/dist/chunk-TRSVUPCX.js +25 -0
- package/dist/chunk-TSXGRLPR.js +107 -0
- package/dist/chunk-U2S3YEX3.js +224 -0
- package/dist/chunk-U45RTRGY.js +818 -0
- package/dist/chunk-U6C3VVWS.js +13 -0
- package/dist/chunk-UDMS5AD3.js +307 -0
- package/dist/chunk-UGX7GI37.js +94 -0
- package/dist/chunk-UH3JJSHK.js +1 -0
- package/dist/chunk-UHRBTZYY.js +208 -0
- package/dist/chunk-UHT2KRG5.js +193 -0
- package/dist/chunk-UI2F6DJ5.js +118 -0
- package/dist/chunk-UMAKSB4Z.js +284 -0
- package/dist/chunk-UR2IBGIM.js +521 -0
- package/dist/chunk-UUH2RVKS.js +585 -0
- package/dist/chunk-UVJ4PJDK.js +4533 -0
- package/dist/chunk-V53UG2OT.js +9924 -0
- package/dist/chunk-V72RMBM4.js +48 -0
- package/dist/chunk-VBNCKCCI.js +16 -0
- package/dist/chunk-VNSYKC25.js +24 -0
- package/dist/chunk-VPHVFK4A.js +1984 -0
- package/dist/chunk-VTLNJQ44.js +133 -0
- package/dist/chunk-VTW7HP3R.js +100 -0
- package/dist/chunk-VVGEPBPS.js +218 -0
- package/dist/chunk-VVLLL7I4.js +166 -0
- package/dist/chunk-VX3UMWB7.js +483 -0
- package/dist/chunk-VXF4Q3FW.js +20 -0
- package/dist/chunk-W3JMT2YY.js +712 -0
- package/dist/chunk-WDUORIHF.js +877 -0
- package/dist/chunk-WDVTY4U6.js +148 -0
- package/dist/chunk-WIFZCHEG.js +12566 -0
- package/dist/chunk-WIRN3F75.js +736 -0
- package/dist/chunk-WMPU2UOV.js +82 -0
- package/dist/chunk-WTOKKE2V.js +784 -0
- package/dist/chunk-WX5IRLF6.js +740 -0
- package/dist/chunk-WZ6U3O7I.js +1581 -0
- package/dist/chunk-XAONGNST.js +57 -0
- package/dist/chunk-XB5YLCLB.js +13 -0
- package/dist/chunk-XEP5NQ5Y.js +688 -0
- package/dist/chunk-XGYF2QMZ.js +351 -0
- package/dist/chunk-XHEKQENB.js +255 -0
- package/dist/chunk-XNO4FM6X.js +1124 -0
- package/dist/chunk-XPHKYHO4.js +878 -0
- package/dist/chunk-XPK2I4NC.js +405 -0
- package/dist/chunk-XPU2XADL.js +2175 -0
- package/dist/chunk-XQD2B6BB.js +507 -0
- package/dist/chunk-XT2ZQVTC.js +558 -0
- package/dist/chunk-XTXJGGUV.js +351 -0
- package/dist/chunk-XUXVDPSZ.js +50 -0
- package/dist/chunk-XV7NZL4B.js +57 -0
- package/dist/chunk-XZE4XARH.js +563 -0
- package/dist/chunk-XZYR5EDO.js +152 -0
- package/dist/chunk-Y3J4JMTU.js +61 -0
- package/dist/chunk-Y55LZN5U.js +52 -0
- package/dist/chunk-Y5VN7DMP.js +112 -0
- package/dist/chunk-Y67VAHN4.js +459 -0
- package/dist/chunk-YAXSKEUH.js +3544 -0
- package/dist/chunk-YB3JD4E6.js +975 -0
- package/dist/chunk-YESZJFK6.js +220 -0
- package/dist/chunk-YGXKOBQQ.js +292 -0
- package/dist/chunk-YMX76IOS.js +31 -0
- package/dist/chunk-YOTXESEH.js +257 -0
- package/dist/chunk-YTYIEZQY.js +119 -0
- package/dist/chunk-YVORHQ2S.js +579 -0
- package/dist/chunk-Z2CUQDAR.js +3429 -0
- package/dist/chunk-Z2KYOFHS.js +7000 -0
- package/dist/chunk-Z6PC7QX6.js +161 -0
- package/dist/chunk-ZDTGECTN.js +235 -0
- package/dist/chunk-ZIPWI2LY.js +151 -0
- package/dist/chunk-ZSKKMTQJ.js +554 -0
- package/dist/chunk-ZTT5IVPY.js +1160 -0
- package/dist/chunk-ZX65UI5W.js +78 -0
- package/dist/chunk-ZYG7GGKO.js +218 -0
- package/dist/chunk-ZZZUL4OF.js +38 -0
- package/dist/cli-utils-IXL26KJT.js +40 -0
- package/dist/cli-validation-WLXWLUJL.js +111 -0
- package/dist/commit-utils-P7CRJF5N.js +202 -0
- package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
- package/dist/compete-request-62JESVET.js +364 -0
- package/dist/compete-results-QEPG6FZX.js +208 -0
- package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
- package/dist/config-JCOKXOQT.js +166 -0
- package/dist/config-audit-EL3GHXS7.js +360 -0
- package/dist/config-explain-TNILDEVJ.js +12 -0
- package/dist/config-loader-VPFPFO4B.js +38 -0
- package/dist/config-manager-7T4E2BQO.js +67 -0
- package/dist/config-validator-KKOHOW7O.js +72 -0
- package/dist/cost-YC42XUF3.js +53 -0
- package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
- package/dist/coverage-scanner-YVD62MLH.js +12 -0
- package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
- package/dist/data-migration-state-VJK64DLT.js +31 -0
- package/dist/db-migrator-XSEIOGWY.js +34 -0
- package/dist/discovery-JGYGDD25.js +25 -0
- package/dist/doctor-GJOYE7AE.js +186 -0
- package/dist/domain-analyzer-AWF3RP6E.js +29 -0
- package/dist/ensure-initialized-744DIZEZ.js +52 -0
- package/dist/entry.js +940 -0
- package/dist/environment-YS45U5ZI.js +81 -0
- package/dist/error-parser-core-PPZ36A4S.js +50 -0
- package/dist/escalation-ladder-MKTCEGSA.js +130 -0
- package/dist/evaluation-context-KV4GZNN7.js +35 -0
- package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
- package/dist/execution-data-writer-3ODTBDLH.js +53 -0
- package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
- package/dist/execution-preflight-Z4Y64V3I.js +209 -0
- package/dist/execution-roles-R3DPPMD3.js +66 -0
- package/dist/exit-code-error-Z4SW2DVK.js +14 -0
- package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
- package/dist/factory-XBN7DFIM.js +149 -0
- package/dist/file-utils-XIVR2ZMA.js +47 -0
- package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
- package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
- package/dist/flywheel-executor-6JFLA6J5.js +369 -0
- package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
- package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
- package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
- package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
- package/dist/flywheel-resume-7HELH7QS.js +23 -0
- package/dist/flywheel-safety-7U7DPOAP.js +28 -0
- package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
- package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
- package/dist/git-worktree-IY6V6DUO.js +18 -0
- package/dist/github-pr-manager-4LXEKJTA.js +211 -0
- package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
- package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
- package/dist/index-query-4JEUKA44.js +31 -0
- package/dist/index.js +108661 -0
- package/dist/instructions-6BURLQJC.js +64 -0
- package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
- package/dist/judge-scoring.json +80 -0
- package/dist/judge-test.js +555 -0
- package/dist/lab-mode-OTWVHN63.js +39 -0
- package/dist/lab-utils-BJRFLGK4.js +23 -0
- package/dist/linux-host-class-UY4KVLFD.js +29 -0
- package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
- package/dist/local-executor-CEHWE2PL.js +223 -0
- package/dist/logger-33TR6EE5.js +72 -0
- package/dist/loop-spec-XTLQAVZ7.js +191 -0
- package/dist/manager-2HJG5CLT.js +25 -0
- package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
- package/dist/matrix-result-parser-7W35EUOV.js +15 -0
- package/dist/metadata-HQ43NDEK.js +22 -0
- package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
- package/dist/monitor-XGYBG2DW.js +72 -0
- package/dist/next-PB5ZXZKB.js +90 -0
- package/dist/next-ZBDK725T.js +69 -0
- package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
- package/dist/package-3YCWIQQ5.js +10 -0
- package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
- package/dist/parallel-worker.js +279 -0
- package/dist/parse-git-status-PIAF3OTP.js +10 -0
- package/dist/path-security-ETTH6TZL.js +39 -0
- package/dist/pattern-bank-UNJR5ADV.js +15 -0
- package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
- package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
- package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
- package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
- package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
- package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
- package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
- package/dist/poetic-root-V5DNXEAE.js +17 -0
- package/dist/preflight-OPANWMME.js +12 -0
- package/dist/process-registry-PDZJPTAS.js +27 -0
- package/dist/process-scanner-C22SYXYD.js +22 -0
- package/dist/processes-KMQUD7HY.js +29 -0
- package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
- package/dist/profile-SE5EVXAP.js +149 -0
- package/dist/prompts-WZZPGWBX.js +168 -0
- package/dist/protected-branches-RNTEX7ET.js +57 -0
- package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
- package/dist/provider-matrix-N5X57V3Y.js +154 -0
- package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
- package/dist/provider-output-forwarding-DERID3TP.js +30 -0
- package/dist/provider-registry-J5NRBJKI.js +128 -0
- package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
- package/dist/prune-engine-Q6E2DXBN.js +451 -0
- package/dist/quality-gate-YRHMQAEI.js +70 -0
- package/dist/quickstart-FIRLKGJI.js +62 -0
- package/dist/readiness-VZTMSG6J.js +96 -0
- package/dist/registry-YODFY77A.js +153 -0
- package/dist/repair-helpers-TTV5FEF4.js +117 -0
- package/dist/repo-root-2IGD4H7X.js +22 -0
- package/dist/resolution-engine-D6TX6FRG.js +127 -0
- package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
- package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
- package/dist/result-streamer-WEHW476R.js +19 -0
- package/dist/routing-events-DHPUZDDF.js +27 -0
- package/dist/routing-history-store-UWCEXAP3.js +46 -0
- package/dist/routing-planner-F5WQEUOM.js +160 -0
- package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
- package/dist/run-simulation.js +376 -0
- package/dist/runner-CS2TNGHA.js +1092 -0
- package/dist/runner-HHH7ZN2Z.js +1571 -0
- package/dist/safety-OCC4KJJR.js +64 -0
- package/dist/safety-stanza-7SV3HGG3.js +60 -0
- package/dist/sandbox-32QXJEMV.js +81 -0
- package/dist/sandbox-RSO7VP6V.js +94 -0
- package/dist/schema-extensions.sql +234 -0
- package/dist/security-2KI5XNDG.js +17 -0
- package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
- package/dist/setup-claude-code-P7BTTSPO.js +317 -0
- package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
- package/dist/shared-utils-D6U6UREP.js +37 -0
- package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
- package/dist/sprint-UIXPYOXQ.js +338 -0
- package/dist/sprint-bridge-4BHMSC3M.js +68 -0
- package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
- package/dist/sprint-manager-IDQUDNQI.js +91 -0
- package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
- package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
- package/dist/storage-access-F6ALDN4S.js +22 -0
- package/dist/synthesis-XD6EDVHF.js +185 -0
- package/dist/task-classifier-LNLXSHOM.js +494 -0
- package/dist/task-list-fast-PTMA4LUC.js +147 -0
- package/dist/task-manager-XAT7GOWB.js +93 -0
- package/dist/task-splitter-U7DJ7W6A.js +79 -0
- package/dist/task-type-detector-OLVOMXZO.js +21 -0
- package/dist/task-type-resolver-KKNQYSB4.js +42 -0
- package/dist/telemetry-5HWBBXLX.js +131 -0
- package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
- package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
- package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
- package/dist/token-estimator-MEQUL3EJ.js +37 -0
- package/dist/transports-KNSSV2V4.js +255 -0
- package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
- package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
- package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
- package/dist/user-agents-GHUGCSKN.js +22 -0
- package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
- package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
- package/dist/variant-success-PJXWE3ZV.js +12 -0
- package/dist/variant-worker-KUWKBLAH.js +4196 -0
- package/dist/variant-worker.js +24 -0
- package/dist/variants-JE2FSAQS.js +233 -0
- package/dist/verification-toolchains-V24UHW6Q.js +28 -0
- package/dist/verify-commands-H3DTCSGI.js +37 -0
- package/dist/warning-EGQGUUIO.js +12 -0
- package/dist/work-edge-RWEDWJZF.js +49 -0
- package/dist/work-item-writer-WHAVZXAY.js +19 -0
- package/dist/worker-7SA2VS2Y.js +1435 -0
- package/dist/worker.js +19 -0
- package/dist/worktree-metrics-3DFUYVYE.js +26 -0
- package/dist/writeback-VZKHYHSN.js +44 -0
- package/docs/CLI_REFERENCE.md +7042 -0
- package/docs/PROVIDER_SETUP.md +1570 -0
- package/docs/README.md +96 -0
- package/docs/TROUBLESHOOTING.md +2232 -0
- package/docs/getting-started/QUICK_START.md +294 -0
- package/docs/getting-started/README.md +188 -0
- package/docs/getting-started/SETUP.md +52 -0
- package/docs/reference/AGENT_CONTEXT.md +38 -0
- package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
- package/docs/reference/README.md +381 -0
- package/docs/reference/SECURITY.md +262 -0
- package/integrations/bb-plugin-poetic/README.md +362 -0
- package/integrations/bb-plugin-poetic/app.css +341 -0
- package/integrations/bb-plugin-poetic/app.tsx +5059 -0
- package/integrations/bb-plugin-poetic/package.json +45 -0
- package/integrations/bb-plugin-poetic/server.ts +444 -0
- package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
- package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
- package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
- package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
- package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
- package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
- package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
- package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
- package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
- package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
- package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
- package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
- package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
- package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
- package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
- package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
- package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
- package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
- package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
- package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
- package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
- package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
- package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
- package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
- package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
- package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
- package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
- package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
- package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
- package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
- package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
- package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
- package/npm-shrinkwrap.json +4950 -0
- package/package.json +331 -0
- package/schemas/README.md +80 -0
- package/schemas/config-v1.schema.json +136 -0
- package/schemas/execution-config.schema.json +47 -0
- package/schemas/judge-scoring.schema.json +370 -0
- package/schemas/poetic.config.schema.json +2214 -0
- package/schemas/provider-config.schema.json +203 -0
- package/schemas/telemetry-config.schema.json +79 -0
- package/schemas/user-preferences.schema.json +141 -0
- package/scripts/assert-node-runtime.mjs +140 -0
- package/scripts/preflight-native.mjs +49 -0
- package/scripts/preinstall-node-check.mjs +78 -0
- package/scripts/setup-git-hooks.mjs +24 -0
- package/scripts/sync.sh +2722 -0
- package/scripts/write-node-launcher.sh +108 -0
- package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
- package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
- package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
- package/templates/.poetic/README.md +37 -0
- package/templates/.poetic/agents/README.md +296 -0
- package/templates/.poetic/agents/api-documenter.md +147 -0
- package/templates/.poetic/agents/backend-architect.md +31 -0
- package/templates/.poetic/agents/code-reviewer.md +157 -0
- package/templates/.poetic/agents/data-scientist.md +179 -0
- package/templates/.poetic/agents/database-optimizer.md +145 -0
- package/templates/.poetic/agents/debugger.md +31 -0
- package/templates/.poetic/agents/deployment-engineer.md +164 -0
- package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
- package/templates/.poetic/agents/frontend-developer.md +150 -0
- package/templates/.poetic/agents/javascript-pro.md +36 -0
- package/templates/.poetic/agents/performance-engineer.md +151 -0
- package/templates/.poetic/agents/python-pro.md +137 -0
- package/templates/.poetic/agents/test-automator.md +147 -0
- package/templates/.poetic/agents/typescript-pro.md +34 -0
- package/templates/.poetic/config/poetic.config.jsonc +69 -0
- package/templates/.poetic/config/project-context.template.json +6 -0
- package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
- package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
- package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
- package/templates/.poetic/config/task-type-aliases.yaml +28 -0
- package/templates/.poetic/gitignore.template +55 -0
- package/templates/.poetic/task-types/analysis.yaml +40 -0
- package/templates/.poetic/task-types/architecture.yaml +38 -0
- package/templates/.poetic/task-types/doc.yaml +35 -0
- package/templates/.poetic/task-types/feature.yaml +23 -0
- package/templates/.poetic/task-types/general.yaml +6 -0
- package/templates/.poetic/task-types/security.yaml +39 -0
- package/templates/AGENTS.template.md +99 -0
- package/templates/CLAUDE.template.md +1 -0
- package/templates/GEMINI.template.md +1 -0
- package/templates/builtin-workflows/code-review.yaml +73 -0
- package/templates/builtin-workflows/compete-streak.yaml +78 -0
- package/templates/builtin-workflows/hello-verify.yaml +10 -0
- package/templates/builtin-workflows/judge-regression.yaml +114 -0
- package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
- package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
- package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
- package/templates/guard-kit/check.mjs.template +777 -0
- package/templates/guard-kit/config.json.template +6 -0
- package/templates/guard-kit/poetic-guard.yml.template +189 -0
- package/templates/profiles/README.md +56 -0
- package/templates/profiles/frontier-claude.json +27 -0
- package/templates/profiles/frontier-codex.json +26 -0
|
@@ -0,0 +1,3104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveTestVerificationDisplay,
|
|
3
|
+
gateStatusToDisplayVerdict
|
|
4
|
+
} from "./chunk-QNOB37UH.js";
|
|
5
|
+
import {
|
|
6
|
+
evaluateStageCompletionProof,
|
|
7
|
+
resolveProviderExecutionIntentFromStage,
|
|
8
|
+
stageHasHostDeterministicCompletionSurface
|
|
9
|
+
} from "./chunk-5ZCXC23G.js";
|
|
10
|
+
import {
|
|
11
|
+
collectDeclaredStageTargets
|
|
12
|
+
} from "./chunk-IFCBYECK.js";
|
|
13
|
+
import {
|
|
14
|
+
decideStageChangeScope
|
|
15
|
+
} from "./chunk-HAC6EHZZ.js";
|
|
16
|
+
import {
|
|
17
|
+
providerReportsUsage,
|
|
18
|
+
readCostMetricsUnavailableReason,
|
|
19
|
+
readUsageUnavailableReason
|
|
20
|
+
} from "./chunk-XUXVDPSZ.js";
|
|
21
|
+
import {
|
|
22
|
+
cleanupSynthesisInputPatches,
|
|
23
|
+
resolveBasicCompetitionInterruption,
|
|
24
|
+
resolveSynthesisInputPatchDir,
|
|
25
|
+
runBasicCompetition,
|
|
26
|
+
selectWinnerWithJudge
|
|
27
|
+
} from "./chunk-DCBZP442.js";
|
|
28
|
+
import {
|
|
29
|
+
createEvaluationHandleFinalState,
|
|
30
|
+
finalizeEvaluationHandleAsync,
|
|
31
|
+
isDurableHandleCompletion,
|
|
32
|
+
toEvaluationHandleWinnerMetadata,
|
|
33
|
+
updateEvaluationHandleWithResultAsync
|
|
34
|
+
} from "./chunk-2IUXIGQD.js";
|
|
35
|
+
import {
|
|
36
|
+
JudgeCoordinator,
|
|
37
|
+
evaluateMatrixAuthority,
|
|
38
|
+
generateCompetitionId,
|
|
39
|
+
resolveMatrixAuthorityPolicy,
|
|
40
|
+
resolveTypedCompletenessAuthority
|
|
41
|
+
} from "./chunk-WIFZCHEG.js";
|
|
42
|
+
import {
|
|
43
|
+
validateStrategy
|
|
44
|
+
} from "./chunk-LWTN3WRV.js";
|
|
45
|
+
import {
|
|
46
|
+
isAcceptedMatrixVerdict
|
|
47
|
+
} from "./chunk-5LAMRH4X.js";
|
|
48
|
+
import {
|
|
49
|
+
findAllowlistViolations
|
|
50
|
+
} from "./chunk-ZIPWI2LY.js";
|
|
51
|
+
import {
|
|
52
|
+
ArtifactNotFoundError,
|
|
53
|
+
createSecurityBoundary,
|
|
54
|
+
deriveAiJudgeInvocationArgs,
|
|
55
|
+
resolvePromptArtifacts
|
|
56
|
+
} from "./chunk-4HN6DF7V.js";
|
|
57
|
+
import {
|
|
58
|
+
getProjectRoot
|
|
59
|
+
} from "./chunk-CQM3A35X.js";
|
|
60
|
+
import {
|
|
61
|
+
applyFlywheelModelDefaults
|
|
62
|
+
} from "./chunk-FH7WOJAE.js";
|
|
63
|
+
import {
|
|
64
|
+
extractEvidenceAnchors,
|
|
65
|
+
isNegativeClaim
|
|
66
|
+
} from "./chunk-O4G2W3ST.js";
|
|
67
|
+
import {
|
|
68
|
+
shouldExcludeFile
|
|
69
|
+
} from "./chunk-NS33V3IM.js";
|
|
70
|
+
import {
|
|
71
|
+
filterWorktreeRunSentinelPaths
|
|
72
|
+
} from "./chunk-I5WRT7ZR.js";
|
|
73
|
+
import {
|
|
74
|
+
taskVariantId
|
|
75
|
+
} from "./chunk-34CNP2HB.js";
|
|
76
|
+
import {
|
|
77
|
+
runVerifyCommands
|
|
78
|
+
} from "./chunk-LO23NABI.js";
|
|
79
|
+
import {
|
|
80
|
+
createExecutionContext
|
|
81
|
+
} from "./chunk-UI2F6DJ5.js";
|
|
82
|
+
import {
|
|
83
|
+
normalizeReasoningEffortInput
|
|
84
|
+
} from "./chunk-4BTDUT2S.js";
|
|
85
|
+
|
|
86
|
+
// src/automation/flywheel-competition-executor.ts
|
|
87
|
+
import * as fs from "fs/promises";
|
|
88
|
+
import * as path from "path";
|
|
89
|
+
import chalk from "chalk";
|
|
90
|
+
|
|
91
|
+
// src/automation/flywheel-to-core-verification-finding.ts
|
|
92
|
+
function toCoreVerificationFinding(finding) {
|
|
93
|
+
const kind = finding.kind === "coverage" ? "other" : finding.kind;
|
|
94
|
+
const outputParts = [];
|
|
95
|
+
if (finding.kind === "coverage") {
|
|
96
|
+
const coverageDetail = finding.outputTail?.trim() ? finding.outputTail.trim() : finding.command ? `Coverage observation for ${finding.command}` : "Coverage observation";
|
|
97
|
+
outputParts.push(
|
|
98
|
+
coverageDetail.toLowerCase().includes("coverage") ? coverageDetail : `Coverage: ${coverageDetail}`
|
|
99
|
+
);
|
|
100
|
+
} else if (finding.outputTail) {
|
|
101
|
+
outputParts.push(finding.outputTail);
|
|
102
|
+
}
|
|
103
|
+
if (finding.recommendedNextStep) {
|
|
104
|
+
const next = finding.recommendedNextStep.trim();
|
|
105
|
+
if (next && !outputParts.some((part) => part.includes(next))) {
|
|
106
|
+
outputParts.push(next);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const mapped = {
|
|
110
|
+
kind,
|
|
111
|
+
command: finding.command,
|
|
112
|
+
exitCode: finding.exitCode,
|
|
113
|
+
severity: finding.severity
|
|
114
|
+
};
|
|
115
|
+
if (outputParts.length > 0) {
|
|
116
|
+
mapped.outputTail = outputParts.join("\n");
|
|
117
|
+
}
|
|
118
|
+
return mapped;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/automation/verification-polarity.ts
|
|
122
|
+
function hasExplicitVerificationSignal(input) {
|
|
123
|
+
if (input.verification && typeof input.verification.passed === "boolean") {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
if (typeof input.verification?.status === "string" && input.verification.status.trim()) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
if (typeof input.testStatus === "string" && input.testStatus.trim()) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
if (typeof input.rawTestStatus === "string" && input.rawTestStatus.trim()) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
if (typeof input.exitCode === "number") {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
if (typeof input.failedTests === "number") {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
function verificationRecordsBaselineClean(verification) {
|
|
144
|
+
if (!verification) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (verification.passedBaseline === false) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
const status = verification.status?.trim().toLowerCase();
|
|
151
|
+
if (status === "baseline_clean") {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
if (verification.passedBaseline !== true) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return !status || gateStatusToDisplayVerdict(status) !== "unavailable";
|
|
158
|
+
}
|
|
159
|
+
function verificationPolarityAllowsStageSuccess(input) {
|
|
160
|
+
if (!hasExplicitVerificationSignal(input)) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (verificationRecordsBaselineClean(input.verification)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
if (input.verification?.passed === false) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const status = input.verification?.status?.trim().toLowerCase();
|
|
170
|
+
if (status === "failed" || status === "unavailable") {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
const hasExplicitTestSignal = typeof input.testStatus === "string" && input.testStatus.trim().length > 0 || typeof input.rawTestStatus === "string" && input.rawTestStatus.trim().length > 0 || typeof input.exitCode === "number" || typeof input.failedTests === "number";
|
|
174
|
+
if (hasExplicitTestSignal) {
|
|
175
|
+
const display = deriveTestVerificationDisplay({
|
|
176
|
+
testStatus: input.testStatus,
|
|
177
|
+
rawTestStatus: input.rawTestStatus,
|
|
178
|
+
exitCode: input.exitCode,
|
|
179
|
+
failedTests: input.failedTests
|
|
180
|
+
});
|
|
181
|
+
return display === "passed";
|
|
182
|
+
}
|
|
183
|
+
return input.verification?.passed === true || status === "passed";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/automation/flywheel-competition-executor.ts
|
|
187
|
+
var CANDIDATE_GATE_COMMAND_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
188
|
+
function isNoChangesDetectedError(errorMessage) {
|
|
189
|
+
return Boolean(errorMessage?.includes("No changes detected (git status clean)"));
|
|
190
|
+
}
|
|
191
|
+
function generateCandidateFeedback(variantEvaluation, result) {
|
|
192
|
+
if (!variantEvaluation && !result) return void 0;
|
|
193
|
+
const parts = [];
|
|
194
|
+
const score = variantEvaluation?.qualityScore ?? result.judgeScore ?? result.completeness;
|
|
195
|
+
if (score !== void 0) {
|
|
196
|
+
parts.push(`Score: ${Number(score).toFixed(1)}/100`);
|
|
197
|
+
}
|
|
198
|
+
const changedFiles = extractChangedFilesFromResult(result);
|
|
199
|
+
const fileCount = changedFiles.length;
|
|
200
|
+
const linesAdded = result.gitMetrics?.linesAdded ?? result.linesAdded ?? 0;
|
|
201
|
+
const linesDeleted = result.gitMetrics?.linesDeleted ?? result.linesRemoved ?? 0;
|
|
202
|
+
if (fileCount > 0 || linesAdded > 0 || linesDeleted > 0) {
|
|
203
|
+
parts.push(`Changes: ${fileCount} file(s), +${linesAdded}/-${linesDeleted} lines`);
|
|
204
|
+
}
|
|
205
|
+
const testStatus = result.testStatus;
|
|
206
|
+
if (testStatus) {
|
|
207
|
+
parts.push(`Tests: ${testStatus}`);
|
|
208
|
+
}
|
|
209
|
+
const strengths = variantEvaluation?.strengths;
|
|
210
|
+
if (strengths && strengths.length > 0) {
|
|
211
|
+
const topStrengths = strengths.slice(0, 2).join("; ");
|
|
212
|
+
parts.push(`Strengths: ${topStrengths}`);
|
|
213
|
+
}
|
|
214
|
+
const weaknesses = variantEvaluation?.weaknesses;
|
|
215
|
+
if (weaknesses && weaknesses.length > 0) {
|
|
216
|
+
const topWeaknesses = weaknesses.slice(0, 2).join("; ");
|
|
217
|
+
parts.push(`Areas for improvement: ${topWeaknesses}`);
|
|
218
|
+
}
|
|
219
|
+
const cq = variantEvaluation?.codeQuality;
|
|
220
|
+
if (cq) {
|
|
221
|
+
const metrics = [];
|
|
222
|
+
if (cq.correctness !== void 0) metrics.push(`correctness=${cq.correctness}`);
|
|
223
|
+
if (cq.completeness !== void 0) metrics.push(`completeness=${cq.completeness}`);
|
|
224
|
+
if (metrics.length > 0) {
|
|
225
|
+
parts.push(`Quality: ${metrics.join(", ")}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return parts.length > 0 ? `${parts.join(". ")}.` : void 0;
|
|
229
|
+
}
|
|
230
|
+
function extractChangedFilesFromResult(result) {
|
|
231
|
+
if ("changedFiles" in result && Array.isArray(result.changedFiles)) {
|
|
232
|
+
return result.changedFiles;
|
|
233
|
+
}
|
|
234
|
+
const statusLines = result.worktreeSummary?.statusLines;
|
|
235
|
+
if (statusLines && Array.isArray(statusLines) && statusLines.length > 0) {
|
|
236
|
+
return statusLines.map((line) => extractChangedFileFromStatusLine(String(line))).filter((line) => Boolean(line));
|
|
237
|
+
}
|
|
238
|
+
const filesChanged = result.gitMetrics?.filesChanged;
|
|
239
|
+
if (typeof filesChanged === "number" && filesChanged > 0) {
|
|
240
|
+
return Array.from({ length: filesChanged }, (_, i) => `file${i + 1}`);
|
|
241
|
+
}
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
function resultHasChangeTracking(result) {
|
|
245
|
+
if ("changedFiles" in result && Array.isArray(result.changedFiles)) {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
const statusLines = result.worktreeSummary?.statusLines;
|
|
249
|
+
if (Array.isArray(statusLines)) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return typeof result.gitMetrics?.filesChanged === "number";
|
|
253
|
+
}
|
|
254
|
+
function extractChangedFileFromStatusLine(line) {
|
|
255
|
+
const trimmed = line.trim();
|
|
256
|
+
if (!trimmed) return null;
|
|
257
|
+
const arrowIdx = trimmed.lastIndexOf("->");
|
|
258
|
+
if (arrowIdx !== -1) {
|
|
259
|
+
const candidate = trimmed.slice(arrowIdx + 2).trim();
|
|
260
|
+
return candidate || null;
|
|
261
|
+
}
|
|
262
|
+
const match = trimmed.match(/^[MADRCU?! ]{1,2}\s*(.+)$/);
|
|
263
|
+
return match?.[1]?.trim() ?? null;
|
|
264
|
+
}
|
|
265
|
+
function candidateHasChangedFiles(candidate) {
|
|
266
|
+
return Array.isArray(candidate.changedFiles) && candidate.changedFiles.length > 0;
|
|
267
|
+
}
|
|
268
|
+
function candidateHasConcreteZeroChanges(candidate) {
|
|
269
|
+
return candidate.changeTrackingAvailable === true && !candidateHasChangedFiles(candidate);
|
|
270
|
+
}
|
|
271
|
+
function stageHasDeterministicChecks(stage) {
|
|
272
|
+
return stageHasHostDeterministicCompletionSurface(stage);
|
|
273
|
+
}
|
|
274
|
+
function renderCandidateGateCommand(command, candidate) {
|
|
275
|
+
return command.replaceAll("{{provider}}", shellArg(candidate.variant.provider)).replaceAll("{{model}}", shellArg(candidate.variant.model ?? "")).replaceAll("{{strategy}}", shellArg(candidate.variant.strategy ?? "")).replaceAll("{{variant}}", shellArg(formatCompetitionCandidateVariantDisplay(candidate)));
|
|
276
|
+
}
|
|
277
|
+
function formatCompetitionCandidateVariantDisplay(candidate) {
|
|
278
|
+
return formatCompetitionVariantDisplay(candidate.variant);
|
|
279
|
+
}
|
|
280
|
+
function formatCompetitionVariantDisplay(variant) {
|
|
281
|
+
const parts = [variant.provider, variant.model, variant.strategy ?? "conservative"].filter(
|
|
282
|
+
(part) => typeof part === "string" && part.length > 0
|
|
283
|
+
);
|
|
284
|
+
return parts.join(":");
|
|
285
|
+
}
|
|
286
|
+
function shellArg(value) {
|
|
287
|
+
if (/^[A-Za-z0-9._:@/+,-]+$/.test(value)) {
|
|
288
|
+
return value;
|
|
289
|
+
}
|
|
290
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
291
|
+
}
|
|
292
|
+
async function validateWorktreeAgainstStageChecks(stage, worktreePath, stdout, options) {
|
|
293
|
+
if (!stageHasHostDeterministicCompletionSurface(stage)) return false;
|
|
294
|
+
const proof = await evaluateStageCompletionProof({
|
|
295
|
+
stage,
|
|
296
|
+
worktreePath,
|
|
297
|
+
stdout,
|
|
298
|
+
attemptChangedFiles: options?.attemptChangedFiles ?? [],
|
|
299
|
+
allowlist: options?.allowlist ?? computeExpectedAllowlist(stage),
|
|
300
|
+
stageId: stage.id
|
|
301
|
+
});
|
|
302
|
+
return proof.contractsSatisfied && proof.hasHostSurface && proof.mayAcceptOutcome;
|
|
303
|
+
}
|
|
304
|
+
function getVariantTelemetryStatePath(taskId, provider, strategy, model, mode, reasoningEffort) {
|
|
305
|
+
const variantKey = taskVariantId(
|
|
306
|
+
taskId,
|
|
307
|
+
provider,
|
|
308
|
+
model,
|
|
309
|
+
strategy,
|
|
310
|
+
mode,
|
|
311
|
+
void 0,
|
|
312
|
+
void 0,
|
|
313
|
+
reasoningEffort
|
|
314
|
+
);
|
|
315
|
+
return path.join(
|
|
316
|
+
getProjectRoot(),
|
|
317
|
+
".poetic",
|
|
318
|
+
"telemetry",
|
|
319
|
+
"state",
|
|
320
|
+
"variants",
|
|
321
|
+
`${variantKey}.json`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
function getValueAtPath(root, keys) {
|
|
325
|
+
let current = root;
|
|
326
|
+
for (const key of keys) {
|
|
327
|
+
if (!current || typeof current !== "object") return void 0;
|
|
328
|
+
current = current[key];
|
|
329
|
+
}
|
|
330
|
+
return current;
|
|
331
|
+
}
|
|
332
|
+
function getFiniteNumberAtPath(root, keys) {
|
|
333
|
+
const value = getValueAtPath(root, keys);
|
|
334
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
335
|
+
}
|
|
336
|
+
function getStringAtPath(root, keys) {
|
|
337
|
+
const value = getValueAtPath(root, keys);
|
|
338
|
+
return typeof value === "string" ? value : void 0;
|
|
339
|
+
}
|
|
340
|
+
function extractNativeObservedCostFromVariantState(state) {
|
|
341
|
+
return getFiniteNumberAtPath(state, ["result", "totalCostUsd"]) ?? getFiniteNumberAtPath(state, ["result", "total_cost_usd"]) ?? getFiniteNumberAtPath(state, ["result", "totalCost"]) ?? getFiniteNumberAtPath(state, ["result", "total_cost"]) ?? null;
|
|
342
|
+
}
|
|
343
|
+
function extractCostMetricsAmountFromVariantState(state) {
|
|
344
|
+
return getFiniteNumberAtPath(state, ["costMetrics", "totalCostUsd"]) ?? getFiniteNumberAtPath(state, ["costMetrics", "totalCost"]) ?? null;
|
|
345
|
+
}
|
|
346
|
+
function resolveCostMetricsUnavailableReason(costMetrics) {
|
|
347
|
+
if (!costMetrics || typeof costMetrics !== "object") {
|
|
348
|
+
return void 0;
|
|
349
|
+
}
|
|
350
|
+
const usageReason = readUsageUnavailableReason({ costMetrics });
|
|
351
|
+
if (usageReason !== void 0) {
|
|
352
|
+
return usageReason;
|
|
353
|
+
}
|
|
354
|
+
const reason = readCostMetricsUnavailableReason(
|
|
355
|
+
costMetrics
|
|
356
|
+
);
|
|
357
|
+
if (reason !== void 0) {
|
|
358
|
+
return reason;
|
|
359
|
+
}
|
|
360
|
+
if (costMetrics.pricingStatus === "error") {
|
|
361
|
+
return "pricing_unavailable";
|
|
362
|
+
}
|
|
363
|
+
return void 0;
|
|
364
|
+
}
|
|
365
|
+
function markCandidateCostUnavailable(candidate, reason) {
|
|
366
|
+
candidate.cost = 0;
|
|
367
|
+
candidate.costUnavailableReason = reason;
|
|
368
|
+
}
|
|
369
|
+
async function hydrateCandidateCostsFromTelemetry(taskId, candidates, stageIdForLogs, verbose) {
|
|
370
|
+
await Promise.all(
|
|
371
|
+
candidates.map(async (candidate) => {
|
|
372
|
+
if (!candidate.success) return;
|
|
373
|
+
if (typeof candidate.cost === "number" && Number.isFinite(candidate.cost) && candidate.costUnavailableReason === void 0) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (typeof candidate.cost === "number" && Number.isFinite(candidate.cost) && candidate.cost > 0) {
|
|
377
|
+
candidate.costUnavailableReason = void 0;
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const provider = candidate.variant.provider;
|
|
381
|
+
const strategy = candidate.variant.strategy ?? "conservative";
|
|
382
|
+
if (!provider || !strategy) return;
|
|
383
|
+
if (!providerReportsUsage(provider)) {
|
|
384
|
+
candidate.costUnavailableReason = candidate.costUnavailableReason ?? "provider_not_reported";
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const variantStatePath = getVariantTelemetryStatePath(
|
|
388
|
+
taskId,
|
|
389
|
+
provider,
|
|
390
|
+
strategy,
|
|
391
|
+
candidate.variant.model,
|
|
392
|
+
candidate.variant.executionMode,
|
|
393
|
+
normalizeReasoningEffortInput(candidate.variant.reasoning)
|
|
394
|
+
);
|
|
395
|
+
try {
|
|
396
|
+
const raw = await fs.readFile(variantStatePath, "utf8");
|
|
397
|
+
const state = JSON.parse(raw);
|
|
398
|
+
const nativeObservedCost = extractNativeObservedCostFromVariantState(state);
|
|
399
|
+
const metricsCost = extractCostMetricsAmountFromVariantState(state);
|
|
400
|
+
const costMetrics = getValueAtPath(state, ["costMetrics"]);
|
|
401
|
+
const unavailableReason = resolveCostMetricsUnavailableReason(costMetrics);
|
|
402
|
+
if (typeof nativeObservedCost === "number") {
|
|
403
|
+
candidate.cost = nativeObservedCost;
|
|
404
|
+
candidate.costUnavailableReason = void 0;
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (typeof metricsCost === "number" && metricsCost > 0) {
|
|
408
|
+
candidate.cost = metricsCost;
|
|
409
|
+
candidate.costUnavailableReason = void 0;
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
if (unavailableReason !== void 0) {
|
|
413
|
+
markCandidateCostUnavailable(candidate, unavailableReason);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (typeof metricsCost === "number") {
|
|
417
|
+
candidate.cost = metricsCost;
|
|
418
|
+
candidate.costUnavailableReason = void 0;
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
markCandidateCostUnavailable(
|
|
422
|
+
candidate,
|
|
423
|
+
candidate.costUnavailableReason ?? "provider_not_reported"
|
|
424
|
+
);
|
|
425
|
+
} catch {
|
|
426
|
+
markCandidateCostUnavailable(
|
|
427
|
+
candidate,
|
|
428
|
+
candidate.costUnavailableReason ?? "provider_not_reported"
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
if (verbose) {
|
|
432
|
+
console.warn(
|
|
433
|
+
chalk.yellow(
|
|
434
|
+
` [${stageIdForLogs}] Unable to hydrate cost from telemetry for ${provider}:${strategy}`
|
|
435
|
+
)
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
function variantSpecToConfig(spec, executionIntent, stage, defaultProviderExecutionTransport, unknownStrategyPolicy) {
|
|
442
|
+
const validatedStrategy = validateStrategy(spec.strategy, unknownStrategyPolicy);
|
|
443
|
+
const model = spec.model ?? applyFlywheelModelDefaults(stage, spec.provider);
|
|
444
|
+
const modelReasoningEffort = normalizeReasoningEffortInput(spec.reasoning);
|
|
445
|
+
return {
|
|
446
|
+
provider: spec.provider,
|
|
447
|
+
model,
|
|
448
|
+
...modelReasoningEffort ? { modelReasoningEffort } : {},
|
|
449
|
+
strategy: validatedStrategy,
|
|
450
|
+
executionMode: "local",
|
|
451
|
+
// Competition stages always run locally
|
|
452
|
+
executionIntent,
|
|
453
|
+
...spec.providerExecutionTransport ?? stage.providerExecutionTransport ?? defaultProviderExecutionTransport ? {
|
|
454
|
+
executionTransport: spec.providerExecutionTransport ?? stage.providerExecutionTransport ?? defaultProviderExecutionTransport
|
|
455
|
+
} : {},
|
|
456
|
+
allowEmptyResults: stage.allowEmptyResults,
|
|
457
|
+
isBasicCompetition: true,
|
|
458
|
+
// Don't auto-commit - flywheel manages commits
|
|
459
|
+
disableAutoCommit: true,
|
|
460
|
+
structuredFileTargets: computeExpectedAllowlist(stage)
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function assertNoDuplicateVariantSpecs(variants, options) {
|
|
464
|
+
if (options.allowDuplicates) return;
|
|
465
|
+
const keyCounts = /* @__PURE__ */ new Map();
|
|
466
|
+
const keyToVariants = /* @__PURE__ */ new Map();
|
|
467
|
+
for (const variant of variants) {
|
|
468
|
+
const modelKey = variant.model ?? "default";
|
|
469
|
+
const strategyKey = variant.strategy ?? "conservative";
|
|
470
|
+
const effortKey = variant.modelReasoningEffort ?? "default";
|
|
471
|
+
const key = `${variant.provider}:${modelKey}:${strategyKey}:${effortKey}`;
|
|
472
|
+
keyCounts.set(key, (keyCounts.get(key) ?? 0) + 1);
|
|
473
|
+
if (!keyToVariants.has(key)) {
|
|
474
|
+
keyToVariants.set(key, []);
|
|
475
|
+
}
|
|
476
|
+
keyToVariants.get(key)?.push(variant);
|
|
477
|
+
}
|
|
478
|
+
const duplicates = [...keyCounts.entries()].filter(([, count]) => count > 1);
|
|
479
|
+
if (duplicates.length === 0) return;
|
|
480
|
+
const details = duplicates.map(([key, count]) => {
|
|
481
|
+
const parts = key.split(":");
|
|
482
|
+
const provider = parts[0] ?? "unknown";
|
|
483
|
+
const model = parts[1] === "default" ? "(default)" : parts[1];
|
|
484
|
+
const strategy = parts[2] ?? "conservative";
|
|
485
|
+
const effort = parts[3] === "default" ? void 0 : parts[3];
|
|
486
|
+
return ` \u2022 ${provider}:${model}:${strategy}${effort ? `:effort-${effort}` : ""} \u2014 appears ${count} times`;
|
|
487
|
+
}).join("\n");
|
|
488
|
+
throw new Error(
|
|
489
|
+
`Duplicate variant specs detected in competition stage
|
|
490
|
+
|
|
491
|
+
What this means:
|
|
492
|
+
Competition stages should compare different variants, not the same variant
|
|
493
|
+
to itself. Duplicates are identified by provider+model+strategy+reasoningEffort identity.
|
|
494
|
+
|
|
495
|
+
Duplicate variants found:
|
|
496
|
+
${details}
|
|
497
|
+
|
|
498
|
+
How to fix:
|
|
499
|
+
1. Remove duplicate entries from your competition.variants configuration
|
|
500
|
+
2. Or change model/strategy to make variants distinct
|
|
501
|
+
3. Or use different providers for same strategy (e.g., claude:conservative + codex:conservative)
|
|
502
|
+
|
|
503
|
+
Escape hatch (not recommended):
|
|
504
|
+
Set competition.allowDuplicateVariantSpecs: true in your stage config
|
|
505
|
+
|
|
506
|
+
Tip: This guard prevents wasted compute on redundant comparisons.`
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
function resolveCompetitionExecutionIntent(stage) {
|
|
510
|
+
return resolveProviderExecutionIntentFromStage(stage);
|
|
511
|
+
}
|
|
512
|
+
function getVariantDurationMs(result) {
|
|
513
|
+
if (typeof result.executionDurationMs === "number" && Number.isFinite(result.executionDurationMs)) {
|
|
514
|
+
return result.executionDurationMs;
|
|
515
|
+
}
|
|
516
|
+
if (typeof result.totalDurationSec === "number" && Number.isFinite(result.totalDurationSec)) {
|
|
517
|
+
return result.totalDurationSec * 1e3;
|
|
518
|
+
}
|
|
519
|
+
return Math.max(0, Math.round((result.duration ?? 0) * 1e3));
|
|
520
|
+
}
|
|
521
|
+
var CHANGED_FILES_EXCLUDE_PATTERNS = [
|
|
522
|
+
"node_modules",
|
|
523
|
+
".cursor",
|
|
524
|
+
".vscode",
|
|
525
|
+
"coverage",
|
|
526
|
+
"dist",
|
|
527
|
+
".poetic/tmp",
|
|
528
|
+
".git"
|
|
529
|
+
];
|
|
530
|
+
function shouldExcludeChangedFile(filePath) {
|
|
531
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
532
|
+
if (shouldExcludeFile(normalized)) return true;
|
|
533
|
+
for (const pattern of CHANGED_FILES_EXCLUDE_PATTERNS) {
|
|
534
|
+
if (normalized === pattern || normalized.startsWith(`${pattern}/`)) return true;
|
|
535
|
+
}
|
|
536
|
+
return false;
|
|
537
|
+
}
|
|
538
|
+
function extractChangedFiles(result) {
|
|
539
|
+
const statusLines = result.worktreeSummary?.statusLines;
|
|
540
|
+
if (!Array.isArray(statusLines) || statusLines.length === 0) return void 0;
|
|
541
|
+
const files = statusLines.map((line) => extractChangedFileFromStatusLine(String(line))).filter((v) => Boolean(v)).filter((f) => !shouldExcludeChangedFile(f));
|
|
542
|
+
return files.length > 0 ? files : void 0;
|
|
543
|
+
}
|
|
544
|
+
function normalizeCoveragePath(value) {
|
|
545
|
+
return value.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+/g, "/");
|
|
546
|
+
}
|
|
547
|
+
function tryGetPct(metric) {
|
|
548
|
+
if (!metric || typeof metric !== "object") return null;
|
|
549
|
+
const pct = metric.pct;
|
|
550
|
+
return typeof pct === "number" && Number.isFinite(pct) ? pct : null;
|
|
551
|
+
}
|
|
552
|
+
function getCoveragePctForEntry(entry) {
|
|
553
|
+
if (!entry || typeof entry !== "object") return null;
|
|
554
|
+
const record = entry;
|
|
555
|
+
return tryGetPct(record.lines) ?? tryGetPct(record.statements) ?? tryGetPct(record.functions) ?? tryGetPct(record.branches) ?? null;
|
|
556
|
+
}
|
|
557
|
+
function getTotalLinesForEntry(entry) {
|
|
558
|
+
if (!entry || typeof entry !== "object") return null;
|
|
559
|
+
const record = entry;
|
|
560
|
+
const lines = record.lines;
|
|
561
|
+
if (!lines || typeof lines !== "object") return null;
|
|
562
|
+
const total = lines.total;
|
|
563
|
+
return typeof total === "number" && Number.isFinite(total) ? total : null;
|
|
564
|
+
}
|
|
565
|
+
async function loadCoverageSummaryJson(worktreePath, summaryPath, options = {}) {
|
|
566
|
+
try {
|
|
567
|
+
const resolved = path.join(worktreePath, summaryPath);
|
|
568
|
+
if (typeof options.minMtimeMs === "number") {
|
|
569
|
+
const stats = await fs.stat(resolved);
|
|
570
|
+
if (stats.mtimeMs < options.minMtimeMs) return null;
|
|
571
|
+
}
|
|
572
|
+
const raw = await fs.readFile(resolved, "utf8");
|
|
573
|
+
const parsed = JSON.parse(raw);
|
|
574
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
575
|
+
return parsed;
|
|
576
|
+
} catch {
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
function findCoverageEntry(summary, target) {
|
|
581
|
+
const normalizedTarget = normalizeCoveragePath(target);
|
|
582
|
+
const direct = summary[normalizedTarget];
|
|
583
|
+
if (direct && typeof direct === "object") {
|
|
584
|
+
return direct;
|
|
585
|
+
}
|
|
586
|
+
const candidates = [];
|
|
587
|
+
for (const [key, value] of Object.entries(summary)) {
|
|
588
|
+
if (key === "total") continue;
|
|
589
|
+
if (!value || typeof value !== "object") continue;
|
|
590
|
+
const normalizedKey = normalizeCoveragePath(key);
|
|
591
|
+
if (normalizedKey === normalizedTarget || normalizedKey.endsWith(`/${normalizedTarget}`)) {
|
|
592
|
+
candidates.push({ key, entry: value });
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (candidates.length === 0) return null;
|
|
596
|
+
candidates.sort((a, b) => a.key.length - b.key.length);
|
|
597
|
+
return candidates[0]?.entry ?? null;
|
|
598
|
+
}
|
|
599
|
+
function computeCoverageStatsForTargets(summary, targets) {
|
|
600
|
+
const byTarget = {};
|
|
601
|
+
const linesByTarget = {};
|
|
602
|
+
const missingTargets = [];
|
|
603
|
+
const pcts = [];
|
|
604
|
+
const lineCounts = [];
|
|
605
|
+
for (const target of targets) {
|
|
606
|
+
if (!summary) {
|
|
607
|
+
byTarget[target] = null;
|
|
608
|
+
linesByTarget[target] = null;
|
|
609
|
+
missingTargets.push(target);
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
const entry = findCoverageEntry(summary, target);
|
|
613
|
+
const pct = entry ? getCoveragePctForEntry(entry) : null;
|
|
614
|
+
const lines = entry ? getTotalLinesForEntry(entry) : null;
|
|
615
|
+
byTarget[target] = pct;
|
|
616
|
+
linesByTarget[target] = lines;
|
|
617
|
+
if (pct === null) {
|
|
618
|
+
missingTargets.push(target);
|
|
619
|
+
} else {
|
|
620
|
+
pcts.push(pct);
|
|
621
|
+
}
|
|
622
|
+
if (typeof lines === "number") {
|
|
623
|
+
lineCounts.push(lines);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (pcts.length === 0) {
|
|
627
|
+
return {
|
|
628
|
+
byTarget,
|
|
629
|
+
linesByTarget,
|
|
630
|
+
avgPct: null,
|
|
631
|
+
minPct: null,
|
|
632
|
+
totalLines: null,
|
|
633
|
+
maxTargetLines: null,
|
|
634
|
+
missingTargets
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
const avgRaw = pcts.reduce((sum, v) => sum + v, 0) / pcts.length;
|
|
638
|
+
const minRaw = Math.min(...pcts);
|
|
639
|
+
const round2 = (v) => Math.round(v * 100) / 100;
|
|
640
|
+
const totalLines = lineCounts.length > 0 ? lineCounts.reduce((sum, v) => sum + v, 0) : null;
|
|
641
|
+
const maxTargetLines = lineCounts.length > 0 ? Math.max(...lineCounts) : null;
|
|
642
|
+
return {
|
|
643
|
+
byTarget,
|
|
644
|
+
linesByTarget,
|
|
645
|
+
avgPct: round2(avgRaw),
|
|
646
|
+
minPct: round2(minRaw),
|
|
647
|
+
totalLines,
|
|
648
|
+
maxTargetLines,
|
|
649
|
+
missingTargets
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function parseBaselineLinesPctFromPrompt(prompt) {
|
|
653
|
+
const match = prompt.match(/Baseline:\s*lines\s+(\d+(?:\.\d+)?)%/i);
|
|
654
|
+
if (!match) return null;
|
|
655
|
+
const value = Number.parseFloat(match[1] ?? "");
|
|
656
|
+
return Number.isFinite(value) ? value : null;
|
|
657
|
+
}
|
|
658
|
+
function resolveAutoCoverageMode(params) {
|
|
659
|
+
const { maxTargetLines, largeFileLineThreshold, baselineAvgPct, threshold, minDeltaPct } = params;
|
|
660
|
+
if (typeof maxTargetLines === "number" && maxTargetLines > largeFileLineThreshold) {
|
|
661
|
+
return "delta";
|
|
662
|
+
}
|
|
663
|
+
if (typeof threshold === "number" && typeof baselineAvgPct === "number" && threshold - baselineAvgPct > minDeltaPct) {
|
|
664
|
+
return "delta";
|
|
665
|
+
}
|
|
666
|
+
return "absolute";
|
|
667
|
+
}
|
|
668
|
+
function computeExpectedAllowlist(stage) {
|
|
669
|
+
return collectDeclaredStageTargets(stage);
|
|
670
|
+
}
|
|
671
|
+
function computeCompetitionDrift(candidates, expectedAllowlist, mode) {
|
|
672
|
+
const allDeliveredFiles = /* @__PURE__ */ new Set();
|
|
673
|
+
const allViolations = /* @__PURE__ */ new Set();
|
|
674
|
+
for (const candidate of candidates) {
|
|
675
|
+
if (!candidate.success || !candidate.changedFiles) continue;
|
|
676
|
+
const changedFiles = filterWorktreeRunSentinelPaths(candidate.changedFiles);
|
|
677
|
+
for (const file of changedFiles) {
|
|
678
|
+
allDeliveredFiles.add(file);
|
|
679
|
+
}
|
|
680
|
+
const decision = decideStageChangeScope({
|
|
681
|
+
changedPaths: changedFiles,
|
|
682
|
+
explicitScope: expectedAllowlist,
|
|
683
|
+
allowlistMode: mode,
|
|
684
|
+
mutationOrigin: "provider"
|
|
685
|
+
});
|
|
686
|
+
for (const violation of decision.allowlistViolations) {
|
|
687
|
+
allViolations.add(violation);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const deliveredFiles = [...allDeliveredFiles];
|
|
691
|
+
const violations = [...allViolations];
|
|
692
|
+
const hasDrift = violations.length > 0;
|
|
693
|
+
const lines = [];
|
|
694
|
+
lines.push(`Competition stage (${candidates.length} candidates)`);
|
|
695
|
+
lines.push(`Mode: ${mode}`);
|
|
696
|
+
lines.push(`Total delivered files: ${deliveredFiles.length}`);
|
|
697
|
+
lines.push(`Expected allowlist entries: ${expectedAllowlist.length}`);
|
|
698
|
+
if (hasDrift) {
|
|
699
|
+
lines.push(`Drift: ${violations.length} file(s) outside allowlist`);
|
|
700
|
+
for (const v of violations.slice(0, 3)) {
|
|
701
|
+
lines.push(` - ${v}`);
|
|
702
|
+
}
|
|
703
|
+
if (violations.length > 3) {
|
|
704
|
+
lines.push(` ... and ${violations.length - 3} more`);
|
|
705
|
+
}
|
|
706
|
+
} else {
|
|
707
|
+
lines.push("Drift: none");
|
|
708
|
+
}
|
|
709
|
+
return {
|
|
710
|
+
mode,
|
|
711
|
+
deliveredFiles,
|
|
712
|
+
expectedFiles: expectedAllowlist,
|
|
713
|
+
violations,
|
|
714
|
+
hasDrift,
|
|
715
|
+
summary: lines.join("\n")
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
var DEFAULT_COHERENCE_THRESHOLD = 0.3;
|
|
719
|
+
function jaccardSimilarity(setA, setB) {
|
|
720
|
+
if (setA.size === 0 && setB.size === 0) return 1;
|
|
721
|
+
const intersection = new Set([...setA].filter((x) => setB.has(x)));
|
|
722
|
+
const union = /* @__PURE__ */ new Set([...setA, ...setB]);
|
|
723
|
+
return union.size > 0 ? intersection.size / union.size : 0;
|
|
724
|
+
}
|
|
725
|
+
function computeCoherenceMetrics(candidates, threshold = DEFAULT_COHERENCE_THRESHOLD, expectedAllowlist) {
|
|
726
|
+
const allowlist = (expectedAllowlist ?? []).filter((v) => typeof v === "string" && v.length > 0);
|
|
727
|
+
const hasAllowlist = allowlist.length > 0;
|
|
728
|
+
const isAllowlisted = (filePath) => {
|
|
729
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
730
|
+
for (const entry of allowlist) {
|
|
731
|
+
const rule = entry.replace(/\\/g, "/");
|
|
732
|
+
if (rule.endsWith("/")) {
|
|
733
|
+
if (normalized.startsWith(rule)) return true;
|
|
734
|
+
} else if (normalized === rule) {
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return false;
|
|
739
|
+
};
|
|
740
|
+
const filterCandidateFiles = (files) => {
|
|
741
|
+
if (!files) return void 0;
|
|
742
|
+
if (!hasAllowlist) return files;
|
|
743
|
+
const filtered = files.filter(isAllowlisted);
|
|
744
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
745
|
+
};
|
|
746
|
+
const successfulCandidates = candidates.filter(
|
|
747
|
+
(c) => c.success && filterCandidateFiles(c.changedFiles)?.length
|
|
748
|
+
);
|
|
749
|
+
if (successfulCandidates.length < 2) {
|
|
750
|
+
return {
|
|
751
|
+
pairwiseSimilarity: {},
|
|
752
|
+
averageSimilarity: 1,
|
|
753
|
+
// Single candidate = coherent with itself
|
|
754
|
+
isCoherent: true,
|
|
755
|
+
coherenceThreshold: threshold
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
const fileSets = /* @__PURE__ */ new Map();
|
|
759
|
+
for (const [index, candidate] of successfulCandidates.entries()) {
|
|
760
|
+
const provider = candidate.variant.provider;
|
|
761
|
+
const model = candidate.variant.model ?? "";
|
|
762
|
+
const strategy = candidate.variant.strategy ?? "";
|
|
763
|
+
const key = `${provider}:${model}:${strategy}:${index}`;
|
|
764
|
+
fileSets.set(key, new Set(filterCandidateFiles(candidate.changedFiles) || []));
|
|
765
|
+
}
|
|
766
|
+
const pairwiseSimilarity = {};
|
|
767
|
+
const candidateKeys = Array.from(fileSets.keys());
|
|
768
|
+
let totalSimilarity = 0;
|
|
769
|
+
let pairCount = 0;
|
|
770
|
+
for (let i = 0; i < candidateKeys.length; i++) {
|
|
771
|
+
for (let j = i + 1; j < candidateKeys.length; j++) {
|
|
772
|
+
const keyA = candidateKeys[i] ?? "";
|
|
773
|
+
const keyB = candidateKeys[j] ?? "";
|
|
774
|
+
const setA = fileSets.get(keyA);
|
|
775
|
+
const setB = fileSets.get(keyB);
|
|
776
|
+
if (!setA || !setB) continue;
|
|
777
|
+
const similarity = jaccardSimilarity(setA, setB);
|
|
778
|
+
const pairKey = `${keyA}|${keyB}`;
|
|
779
|
+
pairwiseSimilarity[pairKey] = Math.round(similarity * 100) / 100;
|
|
780
|
+
totalSimilarity += similarity;
|
|
781
|
+
pairCount++;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const averageSimilarity = pairCount > 0 ? totalSimilarity / pairCount : 1;
|
|
785
|
+
const isCoherent = averageSimilarity >= threshold;
|
|
786
|
+
const allFileSets = Array.from(fileSets.values());
|
|
787
|
+
const allFiles = new Set(allFileSets.flatMap((s) => [...s]));
|
|
788
|
+
const commonFiles = [...allFiles].filter((file) => allFileSets.every((set) => set.has(file)));
|
|
789
|
+
const uniqueFiles = {};
|
|
790
|
+
for (const [candidateKey, files] of fileSets) {
|
|
791
|
+
const unique = [...files].filter(
|
|
792
|
+
(file) => !Array.from(fileSets.entries()).filter(([k]) => k !== candidateKey).some(([, otherSet]) => otherSet.has(file))
|
|
793
|
+
);
|
|
794
|
+
if (unique.length > 0) {
|
|
795
|
+
uniqueFiles[candidateKey] = unique;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return {
|
|
799
|
+
pairwiseSimilarity,
|
|
800
|
+
averageSimilarity: Math.round(averageSimilarity * 100) / 100,
|
|
801
|
+
isCoherent,
|
|
802
|
+
coherenceThreshold: threshold,
|
|
803
|
+
fileOverlap: {
|
|
804
|
+
commonFiles,
|
|
805
|
+
uniqueFiles
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
function matchVariantResult(spec, results) {
|
|
810
|
+
const baseMatches = results.filter(
|
|
811
|
+
(v) => v.provider === spec.provider && (spec.model === void 0 || v.model === spec.model) && (spec.strategy === void 0 || v.strategy === spec.strategy)
|
|
812
|
+
);
|
|
813
|
+
if (baseMatches.length <= 1) return baseMatches[0];
|
|
814
|
+
const specEffort = normalizeReasoningEffortInput(spec.reasoning);
|
|
815
|
+
if (specEffort !== void 0) {
|
|
816
|
+
const effortMatch = baseMatches.find(
|
|
817
|
+
(v) => normalizeReasoningEffortInput(v.requestedReasoningEffort) === specEffort
|
|
818
|
+
);
|
|
819
|
+
if (effortMatch) return effortMatch;
|
|
820
|
+
}
|
|
821
|
+
return baseMatches[0];
|
|
822
|
+
}
|
|
823
|
+
function resolveCandidateCompletenessFallback(result) {
|
|
824
|
+
const typed = resolveTypedCompletenessAuthority(result);
|
|
825
|
+
if (typed.present) {
|
|
826
|
+
return typed.usable ? typed.score : -1;
|
|
827
|
+
}
|
|
828
|
+
return result.completeness;
|
|
829
|
+
}
|
|
830
|
+
function variantResultToCandidate(spec, result) {
|
|
831
|
+
if (!result) {
|
|
832
|
+
return {
|
|
833
|
+
variant: spec,
|
|
834
|
+
success: false,
|
|
835
|
+
error: "Variant not found in results",
|
|
836
|
+
cost: 0,
|
|
837
|
+
costUnavailableReason: "provider_not_reported",
|
|
838
|
+
durationMs: 0
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
const variantEvaluation = result.judgeEvaluation?.evaluations?.find(
|
|
842
|
+
(e) => e.variant === result.variant
|
|
843
|
+
);
|
|
844
|
+
const aiJudgeScore = variantEvaluation?.qualityScore != null ? Number(variantEvaluation.qualityScore) : void 0;
|
|
845
|
+
const score = aiJudgeScore ?? result.judgeScore ?? resolveCandidateCompletenessFallback(result);
|
|
846
|
+
const feedback = generateCandidateFeedback(variantEvaluation, result);
|
|
847
|
+
const testStatus = result.testStatus;
|
|
848
|
+
const testsExecuted = result.testsExecuted;
|
|
849
|
+
const nativeObservedCost = getFiniteNumberAtPath(result, ["result", "totalCostUsd"]) ?? getFiniteNumberAtPath(result, ["result", "total_cost_usd"]) ?? getFiniteNumberAtPath(result, ["result", "totalCost"]) ?? getFiniteNumberAtPath(result, ["totalCostUsd"]);
|
|
850
|
+
const metricsCost = getFiniteNumberAtPath(result.costMetrics, ["totalCost"]) ?? getFiniteNumberAtPath(result.costMetrics, ["totalCostUsd"]);
|
|
851
|
+
const metricsUnavailableReason = resolveCostMetricsUnavailableReason(result.costMetrics);
|
|
852
|
+
let cost;
|
|
853
|
+
let costUnavailableReason;
|
|
854
|
+
if (typeof nativeObservedCost === "number") {
|
|
855
|
+
cost = nativeObservedCost;
|
|
856
|
+
costUnavailableReason = void 0;
|
|
857
|
+
} else if (typeof metricsCost === "number" && metricsCost > 0) {
|
|
858
|
+
cost = metricsCost;
|
|
859
|
+
costUnavailableReason = void 0;
|
|
860
|
+
} else if (metricsUnavailableReason !== void 0) {
|
|
861
|
+
cost = 0;
|
|
862
|
+
costUnavailableReason = metricsUnavailableReason;
|
|
863
|
+
} else if (typeof metricsCost === "number") {
|
|
864
|
+
cost = metricsCost;
|
|
865
|
+
costUnavailableReason = void 0;
|
|
866
|
+
} else {
|
|
867
|
+
cost = 0;
|
|
868
|
+
costUnavailableReason = "provider_not_reported";
|
|
869
|
+
}
|
|
870
|
+
return {
|
|
871
|
+
variant: spec,
|
|
872
|
+
success: result.success,
|
|
873
|
+
error: result.error?.message,
|
|
874
|
+
score,
|
|
875
|
+
feedback,
|
|
876
|
+
cost,
|
|
877
|
+
costUnavailableReason,
|
|
878
|
+
durationMs: getVariantDurationMs(result),
|
|
879
|
+
worktreePath: result.retainedWorktreePath,
|
|
880
|
+
changedFiles: extractChangedFiles(result),
|
|
881
|
+
changeTrackingAvailable: resultHasChangeTracking(result),
|
|
882
|
+
testStatus,
|
|
883
|
+
testsExecuted,
|
|
884
|
+
mergeInvariantValidation: result.mergeInvariantValidation
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function resolveCompetitionCostAggregate(candidates) {
|
|
888
|
+
let sum = 0;
|
|
889
|
+
let firstExplicitReason;
|
|
890
|
+
let sawPricingUnavailable = false;
|
|
891
|
+
let sawUnavailable = false;
|
|
892
|
+
for (const candidate of candidates) {
|
|
893
|
+
if (candidate.costUnavailableReason !== void 0) {
|
|
894
|
+
sawUnavailable = true;
|
|
895
|
+
if (candidate.costUnavailableReason === "pricing_unavailable") {
|
|
896
|
+
sawPricingUnavailable = true;
|
|
897
|
+
} else if (firstExplicitReason === void 0) {
|
|
898
|
+
firstExplicitReason = candidate.costUnavailableReason;
|
|
899
|
+
}
|
|
900
|
+
sum = 0;
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
if (typeof candidate.cost !== "number" || !Number.isFinite(candidate.cost)) {
|
|
904
|
+
sawUnavailable = true;
|
|
905
|
+
if (firstExplicitReason === void 0) {
|
|
906
|
+
firstExplicitReason = "provider_not_reported";
|
|
907
|
+
}
|
|
908
|
+
sum = 0;
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
if (!sawUnavailable) {
|
|
912
|
+
sum += candidate.cost;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
if (sawUnavailable) {
|
|
916
|
+
return {
|
|
917
|
+
cost: 0,
|
|
918
|
+
costUnavailableReason: sawPricingUnavailable ? "pricing_unavailable" : firstExplicitReason ?? "provider_not_reported"
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
return { cost: sum };
|
|
922
|
+
}
|
|
923
|
+
function candidateMatchesVariantResult(candidate, result) {
|
|
924
|
+
if (candidate.variant.provider !== result.provider) return false;
|
|
925
|
+
if (candidate.variant.model !== void 0 && candidate.variant.model !== result.model) {
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
if (candidate.variant.strategy !== void 0 && candidate.variant.strategy !== result.strategy) {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
const specEffort = normalizeReasoningEffortInput(candidate.variant.reasoning);
|
|
932
|
+
const resultEffort = normalizeReasoningEffortInput(result.requestedReasoningEffort);
|
|
933
|
+
if (specEffort !== void 0 && resultEffort !== void 0 && specEffort !== resultEffort) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
return true;
|
|
937
|
+
}
|
|
938
|
+
function isJudgeType(value) {
|
|
939
|
+
return value === "ai" || value === "multi-lens" || value === "multi-agent";
|
|
940
|
+
}
|
|
941
|
+
function buildMultiJudgeEvidenceBlock(args) {
|
|
942
|
+
const synthesisContext = args.judgeResult?.synthesisContext;
|
|
943
|
+
if (!synthesisContext && !args.matrixRan) {
|
|
944
|
+
return void 0;
|
|
945
|
+
}
|
|
946
|
+
const judgesWithVerdicts = synthesisContext?.judgeResults ? Object.entries(synthesisContext.judgeResults).filter(([, result]) => result !== void 0 && result !== null).map(([judgeId]) => judgeId) : [];
|
|
947
|
+
return {
|
|
948
|
+
selectedJudge: synthesisContext?.selectedJudge,
|
|
949
|
+
judgeRunRequested: args.judgeRunRequested ?? [],
|
|
950
|
+
judgesWithVerdicts,
|
|
951
|
+
allJudgesAgree: synthesisContext?.disagreement?.allAgree,
|
|
952
|
+
matrixAuthority: args.matrixAuthority,
|
|
953
|
+
matrixRan: args.matrixRan,
|
|
954
|
+
matrixProfileAgreement: args.matrixProfileAgreement,
|
|
955
|
+
matrixNonSelectionReasons: args.matrixNonSelectionReasons && args.matrixNonSelectionReasons.length > 0 ? args.matrixNonSelectionReasons : void 0
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
function findCandidateForVariantResult(candidates, result) {
|
|
959
|
+
return candidates.find((candidate) => candidateMatchesVariantResult(candidate, result));
|
|
960
|
+
}
|
|
961
|
+
function recordDeterministicTestSignalObservation(candidates, verbose) {
|
|
962
|
+
const hasVerifiedPassingCandidate = candidates.some(
|
|
963
|
+
(c) => c.success && c.testsExecuted !== void 0 && c.testStatus === "passed"
|
|
964
|
+
);
|
|
965
|
+
if (!hasVerifiedPassingCandidate) return;
|
|
966
|
+
for (const candidate of candidates) {
|
|
967
|
+
if (!candidate.success) continue;
|
|
968
|
+
if (!candidate.testsExecuted) continue;
|
|
969
|
+
const status = candidate.testStatus ?? "not_run";
|
|
970
|
+
if (status !== "failed" && status !== "error" && status !== "timeout") continue;
|
|
971
|
+
const note = `Verified failing test observation recorded (testStatus=${status}).`;
|
|
972
|
+
candidate.feedback = candidate.feedback ? `${note}
|
|
973
|
+
|
|
974
|
+
${candidate.feedback}` : note;
|
|
975
|
+
if (verbose) {
|
|
976
|
+
const id = `${candidate.variant.provider}:${candidate.variant.model ?? ""}:${candidate.variant.strategy ?? ""}`;
|
|
977
|
+
console.log(
|
|
978
|
+
chalk.yellow(` Test observation: ${id} retained score ${candidate.score ?? 0}`)
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function variantIdForSpec(spec) {
|
|
984
|
+
const provider = spec.provider ?? "";
|
|
985
|
+
const model = spec.model ?? "";
|
|
986
|
+
const strategy = spec.strategy ?? "";
|
|
987
|
+
return `${provider}:${model}:${strategy}`;
|
|
988
|
+
}
|
|
989
|
+
function variantResultDiagnosticId(result) {
|
|
990
|
+
const provider = result.provider ?? "unknown";
|
|
991
|
+
const model = result.model ?? "";
|
|
992
|
+
const strategy = result.strategy ?? "";
|
|
993
|
+
const variant = result.variant ? ` (${result.variant})` : "";
|
|
994
|
+
return `${provider}:${model}:${strategy}${variant}`;
|
|
995
|
+
}
|
|
996
|
+
function buildWinnerInfoFromJudgeVerdict(candidates, judgedWinner, judgeVisibleCandidates) {
|
|
997
|
+
const rankedPool = judgeVisibleCandidates && judgeVisibleCandidates.length > 0 ? judgeVisibleCandidates : candidates.filter((c) => c.success);
|
|
998
|
+
if (rankedPool.length === 0) {
|
|
999
|
+
return {
|
|
1000
|
+
winner: null,
|
|
1001
|
+
noWinnerReason: "all-failed",
|
|
1002
|
+
wasTie: false,
|
|
1003
|
+
rankings: []
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
const ranked = [...rankedPool].sort((a, b) => {
|
|
1007
|
+
const scoreA = Number(a.score ?? 0);
|
|
1008
|
+
const scoreB = Number(b.score ?? 0);
|
|
1009
|
+
if (scoreB !== scoreA) return scoreB - scoreA;
|
|
1010
|
+
return variantIdForSpec(a.variant).localeCompare(variantIdForSpec(b.variant));
|
|
1011
|
+
});
|
|
1012
|
+
const rankings = ranked.map((c, i) => ({
|
|
1013
|
+
variant: c.variant,
|
|
1014
|
+
score: c.score ?? 0,
|
|
1015
|
+
rank: i + 1
|
|
1016
|
+
}));
|
|
1017
|
+
const topScore = Number(ranked[0]?.score ?? 0);
|
|
1018
|
+
const tiedAtTop = ranked.filter((c) => Number(c.score ?? 0) === topScore);
|
|
1019
|
+
const wasTie = tiedAtTop.length > 1;
|
|
1020
|
+
if (!judgedWinner) {
|
|
1021
|
+
return {
|
|
1022
|
+
winner: null,
|
|
1023
|
+
wasTie,
|
|
1024
|
+
rankings
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
const winner = findCandidateForVariantResult(rankedPool, judgedWinner) ?? findCandidateForVariantResult(candidates, judgedWinner);
|
|
1028
|
+
if (!winner) {
|
|
1029
|
+
return {
|
|
1030
|
+
winner: null,
|
|
1031
|
+
wasTie,
|
|
1032
|
+
rankings,
|
|
1033
|
+
noWinnerReason: "judge-error",
|
|
1034
|
+
noWinnerDiagnostic: `AI judge selected an unmatched winner (${variantResultDiagnosticId(
|
|
1035
|
+
judgedWinner
|
|
1036
|
+
)}); judge-visible candidates: ${rankedPool.map((candidate) => variantIdForSpec(candidate.variant)).join(", ")}`
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
return {
|
|
1040
|
+
winner,
|
|
1041
|
+
wasTie,
|
|
1042
|
+
rankings
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
function attachGateObservationsToVariantResult(result, candidate) {
|
|
1046
|
+
const candidateFindings = candidate.verification?.findings ?? [];
|
|
1047
|
+
const gateError = candidate.success === false ? candidate.error : void 0;
|
|
1048
|
+
if (candidateFindings.length === 0 && !gateError) {
|
|
1049
|
+
return result;
|
|
1050
|
+
}
|
|
1051
|
+
const existingFindings = result.verification?.findings ?? [];
|
|
1052
|
+
const mergedFindings = [...existingFindings];
|
|
1053
|
+
for (const finding of candidateFindings) {
|
|
1054
|
+
const mapped = toCoreVerificationFinding(finding);
|
|
1055
|
+
const alreadyPresent = mergedFindings.some(
|
|
1056
|
+
(existing) => existing.kind === mapped.kind && existing.command === mapped.command && existing.exitCode === mapped.exitCode
|
|
1057
|
+
);
|
|
1058
|
+
if (!alreadyPresent) {
|
|
1059
|
+
mergedFindings.push(mapped);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
if (gateError && mergedFindings.length === existingFindings.length) {
|
|
1063
|
+
mergedFindings.push({
|
|
1064
|
+
kind: "other",
|
|
1065
|
+
command: "candidate-gate",
|
|
1066
|
+
exitCode: 1,
|
|
1067
|
+
severity: "error",
|
|
1068
|
+
outputTail: gateError
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
const verificationPassed = candidate.verification?.passed === false ? false : gateError ? false : result.verification?.passed ?? true;
|
|
1072
|
+
result.verification = {
|
|
1073
|
+
...result.verification ?? {},
|
|
1074
|
+
passed: verificationPassed,
|
|
1075
|
+
findings: mergedFindings
|
|
1076
|
+
};
|
|
1077
|
+
return result;
|
|
1078
|
+
}
|
|
1079
|
+
function buildJudgeVisibleVariantResults(finishedCandidates, basicVariants) {
|
|
1080
|
+
const results = [];
|
|
1081
|
+
for (const candidate of finishedCandidates) {
|
|
1082
|
+
const matching = matchVariantResult(candidate.variant, basicVariants);
|
|
1083
|
+
if (!matching) continue;
|
|
1084
|
+
results.push(attachGateObservationsToVariantResult(matching, candidate));
|
|
1085
|
+
}
|
|
1086
|
+
return results;
|
|
1087
|
+
}
|
|
1088
|
+
function determineWinner(candidates, config, expectedAllowlist) {
|
|
1089
|
+
const SCORE_COLLISION_DECIMALS = 6;
|
|
1090
|
+
const SCORE_COLLISION_MULTIPLIER = 10 ** SCORE_COLLISION_DECIMALS;
|
|
1091
|
+
const quantizeScore = (score) => {
|
|
1092
|
+
if (!Number.isFinite(score)) return 0;
|
|
1093
|
+
return Math.round(score * SCORE_COLLISION_MULTIPLIER) / SCORE_COLLISION_MULTIPLIER;
|
|
1094
|
+
};
|
|
1095
|
+
const variantIdFor = variantIdForSpec;
|
|
1096
|
+
const buildCollisionReport = (args) => {
|
|
1097
|
+
const tiedAtTop2 = [...args.tiedAtTop].map((c) => {
|
|
1098
|
+
const raw = Number(c.score ?? 0);
|
|
1099
|
+
const q = quantizeScore(raw);
|
|
1100
|
+
return { candidate: c, scoreRaw: raw, scoreQuantized: q, id: variantIdFor(c.variant) };
|
|
1101
|
+
}).sort((a, b) => a.id.localeCompare(b.id)).map((x) => ({
|
|
1102
|
+
variant: x.candidate.variant,
|
|
1103
|
+
scoreRaw: x.scoreRaw,
|
|
1104
|
+
scoreQuantized: x.scoreQuantized
|
|
1105
|
+
}));
|
|
1106
|
+
const otherCollisionGroups2 = [...args.otherCollisionGroups].sort((a, b) => b.scoreQuantized - a.scoreQuantized).map((group) => ({
|
|
1107
|
+
scoreQuantized: group.scoreQuantized,
|
|
1108
|
+
entries: [...group.entries].map((e) => ({ ...e, id: variantIdFor(e.variant) })).sort((a, b) => a.id.localeCompare(b.id)).map((e) => ({ variant: e.variant, scoreRaw: e.scoreRaw }))
|
|
1109
|
+
}));
|
|
1110
|
+
return {
|
|
1111
|
+
precisionDecimals: SCORE_COLLISION_DECIMALS,
|
|
1112
|
+
quantization: "round",
|
|
1113
|
+
topScoreRaw: args.topScoreRaw,
|
|
1114
|
+
topScoreQuantized: args.topScoreQuantized,
|
|
1115
|
+
successfulCandidateCount: args.successfulCount,
|
|
1116
|
+
collisionGroupCount: args.collisionGroupsAll.length,
|
|
1117
|
+
collisionPairCount: args.collisionGroupsAll.reduce(
|
|
1118
|
+
(sum, g) => sum + g.entries.length * (g.entries.length - 1) / 2,
|
|
1119
|
+
0
|
|
1120
|
+
),
|
|
1121
|
+
tiedAtTopPairCount: args.tiedAtTop.length * (args.tiedAtTop.length - 1) / 2,
|
|
1122
|
+
tiedAtTop: tiedAtTop2,
|
|
1123
|
+
otherCollisionGroups: otherCollisionGroups2,
|
|
1124
|
+
applied: args.applied
|
|
1125
|
+
};
|
|
1126
|
+
};
|
|
1127
|
+
const computeCollisionGroups = (rankedSuccessful) => {
|
|
1128
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1129
|
+
for (const candidate of rankedSuccessful) {
|
|
1130
|
+
const scoreRaw = Number(candidate.score ?? 0);
|
|
1131
|
+
const scoreQuantized = quantizeScore(scoreRaw);
|
|
1132
|
+
const existing = groups.get(scoreQuantized);
|
|
1133
|
+
if (existing) {
|
|
1134
|
+
existing.push({ variant: candidate.variant, scoreRaw });
|
|
1135
|
+
} else {
|
|
1136
|
+
groups.set(scoreQuantized, [{ variant: candidate.variant, scoreRaw }]);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
const out = [];
|
|
1140
|
+
for (const [scoreQuantized, entries] of groups.entries()) {
|
|
1141
|
+
if (entries.length < 2) continue;
|
|
1142
|
+
out.push({ scoreQuantized, entries });
|
|
1143
|
+
}
|
|
1144
|
+
return out;
|
|
1145
|
+
};
|
|
1146
|
+
const successfulCandidates = candidates.filter((c) => c.success);
|
|
1147
|
+
const threshold = config.judgeConfig?.threshold ?? 0;
|
|
1148
|
+
const allowBelowThresholdWinner = config.judgeConfig?.allowBelowThresholdWinner ?? true;
|
|
1149
|
+
if (successfulCandidates.length === 0) {
|
|
1150
|
+
return {
|
|
1151
|
+
winner: null,
|
|
1152
|
+
noWinnerReason: "all-failed",
|
|
1153
|
+
wasTie: false,
|
|
1154
|
+
rankings: []
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
const cleanCandidates = successfulCandidates.filter(
|
|
1158
|
+
(c) => !c.verification || c.verification.passed
|
|
1159
|
+
);
|
|
1160
|
+
const candidatesWithFindings = successfulCandidates.filter(
|
|
1161
|
+
(c) => c.verification && !c.verification.passed
|
|
1162
|
+
);
|
|
1163
|
+
const candidatesToRank = cleanCandidates.length > 0 ? cleanCandidates : successfulCandidates;
|
|
1164
|
+
const ranked = [...candidatesToRank].sort((a, b) => {
|
|
1165
|
+
const scoreA = Number(a.score ?? 0);
|
|
1166
|
+
const scoreB = Number(b.score ?? 0);
|
|
1167
|
+
const qa = quantizeScore(scoreA);
|
|
1168
|
+
const qb = quantizeScore(scoreB);
|
|
1169
|
+
if (qb !== qa) return qb - qa;
|
|
1170
|
+
return variantIdFor(a.variant).localeCompare(variantIdFor(b.variant));
|
|
1171
|
+
});
|
|
1172
|
+
const rankings = ranked.map((c, i) => ({
|
|
1173
|
+
variant: c.variant,
|
|
1174
|
+
score: c.score ?? 0,
|
|
1175
|
+
rank: i + 1
|
|
1176
|
+
}));
|
|
1177
|
+
const topScore = Number(ranked[0]?.score ?? 0);
|
|
1178
|
+
const topScoreQuantized = quantizeScore(topScore);
|
|
1179
|
+
const tiedAtTop = ranked.filter((c) => quantizeScore(Number(c.score ?? 0)) === topScoreQuantized);
|
|
1180
|
+
const wasTie = tiedAtTop.length > 1;
|
|
1181
|
+
const collisionGroups = computeCollisionGroups(ranked);
|
|
1182
|
+
const otherCollisionGroups = collisionGroups.filter((g) => g.scoreQuantized !== topScoreQuantized).slice(0, 10);
|
|
1183
|
+
const scoreCollisionReportBase = wasTie || otherCollisionGroups.length > 0 ? {
|
|
1184
|
+
ranked,
|
|
1185
|
+
successfulCount: candidatesToRank.length,
|
|
1186
|
+
collisionGroupsAll: collisionGroups,
|
|
1187
|
+
topScoreRaw: topScore,
|
|
1188
|
+
topScoreQuantized,
|
|
1189
|
+
tiedAtTop,
|
|
1190
|
+
otherCollisionGroups
|
|
1191
|
+
} : null;
|
|
1192
|
+
if (wasTie) {
|
|
1193
|
+
if (config.applyWinner) {
|
|
1194
|
+
const tieBreakerConfig = config.tieBreaker ?? (config.candidateGate?.coverage ? { mode: "prefer-low-drift-then-diff" } : { mode: "prefer-first-ranked" });
|
|
1195
|
+
let winner2 = null;
|
|
1196
|
+
let resolvedBy = "rank";
|
|
1197
|
+
const getCandidateChangedFileCount = (candidate) => Array.isArray(candidate.changedFiles) ? candidate.changedFiles.length : 0;
|
|
1198
|
+
const getCandidateDriftViolations = (candidate) => {
|
|
1199
|
+
if (!Array.isArray(candidate.changedFiles) || candidate.changedFiles.length === 0) return 0;
|
|
1200
|
+
if (!Array.isArray(expectedAllowlist) || expectedAllowlist.length === 0) return 0;
|
|
1201
|
+
return findAllowlistViolations(candidate.changedFiles, expectedAllowlist).length;
|
|
1202
|
+
};
|
|
1203
|
+
if (tieBreakerConfig.mode === "inconclusive") {
|
|
1204
|
+
const aiJudgeDisabled = config.judgeConfig?.disableAiJudge === true;
|
|
1205
|
+
if (aiJudgeDisabled) {
|
|
1206
|
+
const scoreCollisionReport2 = scoreCollisionReportBase && scoreCollisionReportBase.tiedAtTop.length > 1 ? buildCollisionReport({
|
|
1207
|
+
...scoreCollisionReportBase,
|
|
1208
|
+
applied: {
|
|
1209
|
+
applyWinner: Boolean(config.applyWinner),
|
|
1210
|
+
wasTie: true,
|
|
1211
|
+
noWinnerReason: "tie",
|
|
1212
|
+
tieBreakerMode: tieBreakerConfig.mode,
|
|
1213
|
+
resolvedBy: void 0,
|
|
1214
|
+
winnerVariant: void 0
|
|
1215
|
+
}
|
|
1216
|
+
}) : void 0;
|
|
1217
|
+
return {
|
|
1218
|
+
winner: null,
|
|
1219
|
+
noWinnerReason: "tie",
|
|
1220
|
+
wasTie: true,
|
|
1221
|
+
rankings,
|
|
1222
|
+
scoreCollisionReport: scoreCollisionReport2
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
winner2 = tiedAtTop[0] ?? null;
|
|
1226
|
+
resolvedBy = "rank";
|
|
1227
|
+
} else if (tieBreakerConfig.mode === "prefer-first-ranked") {
|
|
1228
|
+
winner2 = tiedAtTop[0] ?? null;
|
|
1229
|
+
} else if (tieBreakerConfig.mode === "prefer-strategy" && tieBreakerConfig.strategy) {
|
|
1230
|
+
winner2 = tiedAtTop.find((c) => c.variant.strategy === tieBreakerConfig.strategy) ?? tiedAtTop[0] ?? null;
|
|
1231
|
+
resolvedBy = "strategy";
|
|
1232
|
+
} else if (tieBreakerConfig.mode === "prefer-low-drift") {
|
|
1233
|
+
winner2 = [...tiedAtTop].sort((a, b) => {
|
|
1234
|
+
const driftDelta = getCandidateDriftViolations(a) - getCandidateDriftViolations(b);
|
|
1235
|
+
if (driftDelta !== 0) return driftDelta;
|
|
1236
|
+
return variantIdFor(a.variant).localeCompare(variantIdFor(b.variant));
|
|
1237
|
+
})[0] ?? null;
|
|
1238
|
+
resolvedBy = "drift";
|
|
1239
|
+
} else if (tieBreakerConfig.mode === "prefer-smaller-diff") {
|
|
1240
|
+
winner2 = [...tiedAtTop].sort((a, b) => {
|
|
1241
|
+
const diffDelta = getCandidateChangedFileCount(a) - getCandidateChangedFileCount(b);
|
|
1242
|
+
if (diffDelta !== 0) return diffDelta;
|
|
1243
|
+
return variantIdFor(a.variant).localeCompare(variantIdFor(b.variant));
|
|
1244
|
+
})[0] ?? null;
|
|
1245
|
+
resolvedBy = "diff";
|
|
1246
|
+
} else if (tieBreakerConfig.mode === "prefer-low-drift-then-diff") {
|
|
1247
|
+
winner2 = [...tiedAtTop].sort((a, b) => {
|
|
1248
|
+
const driftDelta = getCandidateDriftViolations(a) - getCandidateDriftViolations(b);
|
|
1249
|
+
if (driftDelta !== 0) return driftDelta;
|
|
1250
|
+
const diffDelta = getCandidateChangedFileCount(a) - getCandidateChangedFileCount(b);
|
|
1251
|
+
if (diffDelta !== 0) return diffDelta;
|
|
1252
|
+
return variantIdFor(a.variant).localeCompare(variantIdFor(b.variant));
|
|
1253
|
+
})[0] ?? null;
|
|
1254
|
+
if (winner2) {
|
|
1255
|
+
const winnerDrift = getCandidateDriftViolations(winner2);
|
|
1256
|
+
const allSameDrift = tiedAtTop.every(
|
|
1257
|
+
(c) => getCandidateDriftViolations(c) === winnerDrift
|
|
1258
|
+
);
|
|
1259
|
+
if (!allSameDrift) {
|
|
1260
|
+
resolvedBy = "drift";
|
|
1261
|
+
} else {
|
|
1262
|
+
const winnerDiff = getCandidateChangedFileCount(winner2);
|
|
1263
|
+
const allSameDiff = tiedAtTop.every(
|
|
1264
|
+
(c) => getCandidateChangedFileCount(c) === winnerDiff
|
|
1265
|
+
);
|
|
1266
|
+
resolvedBy = allSameDiff ? "rank" : "diff";
|
|
1267
|
+
}
|
|
1268
|
+
} else {
|
|
1269
|
+
resolvedBy = "drift";
|
|
1270
|
+
}
|
|
1271
|
+
} else {
|
|
1272
|
+
winner2 = tiedAtTop[0] ?? null;
|
|
1273
|
+
}
|
|
1274
|
+
if (!winner2) winner2 = ranked[0] ?? null;
|
|
1275
|
+
if (winner2) {
|
|
1276
|
+
const scoreCollisionReport2 = scoreCollisionReportBase && scoreCollisionReportBase.tiedAtTop.length > 1 ? buildCollisionReport({
|
|
1277
|
+
...scoreCollisionReportBase,
|
|
1278
|
+
applied: {
|
|
1279
|
+
applyWinner: true,
|
|
1280
|
+
wasTie: true,
|
|
1281
|
+
noWinnerReason: void 0,
|
|
1282
|
+
tieBreakerMode: tieBreakerConfig.mode,
|
|
1283
|
+
resolvedBy,
|
|
1284
|
+
winnerVariant: winner2.variant
|
|
1285
|
+
}
|
|
1286
|
+
}) : void 0;
|
|
1287
|
+
return {
|
|
1288
|
+
winner: winner2,
|
|
1289
|
+
wasTie: true,
|
|
1290
|
+
// Still record that there was a tie
|
|
1291
|
+
rankings,
|
|
1292
|
+
tieBreaker: {
|
|
1293
|
+
mode: tieBreakerConfig.mode,
|
|
1294
|
+
preferredStrategy: tieBreakerConfig.strategy,
|
|
1295
|
+
resolvedBy,
|
|
1296
|
+
winnerDriftViolations: getCandidateDriftViolations(winner2),
|
|
1297
|
+
winnerChangedFiles: getCandidateChangedFileCount(winner2),
|
|
1298
|
+
tieScore: topScore,
|
|
1299
|
+
tieScoreRounded: topScoreQuantized,
|
|
1300
|
+
tieScoreRoundedDecimals: SCORE_COLLISION_DECIMALS,
|
|
1301
|
+
tiedCount: tiedAtTop.length
|
|
1302
|
+
},
|
|
1303
|
+
scoreCollisionReport: scoreCollisionReport2
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
const scoreCollisionReport = scoreCollisionReportBase && scoreCollisionReportBase.tiedAtTop.length > 1 ? buildCollisionReport({
|
|
1308
|
+
...scoreCollisionReportBase,
|
|
1309
|
+
applied: {
|
|
1310
|
+
applyWinner: Boolean(config.applyWinner),
|
|
1311
|
+
wasTie: true,
|
|
1312
|
+
noWinnerReason: "tie",
|
|
1313
|
+
tieBreakerMode: config.tieBreaker?.mode,
|
|
1314
|
+
resolvedBy: void 0,
|
|
1315
|
+
winnerVariant: void 0
|
|
1316
|
+
}
|
|
1317
|
+
}) : void 0;
|
|
1318
|
+
return {
|
|
1319
|
+
winner: null,
|
|
1320
|
+
noWinnerReason: "tie",
|
|
1321
|
+
wasTie: true,
|
|
1322
|
+
rankings,
|
|
1323
|
+
scoreCollisionReport
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
if (topScore < threshold) {
|
|
1327
|
+
const verificationPolicy = config.verificationPolicy ?? "findings";
|
|
1328
|
+
if (verificationPolicy === "findings") {
|
|
1329
|
+
const bestRepairable = candidatesWithFindings.map((c) => ({
|
|
1330
|
+
candidate: c,
|
|
1331
|
+
effectiveScore: c.scoreBeforeTestSignal ?? c.score ?? 0
|
|
1332
|
+
})).filter((x) => x.effectiveScore >= threshold).sort((a, b) => b.effectiveScore - a.effectiveScore)[0]?.candidate;
|
|
1333
|
+
if (bestRepairable) {
|
|
1334
|
+
const restoredScore = bestRepairable.scoreBeforeTestSignal ?? bestRepairable.score;
|
|
1335
|
+
return {
|
|
1336
|
+
winner: {
|
|
1337
|
+
...bestRepairable,
|
|
1338
|
+
score: restoredScore,
|
|
1339
|
+
feedback: bestRepairable.feedback ? `Selected for repair (tests recorded findings; observed score: ${restoredScore}).
|
|
1340
|
+
|
|
1341
|
+
${bestRepairable.feedback}` : `Selected for repair (tests recorded findings; observed score: ${restoredScore}).`
|
|
1342
|
+
},
|
|
1343
|
+
wasTie: false,
|
|
1344
|
+
rankings
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
if (allowBelowThresholdWinner) {
|
|
1349
|
+
const winner2 = ranked[0] ?? null;
|
|
1350
|
+
if (winner2) {
|
|
1351
|
+
return {
|
|
1352
|
+
winner: winner2,
|
|
1353
|
+
wasTie: false,
|
|
1354
|
+
rankings,
|
|
1355
|
+
belowThresholdWinner: {
|
|
1356
|
+
threshold,
|
|
1357
|
+
winnerScore: topScore
|
|
1358
|
+
},
|
|
1359
|
+
scoreCollisionReport: scoreCollisionReportBase && (scoreCollisionReportBase.tiedAtTop.length > 1 || scoreCollisionReportBase.otherCollisionGroups.length > 0) ? buildCollisionReport({
|
|
1360
|
+
...scoreCollisionReportBase,
|
|
1361
|
+
applied: {
|
|
1362
|
+
applyWinner: Boolean(config.applyWinner),
|
|
1363
|
+
wasTie: false,
|
|
1364
|
+
noWinnerReason: void 0,
|
|
1365
|
+
tieBreakerMode: config.tieBreaker?.mode,
|
|
1366
|
+
resolvedBy: void 0,
|
|
1367
|
+
winnerVariant: winner2.variant
|
|
1368
|
+
}
|
|
1369
|
+
}) : void 0
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return {
|
|
1374
|
+
winner: null,
|
|
1375
|
+
noWinnerReason: "below-threshold",
|
|
1376
|
+
wasTie: false,
|
|
1377
|
+
rankings,
|
|
1378
|
+
scoreCollisionReport: scoreCollisionReportBase && (scoreCollisionReportBase.tiedAtTop.length > 1 || scoreCollisionReportBase.otherCollisionGroups.length > 0) ? buildCollisionReport({
|
|
1379
|
+
...scoreCollisionReportBase,
|
|
1380
|
+
applied: {
|
|
1381
|
+
applyWinner: Boolean(config.applyWinner),
|
|
1382
|
+
wasTie: false,
|
|
1383
|
+
noWinnerReason: "below-threshold",
|
|
1384
|
+
tieBreakerMode: config.tieBreaker?.mode,
|
|
1385
|
+
resolvedBy: void 0,
|
|
1386
|
+
winnerVariant: void 0
|
|
1387
|
+
}
|
|
1388
|
+
}) : void 0
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
const winner = ranked[0] ?? null;
|
|
1392
|
+
return {
|
|
1393
|
+
winner,
|
|
1394
|
+
wasTie: false,
|
|
1395
|
+
rankings,
|
|
1396
|
+
scoreCollisionReport: scoreCollisionReportBase && (scoreCollisionReportBase.tiedAtTop.length > 1 || scoreCollisionReportBase.otherCollisionGroups.length > 0) ? buildCollisionReport({
|
|
1397
|
+
...scoreCollisionReportBase,
|
|
1398
|
+
applied: {
|
|
1399
|
+
applyWinner: Boolean(config.applyWinner),
|
|
1400
|
+
wasTie: false,
|
|
1401
|
+
noWinnerReason: void 0,
|
|
1402
|
+
tieBreakerMode: config.tieBreaker?.mode,
|
|
1403
|
+
resolvedBy: void 0,
|
|
1404
|
+
winnerVariant: winner?.variant
|
|
1405
|
+
}
|
|
1406
|
+
}) : void 0
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
var __internalDetermineWinner = determineWinner;
|
|
1410
|
+
var __internalRecordDeterministicTestSignalObservation = recordDeterministicTestSignalObservation;
|
|
1411
|
+
var __internalExtractChangedFilesFromResult = extractChangedFilesFromResult;
|
|
1412
|
+
var __internalGetVariantTelemetryStatePath = getVariantTelemetryStatePath;
|
|
1413
|
+
var __internalHydrateCandidateCostsFromTelemetry = hydrateCandidateCostsFromTelemetry;
|
|
1414
|
+
var __internalVariantResultToCandidate = variantResultToCandidate;
|
|
1415
|
+
var __internalMatchVariantResult = matchVariantResult;
|
|
1416
|
+
var __internalCandidateMatchesVariantResult = candidateMatchesVariantResult;
|
|
1417
|
+
var __internalResolveCompetitionCostAggregate = resolveCompetitionCostAggregate;
|
|
1418
|
+
function synthesizeDeterministicRationalePacket(candidates, winnerInfo, config) {
|
|
1419
|
+
const { winner, wasTie, noWinnerReason, tieBreaker, belowThresholdWinner } = winnerInfo;
|
|
1420
|
+
const buildVariantId = (candidate) => {
|
|
1421
|
+
const parts = [candidate.variant.provider];
|
|
1422
|
+
if (candidate.variant.model) parts.push(candidate.variant.model);
|
|
1423
|
+
if (candidate.variant.strategy) parts.push(candidate.variant.strategy);
|
|
1424
|
+
return parts.join(":");
|
|
1425
|
+
};
|
|
1426
|
+
const candidateToVariantResult = (candidate) => ({
|
|
1427
|
+
variant: buildVariantId(candidate),
|
|
1428
|
+
success: candidate.success,
|
|
1429
|
+
testStatus: candidate.testStatus,
|
|
1430
|
+
testsExecuted: candidate.testsExecuted ? {
|
|
1431
|
+
scope: candidate.testsExecuted.scope ?? "touched",
|
|
1432
|
+
filesTested: candidate.testsExecuted.filesTested ?? [],
|
|
1433
|
+
exitCode: candidate.testsExecuted.exitCode,
|
|
1434
|
+
durationMs: candidate.testsExecuted.durationMs
|
|
1435
|
+
} : void 0,
|
|
1436
|
+
emptyChanges: !candidate.changedFiles?.length,
|
|
1437
|
+
gitMetrics: candidate.changedFiles ? { filesChanged: candidate.changedFiles.length, linesAdded: 0, linesDeleted: 0 } : void 0,
|
|
1438
|
+
worktreeSummary: candidate.changedFiles ? {
|
|
1439
|
+
filesChanged: candidate.changedFiles.length,
|
|
1440
|
+
insertions: 0,
|
|
1441
|
+
deletions: 0,
|
|
1442
|
+
statusLines: candidate.changedFiles.map((f) => `M ${f}`)
|
|
1443
|
+
} : void 0
|
|
1444
|
+
});
|
|
1445
|
+
const effectiveWinner = winner;
|
|
1446
|
+
const winnerId = effectiveWinner ? buildVariantId(effectiveWinner) : "none";
|
|
1447
|
+
const scores = {};
|
|
1448
|
+
for (const candidate of candidates) {
|
|
1449
|
+
const variantId = buildVariantId(candidate);
|
|
1450
|
+
scores[variantId] = candidate.score ?? 0;
|
|
1451
|
+
}
|
|
1452
|
+
let unverifiedNegativeClaimCount = 0;
|
|
1453
|
+
const scoreBreakdown = {};
|
|
1454
|
+
for (const candidate of candidates) {
|
|
1455
|
+
const variantId = buildVariantId(candidate);
|
|
1456
|
+
const finalScore = candidate.score ?? 0;
|
|
1457
|
+
const subscores = {};
|
|
1458
|
+
const penalties = {};
|
|
1459
|
+
if (typeof candidate.score === "number") {
|
|
1460
|
+
subscores.delivery = candidate.score;
|
|
1461
|
+
}
|
|
1462
|
+
const deductions = [];
|
|
1463
|
+
if (candidate.testStatus === "failed" || candidate.testStatus === "error") {
|
|
1464
|
+
const testPenalty = candidate.scoreBeforeTestSignal ? candidate.scoreBeforeTestSignal - (candidate.score ?? 0) : 10;
|
|
1465
|
+
penalties.testFailure = testPenalty;
|
|
1466
|
+
const testEvidence = [];
|
|
1467
|
+
testEvidence.push({
|
|
1468
|
+
type: "metric",
|
|
1469
|
+
value: `testStatus: ${candidate.testStatus}`,
|
|
1470
|
+
context: "Test execution result"
|
|
1471
|
+
});
|
|
1472
|
+
if (candidate.testsExecuted?.exitCode !== void 0) {
|
|
1473
|
+
testEvidence.push({
|
|
1474
|
+
type: "metric",
|
|
1475
|
+
value: `exit code: ${candidate.testsExecuted.exitCode}`,
|
|
1476
|
+
context: "Test runner exit code"
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
deductions.push({
|
|
1480
|
+
code: "test_failure",
|
|
1481
|
+
delta: -testPenalty,
|
|
1482
|
+
evidence: testEvidence,
|
|
1483
|
+
reason: "Tests failed during verification"
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
if (!candidate.changedFiles?.length && candidate.success) {
|
|
1487
|
+
deductions.push({
|
|
1488
|
+
code: "empty_changes",
|
|
1489
|
+
delta: -50,
|
|
1490
|
+
evidence: [
|
|
1491
|
+
{
|
|
1492
|
+
type: "metric",
|
|
1493
|
+
value: "0 files changed",
|
|
1494
|
+
context: "Git status shows no changes"
|
|
1495
|
+
}
|
|
1496
|
+
],
|
|
1497
|
+
reason: "No code changes detected"
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
if (Array.isArray(candidate.changedFiles) && candidate.changedFiles.length > 10) {
|
|
1501
|
+
const excessPenalty = Math.min(10, (candidate.changedFiles.length - 10) * 2);
|
|
1502
|
+
penalties.other = excessPenalty;
|
|
1503
|
+
deductions.push({
|
|
1504
|
+
code: "off_target_files",
|
|
1505
|
+
delta: -excessPenalty,
|
|
1506
|
+
evidence: [
|
|
1507
|
+
{
|
|
1508
|
+
type: "metric",
|
|
1509
|
+
value: `${candidate.changedFiles.length} files changed`,
|
|
1510
|
+
context: "Excessive file changes may indicate scope creep"
|
|
1511
|
+
}
|
|
1512
|
+
],
|
|
1513
|
+
reason: "Modified more than 10 files"
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
const weights = {
|
|
1517
|
+
delivery: 1
|
|
1518
|
+
// Deterministic mode uses completeness as sole factor
|
|
1519
|
+
};
|
|
1520
|
+
const testStatus = candidate.testStatus;
|
|
1521
|
+
const testsExecuted = candidate.testsExecuted;
|
|
1522
|
+
scoreBreakdown[variantId] = {
|
|
1523
|
+
finalScore,
|
|
1524
|
+
subscores,
|
|
1525
|
+
weights,
|
|
1526
|
+
penalties: Object.keys(penalties).length > 0 ? penalties : void 0,
|
|
1527
|
+
aggregationMethod: "weighted_average",
|
|
1528
|
+
// Default for deterministic scoring
|
|
1529
|
+
// P2: Include floor (harmonic mean floor = 18 in Judge v2.2)
|
|
1530
|
+
floorApplied: 18,
|
|
1531
|
+
// P2b: Structured test status (first-class signal)
|
|
1532
|
+
...testStatus && {
|
|
1533
|
+
testSignal: {
|
|
1534
|
+
status: testStatus,
|
|
1535
|
+
scope: testsExecuted?.scope,
|
|
1536
|
+
exitCode: testsExecuted?.exitCode,
|
|
1537
|
+
durationMs: testsExecuted?.durationMs,
|
|
1538
|
+
penaltyApplied: testStatus === "failed" || testStatus === "error" ? (penalties.testFailure ?? 0) > 0 : false
|
|
1539
|
+
}
|
|
1540
|
+
},
|
|
1541
|
+
// Include deduction trace with evidence (v0.5.0)
|
|
1542
|
+
deductions: deductions.length > 0 ? deductions : void 0
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
const highestScoringCandidate = candidates.filter((candidate) => candidate.success && typeof candidate.score === "number").sort((a, b) => {
|
|
1546
|
+
const scoreDelta = Number(b.score ?? 0) - Number(a.score ?? 0);
|
|
1547
|
+
if (scoreDelta !== 0) return scoreDelta;
|
|
1548
|
+
return buildVariantId(a).localeCompare(buildVariantId(b));
|
|
1549
|
+
})[0];
|
|
1550
|
+
const highestScoringCandidateId = highestScoringCandidate ? buildVariantId(highestScoringCandidate) : void 0;
|
|
1551
|
+
const highestScore = highestScoringCandidate?.score ?? 0;
|
|
1552
|
+
const winnerScore = effectiveWinner?.score ?? 0;
|
|
1553
|
+
const winnerHasHighestDeterministicScore = Boolean(effectiveWinner) && (!highestScoringCandidate || highestScoringCandidateId === winnerId || Number(winnerScore) >= Number(highestScore));
|
|
1554
|
+
const candidateAnalysis = candidates.map((candidate) => {
|
|
1555
|
+
const variantId = buildVariantId(candidate);
|
|
1556
|
+
const isWinner = effectiveWinner && buildVariantId(effectiveWinner) === variantId;
|
|
1557
|
+
const strengths = [];
|
|
1558
|
+
const weaknesses = [];
|
|
1559
|
+
const missedRequirements = [];
|
|
1560
|
+
const riskyAreas = [];
|
|
1561
|
+
if (candidate.success) {
|
|
1562
|
+
strengths.push("Execution succeeded");
|
|
1563
|
+
if (typeof candidate.score === "number" && candidate.score > 80) {
|
|
1564
|
+
strengths.push(`High score: ${candidate.score}`);
|
|
1565
|
+
}
|
|
1566
|
+
if (candidate.testsExecuted && candidate.testStatus) {
|
|
1567
|
+
const scope = candidate.testsExecuted.scope ?? "unknown";
|
|
1568
|
+
if (candidate.testStatus === "passed") {
|
|
1569
|
+
strengths.push(`Tests passed (${scope})`);
|
|
1570
|
+
} else if (candidate.testStatus !== "not_run") {
|
|
1571
|
+
weaknesses.push(`Tests ${candidate.testStatus} (${scope})`);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
if (Array.isArray(candidate.changedFiles) && candidate.changedFiles.length > 0) {
|
|
1575
|
+
strengths.push(`Modified ${candidate.changedFiles.length} file(s)`);
|
|
1576
|
+
}
|
|
1577
|
+
} else {
|
|
1578
|
+
weaknesses.push("Execution failed");
|
|
1579
|
+
if (candidate.error) {
|
|
1580
|
+
weaknesses.push(`Error: ${candidate.error}`);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
if (!isWinner && candidate.success) {
|
|
1584
|
+
const candidateScore = candidate.score ?? 0;
|
|
1585
|
+
if (effectiveWinner && typeof candidate.score === "number") {
|
|
1586
|
+
if (candidateScore > winnerScore) {
|
|
1587
|
+
weaknesses.push(
|
|
1588
|
+
`Not selected despite higher deterministic score (${candidateScore} vs selected ${winnerScore})`
|
|
1589
|
+
);
|
|
1590
|
+
} else if (candidateScore === winnerScore) {
|
|
1591
|
+
weaknesses.push("Final tie-breaker selected another candidate");
|
|
1592
|
+
} else {
|
|
1593
|
+
weaknesses.push("Lower score than winner");
|
|
1594
|
+
}
|
|
1595
|
+
} else {
|
|
1596
|
+
weaknesses.push("Did not win final selection");
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
const variantForEvidence = candidateToVariantResult(candidate);
|
|
1600
|
+
const weaknessEvidence = {
|
|
1601
|
+
weaknesses: weaknesses.map((weakness, index) => {
|
|
1602
|
+
const isNegative = isNegativeClaim(weakness);
|
|
1603
|
+
const anchors = isNegative ? extractEvidenceAnchors(weakness, variantForEvidence) : [];
|
|
1604
|
+
const verified = !isNegative || anchors.length > 0;
|
|
1605
|
+
if (isNegative && !verified) {
|
|
1606
|
+
unverifiedNegativeClaimCount++;
|
|
1607
|
+
}
|
|
1608
|
+
return {
|
|
1609
|
+
index,
|
|
1610
|
+
anchors: anchors.map((a) => ({
|
|
1611
|
+
type: a.type,
|
|
1612
|
+
value: a.value,
|
|
1613
|
+
context: a.context
|
|
1614
|
+
})),
|
|
1615
|
+
verified
|
|
1616
|
+
};
|
|
1617
|
+
})
|
|
1618
|
+
};
|
|
1619
|
+
return {
|
|
1620
|
+
variantId,
|
|
1621
|
+
strengths,
|
|
1622
|
+
weaknesses,
|
|
1623
|
+
missedRequirements,
|
|
1624
|
+
riskyAreas,
|
|
1625
|
+
evidence: weaknessEvidence.weaknesses?.length ? weaknessEvidence : void 0
|
|
1626
|
+
};
|
|
1627
|
+
});
|
|
1628
|
+
let primaryReason = "Winner selected by deterministic scoring";
|
|
1629
|
+
const keyFactors = [];
|
|
1630
|
+
const selectionEvidence = [];
|
|
1631
|
+
if (noWinnerReason) {
|
|
1632
|
+
const reasons = {
|
|
1633
|
+
"all-failed": "All variants failed execution",
|
|
1634
|
+
tie: "Tie between top variants",
|
|
1635
|
+
"below-threshold": `All scores below threshold (${config.judgeConfig?.threshold ?? 0})`,
|
|
1636
|
+
"judge-error": "Judge evaluation failed",
|
|
1637
|
+
incomparable: "Candidates touched disjoint files (low coherence)"
|
|
1638
|
+
};
|
|
1639
|
+
primaryReason = reasons[noWinnerReason] ?? noWinnerReason;
|
|
1640
|
+
} else if (wasTie && tieBreaker) {
|
|
1641
|
+
primaryReason = `Tie resolved by ${tieBreaker.mode} tiebreaker`;
|
|
1642
|
+
keyFactors.push(`Tiebreaker mode: ${tieBreaker.mode}`);
|
|
1643
|
+
if (tieBreaker.resolvedBy) {
|
|
1644
|
+
keyFactors.push(`Resolved by: ${tieBreaker.resolvedBy}`);
|
|
1645
|
+
}
|
|
1646
|
+
} else if (winner) {
|
|
1647
|
+
primaryReason = winnerHasHighestDeterministicScore ? "Highest deterministic score" : "Final winner selected by judge or selection policy despite lower deterministic score";
|
|
1648
|
+
keyFactors.push(`Score: ${winner.score ?? 0}`);
|
|
1649
|
+
if (!winnerHasHighestDeterministicScore && highestScoringCandidateId) {
|
|
1650
|
+
keyFactors.push(`Top deterministic score: ${highestScoringCandidateId} (${highestScore})`);
|
|
1651
|
+
keyFactors.push(`Selected winner score: ${winnerId} (${winnerScore})`);
|
|
1652
|
+
}
|
|
1653
|
+
selectionEvidence.push({
|
|
1654
|
+
type: "metric",
|
|
1655
|
+
value: `score: ${winner.score ?? 0}`,
|
|
1656
|
+
context: "Winner deterministic score"
|
|
1657
|
+
});
|
|
1658
|
+
if (winner.changedFiles?.length) {
|
|
1659
|
+
selectionEvidence.push({
|
|
1660
|
+
type: "metric",
|
|
1661
|
+
value: `${winner.changedFiles.length} files changed`,
|
|
1662
|
+
context: "Winner modified files"
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
if (belowThresholdWinner) {
|
|
1666
|
+
keyFactors.push(
|
|
1667
|
+
`Below threshold: ${belowThresholdWinner.winnerScore} < ${belowThresholdWinner.threshold}`
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
if (winner.testsExecuted && winner.testStatus === "passed") {
|
|
1671
|
+
keyFactors.push("Verified passing tests");
|
|
1672
|
+
selectionEvidence.push({
|
|
1673
|
+
type: "metric",
|
|
1674
|
+
value: "testStatus: passed",
|
|
1675
|
+
context: `Tests verified (${winner.testsExecuted.scope ?? "unknown"} scope)`
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
if (winner.feedback) {
|
|
1679
|
+
keyFactors.push("Has feedback from deterministic evaluation");
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
const rejectionReasons = {};
|
|
1683
|
+
const rejectionReasonsEvidence = {};
|
|
1684
|
+
for (const candidate of candidates) {
|
|
1685
|
+
const variantId = buildVariantId(candidate);
|
|
1686
|
+
if (effectiveWinner && buildVariantId(effectiveWinner) === variantId) continue;
|
|
1687
|
+
let reason;
|
|
1688
|
+
if (!candidate.success) {
|
|
1689
|
+
reason = candidate.error ?? "Execution failed";
|
|
1690
|
+
} else if (candidate.testsExecuted && candidate.testStatus && candidate.testStatus !== "passed") {
|
|
1691
|
+
reason = `Verified failing tests (testStatus=${candidate.testStatus})`;
|
|
1692
|
+
} else if (typeof candidate.score === "number" && typeof effectiveWinner?.score === "number") {
|
|
1693
|
+
if (candidate.score > effectiveWinner.score) {
|
|
1694
|
+
reason = `Not selected despite higher deterministic score (${candidate.score} vs selected ${effectiveWinner.score})`;
|
|
1695
|
+
} else if (candidate.score === effectiveWinner.score) {
|
|
1696
|
+
reason = `Final tie-breaker selected another candidate (${candidate.score} vs selected ${effectiveWinner.score})`;
|
|
1697
|
+
} else {
|
|
1698
|
+
reason = `Lower score (${candidate.score} vs ${effectiveWinner.score})`;
|
|
1699
|
+
}
|
|
1700
|
+
} else {
|
|
1701
|
+
reason = "Did not win deterministic selection";
|
|
1702
|
+
}
|
|
1703
|
+
rejectionReasons[variantId] = reason;
|
|
1704
|
+
if (isNegativeClaim(reason)) {
|
|
1705
|
+
const variantForEvidence = candidateToVariantResult(candidate);
|
|
1706
|
+
const anchors = extractEvidenceAnchors(reason, variantForEvidence);
|
|
1707
|
+
const verified = anchors.length > 0;
|
|
1708
|
+
rejectionReasonsEvidence[variantId] = {
|
|
1709
|
+
anchors: anchors.map((a) => ({
|
|
1710
|
+
type: a.type,
|
|
1711
|
+
value: a.value,
|
|
1712
|
+
context: a.context
|
|
1713
|
+
})),
|
|
1714
|
+
verified
|
|
1715
|
+
};
|
|
1716
|
+
if (!verified) {
|
|
1717
|
+
unverifiedNegativeClaimCount++;
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
const suggestedImprovements = [];
|
|
1722
|
+
const failedCount = candidates.filter((c) => !c.success).length;
|
|
1723
|
+
if (failedCount > 0) {
|
|
1724
|
+
suggestedImprovements.push(`${failedCount} variant(s) failed execution - investigate errors`);
|
|
1725
|
+
}
|
|
1726
|
+
if (wasTie) {
|
|
1727
|
+
suggestedImprovements.push("Consider refining task requirements to reduce ties");
|
|
1728
|
+
}
|
|
1729
|
+
let baseConfidence = noWinnerReason ? 0 : wasTie ? 60 : 100;
|
|
1730
|
+
if (unverifiedNegativeClaimCount > 0) {
|
|
1731
|
+
const penalty = Math.min(0.25, unverifiedNegativeClaimCount * 0.05);
|
|
1732
|
+
baseConfidence = Math.max(0, baseConfidence * (1 - penalty));
|
|
1733
|
+
}
|
|
1734
|
+
return {
|
|
1735
|
+
winnerId,
|
|
1736
|
+
scores,
|
|
1737
|
+
scoreBreakdown,
|
|
1738
|
+
// P1 Fix: Include detailed score breakdown with deduction traces
|
|
1739
|
+
candidateAnalysis,
|
|
1740
|
+
selectionRationale: {
|
|
1741
|
+
primary: primaryReason,
|
|
1742
|
+
keyFactors,
|
|
1743
|
+
confidence: baseConfidence,
|
|
1744
|
+
evidence: selectionEvidence.length > 0 ? selectionEvidence : void 0
|
|
1745
|
+
},
|
|
1746
|
+
rejectionReasons,
|
|
1747
|
+
rejectionReasonsEvidence: Object.keys(rejectionReasonsEvidence).length > 0 ? rejectionReasonsEvidence : void 0,
|
|
1748
|
+
suggestedImprovements,
|
|
1749
|
+
unverifiedNegativeClaimCount: unverifiedNegativeClaimCount > 0 ? unverifiedNegativeClaimCount : void 0
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
function buildCompetitionBundle(taskId, candidates, basicResult) {
|
|
1753
|
+
const lines = [];
|
|
1754
|
+
lines.push("# Competition Bundle");
|
|
1755
|
+
lines.push("");
|
|
1756
|
+
lines.push(`Task ID: ${taskId}`);
|
|
1757
|
+
lines.push("");
|
|
1758
|
+
for (const candidate of candidates) {
|
|
1759
|
+
const provider = candidate.variant.provider;
|
|
1760
|
+
const model = candidate.variant.model;
|
|
1761
|
+
const strategy = candidate.variant.strategy;
|
|
1762
|
+
const header = [provider, model, strategy].filter(Boolean).join(" / ");
|
|
1763
|
+
const result = matchVariantResult(candidate.variant, basicResult.variants);
|
|
1764
|
+
lines.push(`## ${header || provider}`);
|
|
1765
|
+
lines.push("");
|
|
1766
|
+
lines.push(`- Success: ${candidate.success ? "yes" : "no"}`);
|
|
1767
|
+
lines.push(`- Score: ${candidate.score ?? 0}`);
|
|
1768
|
+
lines.push(`- Cost: $${candidate.cost.toFixed(4)}`);
|
|
1769
|
+
lines.push(`- Duration: ${(candidate.durationMs / 1e3).toFixed(1)}s`);
|
|
1770
|
+
if (candidate.error) {
|
|
1771
|
+
lines.push(`- Error: ${candidate.error}`);
|
|
1772
|
+
}
|
|
1773
|
+
const diff = result?.worktreeDiff;
|
|
1774
|
+
if (typeof diff === "string" && diff.trim().length > 0) {
|
|
1775
|
+
lines.push("");
|
|
1776
|
+
lines.push("```diff");
|
|
1777
|
+
lines.push(diff.trimEnd());
|
|
1778
|
+
lines.push("```");
|
|
1779
|
+
} else {
|
|
1780
|
+
lines.push("");
|
|
1781
|
+
lines.push("_No diff captured._");
|
|
1782
|
+
}
|
|
1783
|
+
lines.push("");
|
|
1784
|
+
}
|
|
1785
|
+
return lines.join("\n");
|
|
1786
|
+
}
|
|
1787
|
+
async function executeCompetitionStage(ctx) {
|
|
1788
|
+
const { stage, artifactStore, options } = ctx;
|
|
1789
|
+
const securityBoundary = ctx.securityBoundary ?? createSecurityBoundary(artifactStore.getWorkflowId());
|
|
1790
|
+
const startTime = Date.now();
|
|
1791
|
+
const config = stage.competition;
|
|
1792
|
+
if (!config || !config.variants || config.variants.length === 0) {
|
|
1793
|
+
throw new Error(`Stage '${stage.id}' is type=competition but has no variants configured`);
|
|
1794
|
+
}
|
|
1795
|
+
if (options.verbose) {
|
|
1796
|
+
console.log(chalk.blue(`
|
|
1797
|
+
Competition Stage: ${stage.id}`));
|
|
1798
|
+
console.log(chalk.gray(` Variants: ${config.variants.length}`));
|
|
1799
|
+
console.log(chalk.gray(` Providers: ${config.variants.map((v) => v.provider).join(", ")}`));
|
|
1800
|
+
}
|
|
1801
|
+
let resolvedPrompt = stage.prompt ?? "";
|
|
1802
|
+
try {
|
|
1803
|
+
resolvedPrompt = await resolvePromptArtifacts(
|
|
1804
|
+
stage.prompt ?? "",
|
|
1805
|
+
stage.inputs,
|
|
1806
|
+
artifactStore,
|
|
1807
|
+
stage.id,
|
|
1808
|
+
securityBoundary
|
|
1809
|
+
);
|
|
1810
|
+
} catch (error) {
|
|
1811
|
+
if (error instanceof ArtifactNotFoundError) {
|
|
1812
|
+
const result = {
|
|
1813
|
+
stageId: stage.id,
|
|
1814
|
+
stageType: "competition",
|
|
1815
|
+
validationPassed: false,
|
|
1816
|
+
cost: 0,
|
|
1817
|
+
candidates: [],
|
|
1818
|
+
winner: null,
|
|
1819
|
+
summary: `Failed to resolve input artifacts: ${error.message}`,
|
|
1820
|
+
durationMs: Date.now() - startTime
|
|
1821
|
+
};
|
|
1822
|
+
return result;
|
|
1823
|
+
}
|
|
1824
|
+
throw error;
|
|
1825
|
+
}
|
|
1826
|
+
if (options.verbose) {
|
|
1827
|
+
console.log(chalk.gray(` Prompt length: ${resolvedPrompt.length} chars`));
|
|
1828
|
+
}
|
|
1829
|
+
const effectiveMode = options.allowlistMode ?? "warn";
|
|
1830
|
+
const expectedAllowlistForSkip = computeExpectedAllowlist(stage);
|
|
1831
|
+
const requireChangesDemandsEdits = stage.validation?.requireChanges === true && stage.allowEmptyResults !== true;
|
|
1832
|
+
if (!requireChangesDemandsEdits && stageHasDeterministicChecks(stage) && typeof options.workerCwd === "string" && options.workerCwd.length > 0) {
|
|
1833
|
+
try {
|
|
1834
|
+
const skipProof = await evaluateStageCompletionProof({
|
|
1835
|
+
stage,
|
|
1836
|
+
worktreePath: options.workerCwd,
|
|
1837
|
+
stdout: "",
|
|
1838
|
+
attemptChangedFiles: [],
|
|
1839
|
+
allowlist: expectedAllowlistForSkip,
|
|
1840
|
+
stageId: stage.id
|
|
1841
|
+
});
|
|
1842
|
+
const alreadySatisfied = skipProof.contractsSatisfied && skipProof.hasHostSurface && skipProof.mayAcceptOutcome;
|
|
1843
|
+
if (alreadySatisfied) {
|
|
1844
|
+
const driftContext = computeCompetitionDrift([], expectedAllowlistForSkip, effectiveMode);
|
|
1845
|
+
const coherenceMetrics = computeCoherenceMetrics(
|
|
1846
|
+
[],
|
|
1847
|
+
DEFAULT_COHERENCE_THRESHOLD,
|
|
1848
|
+
expectedAllowlistForSkip
|
|
1849
|
+
);
|
|
1850
|
+
try {
|
|
1851
|
+
await artifactStore.save(stage.id, "stage-change", "json", {
|
|
1852
|
+
stageId: stage.id,
|
|
1853
|
+
stageType: "competition",
|
|
1854
|
+
mode: effectiveMode,
|
|
1855
|
+
deliveredFiles: driftContext.deliveredFiles,
|
|
1856
|
+
expectedFiles: driftContext.expectedFiles,
|
|
1857
|
+
violations: driftContext.violations,
|
|
1858
|
+
hasDrift: driftContext.hasDrift,
|
|
1859
|
+
candidateCount: 0,
|
|
1860
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1861
|
+
skipped: true,
|
|
1862
|
+
reason: "already-satisfied"
|
|
1863
|
+
});
|
|
1864
|
+
await artifactStore.save(
|
|
1865
|
+
stage.id,
|
|
1866
|
+
"stage-change-summary",
|
|
1867
|
+
"text",
|
|
1868
|
+
`${driftContext.summary}
|
|
1869
|
+
|
|
1870
|
+
Skipped: stage already satisfied`
|
|
1871
|
+
);
|
|
1872
|
+
const rationalePacket = {
|
|
1873
|
+
winnerId: "none",
|
|
1874
|
+
scores: {},
|
|
1875
|
+
candidateAnalysis: [],
|
|
1876
|
+
selectionRationale: {
|
|
1877
|
+
primary: "Competition skipped: stage already satisfied by deterministic checks",
|
|
1878
|
+
keyFactors: [
|
|
1879
|
+
"deterministic validation checks passed",
|
|
1880
|
+
"validation.requireChanges=false",
|
|
1881
|
+
"no variants executed"
|
|
1882
|
+
],
|
|
1883
|
+
confidence: 100
|
|
1884
|
+
},
|
|
1885
|
+
rejectionReasons: {},
|
|
1886
|
+
suggestedImprovements: []
|
|
1887
|
+
};
|
|
1888
|
+
await artifactStore.save(stage.id, "judgeRationale", "json", rationalePacket);
|
|
1889
|
+
await artifactStore.save(stage.id, "winnerDiff", "diff", "");
|
|
1890
|
+
} catch {
|
|
1891
|
+
}
|
|
1892
|
+
return {
|
|
1893
|
+
stageId: stage.id,
|
|
1894
|
+
stageType: "competition",
|
|
1895
|
+
validationPassed: true,
|
|
1896
|
+
validationScore: 100,
|
|
1897
|
+
cost: 0,
|
|
1898
|
+
summary: "Competition skipped: stage already satisfied (idempotent)",
|
|
1899
|
+
durationMs: Date.now() - startTime,
|
|
1900
|
+
candidates: [],
|
|
1901
|
+
winner: null,
|
|
1902
|
+
winnerApplied: false,
|
|
1903
|
+
coherenceMetrics,
|
|
1904
|
+
markedIncomparable: false,
|
|
1905
|
+
scoringMode: "deterministic",
|
|
1906
|
+
competitionJudgeResult: {
|
|
1907
|
+
judgeType: config.judgeConfig?.type ?? "ai",
|
|
1908
|
+
aiJudgeAttempted: false,
|
|
1909
|
+
aiJudgeInvoked: false,
|
|
1910
|
+
aiJudgeError: void 0,
|
|
1911
|
+
judgeInvocationReason: "deterministic-shortcut",
|
|
1912
|
+
rankings: [],
|
|
1913
|
+
wasTie: false
|
|
1914
|
+
},
|
|
1915
|
+
driftContext,
|
|
1916
|
+
...skipProof.evidence ? { completionEvidence: skipProof.evidence } : {}
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
} catch {
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
const executionIntent = resolveCompetitionExecutionIntent(stage);
|
|
1923
|
+
const variantConfigs = config.variants.map(
|
|
1924
|
+
(spec) => variantSpecToConfig(
|
|
1925
|
+
spec,
|
|
1926
|
+
executionIntent,
|
|
1927
|
+
stage,
|
|
1928
|
+
options.providerExecutionTransport,
|
|
1929
|
+
config.unknownStrategyPolicy
|
|
1930
|
+
)
|
|
1931
|
+
);
|
|
1932
|
+
const allowDuplicateVariantSpecs = config.allowDuplicateVariantSpecs ?? config.allowDuplicateStrategies;
|
|
1933
|
+
if (config.allowDuplicateVariantSpecs !== void 0 && config.allowDuplicateStrategies !== void 0 && config.allowDuplicateVariantSpecs !== config.allowDuplicateStrategies) {
|
|
1934
|
+
throw new Error(
|
|
1935
|
+
`Invalid competition config for stage '${stage.id}': \`competition.allowDuplicateVariantSpecs\` and \`competition.allowDuplicateStrategies\` are both set but differ. Use \`competition.allowDuplicateVariantSpecs\` and remove the deprecated \`competition.allowDuplicateStrategies\`.`
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
assertNoDuplicateVariantSpecs(variantConfigs, {
|
|
1939
|
+
allowDuplicates: allowDuplicateVariantSpecs
|
|
1940
|
+
});
|
|
1941
|
+
const taskId = generateCompetitionId();
|
|
1942
|
+
const flywheelProjectRoot = getProjectRoot();
|
|
1943
|
+
const competitionOptions = {
|
|
1944
|
+
abortSignal: options.abortSignal,
|
|
1945
|
+
workerCwd: options.workerCwd,
|
|
1946
|
+
verbose: options.verbose,
|
|
1947
|
+
maxConcurrentVariants: options.maxConcurrentVariants,
|
|
1948
|
+
perVariantTimeoutMinutes: options.perVariantTimeoutMinutes,
|
|
1949
|
+
timeoutMinutes: options.timeoutMinutes,
|
|
1950
|
+
// Flywheel never consumes basic-competition synthesis (candidate gates / judge /
|
|
1951
|
+
// apply use variant results only). Always disable synthesis at this boundary so
|
|
1952
|
+
// agentic synthesis compute is not spent on discarded product. (Candidate gates
|
|
1953
|
+
// also run after Basic Competition returns, so early synthesis cannot see that
|
|
1954
|
+
// evidence and can emit misleading "0 eligible variants" warnings.)
|
|
1955
|
+
synthesize: false,
|
|
1956
|
+
deferEvaluationHandleFinalization: true,
|
|
1957
|
+
// Preserve worktrees only when needed for post-processing (e.g. candidateGate commands).
|
|
1958
|
+
// Winner application in flywheel-executor prefers `worktreeDiff` and does not require retained worktrees.
|
|
1959
|
+
preserveWorktrees: config.preserveCandidates ?? Boolean(config.candidateGate),
|
|
1960
|
+
executionContext: createExecutionContext({
|
|
1961
|
+
repoRoot: flywheelProjectRoot,
|
|
1962
|
+
poeticDir: path.join(flywheelProjectRoot, ".poetic"),
|
|
1963
|
+
taskId,
|
|
1964
|
+
envOverrides: config.preserveCandidates ?? Boolean(config.candidateGate) ? {
|
|
1965
|
+
POETIC_PRESERVE_WORKTREES: "1",
|
|
1966
|
+
POETIC_RETAIN_BASIC_WORKTREE: "1"
|
|
1967
|
+
} : {}
|
|
1968
|
+
})
|
|
1969
|
+
};
|
|
1970
|
+
let basicResult;
|
|
1971
|
+
try {
|
|
1972
|
+
basicResult = await runBasicCompetition(
|
|
1973
|
+
taskId,
|
|
1974
|
+
resolvedPrompt,
|
|
1975
|
+
variantConfigs,
|
|
1976
|
+
competitionOptions
|
|
1977
|
+
);
|
|
1978
|
+
} catch (error) {
|
|
1979
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1980
|
+
await finalizeEvaluationHandleAsync(
|
|
1981
|
+
taskId,
|
|
1982
|
+
createEvaluationHandleFinalState({
|
|
1983
|
+
outcome: "error",
|
|
1984
|
+
winner: null,
|
|
1985
|
+
errorMessage: errorMsg
|
|
1986
|
+
})
|
|
1987
|
+
);
|
|
1988
|
+
const result = {
|
|
1989
|
+
stageId: stage.id,
|
|
1990
|
+
stageType: "competition",
|
|
1991
|
+
validationPassed: false,
|
|
1992
|
+
cost: 0,
|
|
1993
|
+
candidates: [],
|
|
1994
|
+
winner: null,
|
|
1995
|
+
summary: `Competition execution failed: ${errorMsg}`,
|
|
1996
|
+
durationMs: Date.now() - startTime,
|
|
1997
|
+
competitionJudgeResult: {
|
|
1998
|
+
judgeType: config.judgeConfig?.type ?? "ai",
|
|
1999
|
+
aiJudgeAttempted: false,
|
|
2000
|
+
aiJudgeInvoked: false,
|
|
2001
|
+
aiJudgeError: errorMsg,
|
|
2002
|
+
judgeInvocationReason: "error",
|
|
2003
|
+
rankings: [],
|
|
2004
|
+
wasTie: false,
|
|
2005
|
+
noWinnerReason: "judge-error"
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
return result;
|
|
2009
|
+
}
|
|
2010
|
+
let deferredHandleFinalized = false;
|
|
2011
|
+
const finalizeDeferredHandle = async (state) => {
|
|
2012
|
+
let finalizeResult = await finalizeEvaluationHandleAsync(taskId, state);
|
|
2013
|
+
if (finalizeResult.kind === "not_terminal") {
|
|
2014
|
+
await Promise.all(
|
|
2015
|
+
basicResult.variants.map(
|
|
2016
|
+
(variant) => updateEvaluationHandleWithResultAsync(taskId, variant)
|
|
2017
|
+
)
|
|
2018
|
+
);
|
|
2019
|
+
finalizeResult = await finalizeEvaluationHandleAsync(taskId, state);
|
|
2020
|
+
}
|
|
2021
|
+
if (finalizeResult.kind !== "absent" && !isDurableHandleCompletion(finalizeResult, state.status)) {
|
|
2022
|
+
throw new Error(
|
|
2023
|
+
`Evaluation handle did not reach durable ${state.status} state (kind=${finalizeResult.kind})`
|
|
2024
|
+
);
|
|
2025
|
+
}
|
|
2026
|
+
deferredHandleFinalized = true;
|
|
2027
|
+
};
|
|
2028
|
+
try {
|
|
2029
|
+
const basicInterruption = resolveBasicCompetitionInterruption(basicResult);
|
|
2030
|
+
if (basicInterruption) {
|
|
2031
|
+
const interruptedCandidates = config.variants.map(
|
|
2032
|
+
(spec) => variantResultToCandidate(spec, matchVariantResult(spec, basicResult.variants))
|
|
2033
|
+
);
|
|
2034
|
+
const { cost, costUnavailableReason: costUnavailableReason2 } = resolveCompetitionCostAggregate(interruptedCandidates);
|
|
2035
|
+
const timedOut = basicInterruption.kind === "timed_out";
|
|
2036
|
+
await finalizeDeferredHandle(
|
|
2037
|
+
timedOut ? createEvaluationHandleFinalState({
|
|
2038
|
+
outcome: "timed_out",
|
|
2039
|
+
winner: null,
|
|
2040
|
+
errorMessage: `Competition timed out after ${basicInterruption.timeout.timeoutMs}ms`
|
|
2041
|
+
}) : createEvaluationHandleFinalState({ outcome: "no_winner", winner: null })
|
|
2042
|
+
);
|
|
2043
|
+
await cleanupSynthesisInputPatches(basicResult.variants, {
|
|
2044
|
+
expectedRoot: resolveSynthesisInputPatchDir(
|
|
2045
|
+
competitionOptions.executionContext.poeticDir,
|
|
2046
|
+
taskId
|
|
2047
|
+
)
|
|
2048
|
+
});
|
|
2049
|
+
return {
|
|
2050
|
+
stageId: stage.id,
|
|
2051
|
+
stageType: "competition",
|
|
2052
|
+
validationPassed: false,
|
|
2053
|
+
cost,
|
|
2054
|
+
costUnavailableReason: costUnavailableReason2,
|
|
2055
|
+
candidates: interruptedCandidates,
|
|
2056
|
+
winner: null,
|
|
2057
|
+
summary: timedOut ? "Competition timed out; no winner selected" : `Competition canceled by ${basicInterruption.kind === "canceled" ? basicInterruption.signal : "unknown signal"}; no winner selected`,
|
|
2058
|
+
durationMs: Date.now() - startTime,
|
|
2059
|
+
competitionJudgeResult: {
|
|
2060
|
+
judgeType: config.judgeConfig?.type ?? "ai",
|
|
2061
|
+
aiJudgeAttempted: false,
|
|
2062
|
+
aiJudgeInvoked: false,
|
|
2063
|
+
judgeInvocationReason: timedOut ? "error" : "canceled",
|
|
2064
|
+
rankings: [],
|
|
2065
|
+
wasTie: false,
|
|
2066
|
+
noWinnerReason: timedOut ? "judge-error" : "canceled"
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
let aiJudgeAttempted = false;
|
|
2071
|
+
let aiJudgeInvoked = false;
|
|
2072
|
+
let judgedWinner = null;
|
|
2073
|
+
let aiJudgeError;
|
|
2074
|
+
let latestJudgeEscalation;
|
|
2075
|
+
let latestMainJudgeResult;
|
|
2076
|
+
let latestTiebreakJudgeResult;
|
|
2077
|
+
let matrixDefaultWinnerSource = "unknown";
|
|
2078
|
+
let eligibleVariantResultsForMatrix = [];
|
|
2079
|
+
let matrixRan = false;
|
|
2080
|
+
let matrixProfileAgreement;
|
|
2081
|
+
let effectiveMatrixAuthority;
|
|
2082
|
+
const matrixAuthorityWarnings = [];
|
|
2083
|
+
const matrixAuthorityNonSelectionReasons = [];
|
|
2084
|
+
const candidates = await Promise.all(
|
|
2085
|
+
config.variants.map(async (spec) => {
|
|
2086
|
+
const matchingResult = matchVariantResult(spec, basicResult.variants);
|
|
2087
|
+
const candidate = variantResultToCandidate(spec, matchingResult);
|
|
2088
|
+
if (candidate.success) return candidate;
|
|
2089
|
+
if (!isNoChangesDetectedError(candidate.error)) return candidate;
|
|
2090
|
+
if (requireChangesDemandsEdits) {
|
|
2091
|
+
return candidate;
|
|
2092
|
+
}
|
|
2093
|
+
if (!stageHasDeterministicChecks(stage)) return candidate;
|
|
2094
|
+
if (!candidate.worktreePath) return candidate;
|
|
2095
|
+
const stdout = getStringAtPath(matchingResult, ["result", "stdout"]) ?? "";
|
|
2096
|
+
const canAcceptNoop = await validateWorktreeAgainstStageChecks(
|
|
2097
|
+
stage,
|
|
2098
|
+
candidate.worktreePath,
|
|
2099
|
+
stdout,
|
|
2100
|
+
{
|
|
2101
|
+
attemptChangedFiles: candidate.changedFiles ?? [],
|
|
2102
|
+
allowlist: expectedAllowlistForSkip
|
|
2103
|
+
}
|
|
2104
|
+
);
|
|
2105
|
+
if (!canAcceptNoop) return candidate;
|
|
2106
|
+
return {
|
|
2107
|
+
...candidate,
|
|
2108
|
+
success: true,
|
|
2109
|
+
error: void 0,
|
|
2110
|
+
score: candidate.score ?? 0
|
|
2111
|
+
};
|
|
2112
|
+
})
|
|
2113
|
+
);
|
|
2114
|
+
const finishedExecutionKeys = new Set(
|
|
2115
|
+
candidates.filter((c) => c.success).map((c) => variantIdForSpec(c.variant))
|
|
2116
|
+
);
|
|
2117
|
+
if (stage.validation?.requireChanges === true && stage.allowEmptyResults !== true) {
|
|
2118
|
+
for (let idx = 0; idx < candidates.length; idx++) {
|
|
2119
|
+
const candidate = candidates[idx];
|
|
2120
|
+
if (!candidate?.success || !candidateHasConcreteZeroChanges(candidate)) continue;
|
|
2121
|
+
candidates[idx] = {
|
|
2122
|
+
...candidate,
|
|
2123
|
+
success: false,
|
|
2124
|
+
error: "Candidate produced no applicable changes but validation.requireChanges is enabled"
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
await hydrateCandidateCostsFromTelemetry(taskId, candidates, stage.id, options.verbose);
|
|
2129
|
+
const verificationPolicy = config.verificationPolicy ?? "findings";
|
|
2130
|
+
const candidatesWithTestFindings = [];
|
|
2131
|
+
for (let idx = 0; idx < candidates.length; idx++) {
|
|
2132
|
+
const candidate = candidates[idx];
|
|
2133
|
+
if (!candidate) continue;
|
|
2134
|
+
if (candidate.success && candidate.testsExecuted && candidate.testStatus && candidate.testStatus !== "passed" && candidate.testStatus !== "not_run") {
|
|
2135
|
+
const variantId = `${candidate.variant.provider}:${candidate.variant.model ?? ""}:${candidate.variant.strategy ?? ""}`;
|
|
2136
|
+
const testScope = candidate.testsExecuted.scope ?? "unknown";
|
|
2137
|
+
const exitCode = candidate.testsExecuted.exitCode ?? 1;
|
|
2138
|
+
const testLabel = `touched tests (scope: ${testScope})`;
|
|
2139
|
+
const verificationUnavailable = candidate.testStatus === "unavailable";
|
|
2140
|
+
const finding = {
|
|
2141
|
+
kind: "test",
|
|
2142
|
+
command: testLabel,
|
|
2143
|
+
exitCode,
|
|
2144
|
+
severity: verificationUnavailable ? "warning" : "error",
|
|
2145
|
+
recommendedNextStep: verificationUnavailable ? `Install or enable test tooling for scope: ${testScope}` : `Fix failing tests in scope: ${testScope}`
|
|
2146
|
+
};
|
|
2147
|
+
candidate.verification = {
|
|
2148
|
+
passed: false,
|
|
2149
|
+
findings: [finding]
|
|
2150
|
+
};
|
|
2151
|
+
if (verificationPolicy === "blocking") {
|
|
2152
|
+
candidatesWithTestFindings.push(
|
|
2153
|
+
`${variantId} (${verificationUnavailable ? "verification unavailable" : "disqualified"})`
|
|
2154
|
+
);
|
|
2155
|
+
candidates[idx] = {
|
|
2156
|
+
...candidate,
|
|
2157
|
+
success: false,
|
|
2158
|
+
error: verificationUnavailable ? `Candidate gate unavailable: touched tests unavailable (scope: ${testScope})` : `Candidate gate failed: touched tests ${candidate.testStatus} (scope: ${testScope})`
|
|
2159
|
+
};
|
|
2160
|
+
} else {
|
|
2161
|
+
candidatesWithTestFindings.push(`${variantId} (findings recorded)`);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
if (candidatesWithTestFindings.length > 0 && options.verbose) {
|
|
2166
|
+
const mode = verificationPolicy === "blocking" ? "disqualified" : "recorded findings for";
|
|
2167
|
+
console.log(
|
|
2168
|
+
chalk.yellow(
|
|
2169
|
+
` ${candidatesWithTestFindings.length} candidate(s) ${mode}: ${candidatesWithTestFindings.join(", ")}`
|
|
2170
|
+
)
|
|
2171
|
+
);
|
|
2172
|
+
}
|
|
2173
|
+
if (config.candidateGate) {
|
|
2174
|
+
const gate = config.candidateGate;
|
|
2175
|
+
const gateResults = [];
|
|
2176
|
+
const gatedCandidates = await Promise.all(
|
|
2177
|
+
candidates.map(async (candidate) => {
|
|
2178
|
+
if (!candidate.success) {
|
|
2179
|
+
gateResults.push({
|
|
2180
|
+
provider: candidate.variant.provider,
|
|
2181
|
+
model: candidate.variant.model,
|
|
2182
|
+
strategy: candidate.variant.strategy,
|
|
2183
|
+
worktreePath: candidate.worktreePath,
|
|
2184
|
+
ran: false,
|
|
2185
|
+
passed: false,
|
|
2186
|
+
error: "Candidate did not execute successfully (gate not run)",
|
|
2187
|
+
commandResults: []
|
|
2188
|
+
});
|
|
2189
|
+
return candidate;
|
|
2190
|
+
}
|
|
2191
|
+
if (!candidate.worktreePath) {
|
|
2192
|
+
const msg = "Candidate gate requires a retained worktreePath but none was provided";
|
|
2193
|
+
gateResults.push({
|
|
2194
|
+
provider: candidate.variant.provider,
|
|
2195
|
+
model: candidate.variant.model,
|
|
2196
|
+
strategy: candidate.variant.strategy,
|
|
2197
|
+
worktreePath: candidate.worktreePath,
|
|
2198
|
+
ran: false,
|
|
2199
|
+
passed: false,
|
|
2200
|
+
error: msg,
|
|
2201
|
+
commandResults: []
|
|
2202
|
+
});
|
|
2203
|
+
return { ...candidate, success: false, error: `Candidate gate failed: ${msg}` };
|
|
2204
|
+
}
|
|
2205
|
+
const findings = [
|
|
2206
|
+
...candidate.verification?.findings ?? []
|
|
2207
|
+
];
|
|
2208
|
+
const renderedCommands = gate.commands.map(
|
|
2209
|
+
(command) => renderCandidateGateCommand(command, candidate)
|
|
2210
|
+
);
|
|
2211
|
+
const verifyResult = await runVerifyCommands({
|
|
2212
|
+
cwd: candidate.worktreePath,
|
|
2213
|
+
commands: renderedCommands,
|
|
2214
|
+
commandProvenance: "candidate-gate-config",
|
|
2215
|
+
timeoutMs: CANDIDATE_GATE_COMMAND_TIMEOUT_MS
|
|
2216
|
+
});
|
|
2217
|
+
const commandResults = verifyResult.results;
|
|
2218
|
+
const gatePassed = verifyResult.passed;
|
|
2219
|
+
let gateError;
|
|
2220
|
+
const failedCommand = commandResults.find((result2) => result2.exitCode !== 0);
|
|
2221
|
+
if (failedCommand) {
|
|
2222
|
+
gateError = `Verify command failed (exit ${failedCommand.exitCode}): ${failedCommand.command}`;
|
|
2223
|
+
findings.push({
|
|
2224
|
+
kind: "gate-command",
|
|
2225
|
+
command: failedCommand.command,
|
|
2226
|
+
exitCode: failedCommand.exitCode,
|
|
2227
|
+
outputTail: failedCommand.outputTail ?? failedCommand.stderrTail ?? failedCommand.stdoutTail,
|
|
2228
|
+
severity: "error",
|
|
2229
|
+
recommendedNextStep: `Fix gate command failure: ${failedCommand.command}`
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
gateResults.push({
|
|
2233
|
+
provider: candidate.variant.provider,
|
|
2234
|
+
model: candidate.variant.model,
|
|
2235
|
+
strategy: candidate.variant.strategy,
|
|
2236
|
+
worktreePath: candidate.worktreePath,
|
|
2237
|
+
ran: true,
|
|
2238
|
+
passed: gatePassed,
|
|
2239
|
+
error: gateError,
|
|
2240
|
+
commandResults
|
|
2241
|
+
});
|
|
2242
|
+
if (!gatePassed) {
|
|
2243
|
+
candidate.verification = {
|
|
2244
|
+
passed: false,
|
|
2245
|
+
findings
|
|
2246
|
+
};
|
|
2247
|
+
if (verificationPolicy === "blocking") {
|
|
2248
|
+
return { ...candidate, success: false, error: `Candidate gate failed: ${gateError}` };
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return candidate;
|
|
2252
|
+
})
|
|
2253
|
+
);
|
|
2254
|
+
candidates.splice(0, candidates.length, ...gatedCandidates);
|
|
2255
|
+
try {
|
|
2256
|
+
await artifactStore.save(stage.id, "candidate-gates", "json", {
|
|
2257
|
+
taskId,
|
|
2258
|
+
stageId: stage.id,
|
|
2259
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2260
|
+
commands: gate.commands,
|
|
2261
|
+
candidateCount: candidates.length,
|
|
2262
|
+
passedCount: gateResults.filter((r) => r.passed).length,
|
|
2263
|
+
results: gateResults
|
|
2264
|
+
});
|
|
2265
|
+
} catch (error) {
|
|
2266
|
+
if (options.verbose) {
|
|
2267
|
+
console.warn(
|
|
2268
|
+
chalk.yellow(` Warning: Failed to persist candidate gate artifacts: ${error}`)
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
const coverageConfig = config.candidateGate?.coverage;
|
|
2274
|
+
let usedCoverageScoring = false;
|
|
2275
|
+
let coverageDataAvailable = false;
|
|
2276
|
+
if (coverageConfig && Array.isArray(coverageConfig.targets) && coverageConfig.targets.length > 0) {
|
|
2277
|
+
const summaryPath = coverageConfig.summaryPath ?? "coverage/coverage-summary.json";
|
|
2278
|
+
const threshold = coverageConfig.threshold;
|
|
2279
|
+
const coverageMode = coverageConfig.mode ?? "absolute";
|
|
2280
|
+
const minDeltaPct = coverageConfig.minDeltaPct ?? 15;
|
|
2281
|
+
const largeFileLineThreshold = coverageConfig.largeFileLineThreshold ?? 300;
|
|
2282
|
+
const baselineSummary = typeof options.workerCwd === "string" && options.workerCwd.length > 0 ? await loadCoverageSummaryJson(options.workerCwd, summaryPath) : null;
|
|
2283
|
+
const baselineStats = computeCoverageStatsForTargets(baselineSummary, coverageConfig.targets);
|
|
2284
|
+
const baselineFromPrompt = parseBaselineLinesPctFromPrompt(resolvedPrompt);
|
|
2285
|
+
const effectiveBaselineAvgPct = baselineStats.avgPct ?? baselineFromPrompt;
|
|
2286
|
+
const perCandidateCoverage = [];
|
|
2287
|
+
for (let idx = 0; idx < candidates.length; idx++) {
|
|
2288
|
+
const candidate = candidates[idx];
|
|
2289
|
+
if (!candidate) continue;
|
|
2290
|
+
const worktreePath = candidate.worktreePath;
|
|
2291
|
+
let avgPct = null;
|
|
2292
|
+
let minPct = null;
|
|
2293
|
+
let maxTargetLines = null;
|
|
2294
|
+
let byTarget = {};
|
|
2295
|
+
let missingTargets = [];
|
|
2296
|
+
let disqualified = false;
|
|
2297
|
+
let disqualifyReason;
|
|
2298
|
+
let deltaAvgPct = null;
|
|
2299
|
+
const baselineAvgPct = effectiveBaselineAvgPct;
|
|
2300
|
+
if (candidate.success) {
|
|
2301
|
+
if (!worktreePath) {
|
|
2302
|
+
byTarget = Object.fromEntries(coverageConfig.targets.map((t) => [t, null]));
|
|
2303
|
+
missingTargets = [...coverageConfig.targets];
|
|
2304
|
+
const hasGateConfig = typeof threshold === "number" || coverageMode === "delta" || coverageMode === "auto";
|
|
2305
|
+
if (hasGateConfig) {
|
|
2306
|
+
disqualified = true;
|
|
2307
|
+
disqualifyReason = "Missing worktreePath required for coverage gate evaluation";
|
|
2308
|
+
}
|
|
2309
|
+
} else {
|
|
2310
|
+
const candidateSummary = await loadCoverageSummaryJson(worktreePath, summaryPath);
|
|
2311
|
+
const stats = computeCoverageStatsForTargets(candidateSummary, coverageConfig.targets);
|
|
2312
|
+
avgPct = stats.avgPct;
|
|
2313
|
+
minPct = stats.minPct;
|
|
2314
|
+
maxTargetLines = stats.maxTargetLines;
|
|
2315
|
+
byTarget = stats.byTarget;
|
|
2316
|
+
missingTargets = stats.missingTargets;
|
|
2317
|
+
deltaAvgPct = typeof avgPct === "number" ? Math.round(
|
|
2318
|
+
(avgPct - (typeof baselineAvgPct === "number" ? baselineAvgPct : 0)) * 100
|
|
2319
|
+
) / 100 : null;
|
|
2320
|
+
let effectiveMode2 = coverageMode;
|
|
2321
|
+
if (coverageMode === "auto" && typeof maxTargetLines === "number") {
|
|
2322
|
+
effectiveMode2 = resolveAutoCoverageMode({
|
|
2323
|
+
maxTargetLines,
|
|
2324
|
+
largeFileLineThreshold,
|
|
2325
|
+
baselineAvgPct,
|
|
2326
|
+
threshold,
|
|
2327
|
+
minDeltaPct
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
if (effectiveMode2 === "absolute" && typeof threshold === "number") {
|
|
2331
|
+
if (missingTargets.length > 0) {
|
|
2332
|
+
disqualified = true;
|
|
2333
|
+
disqualifyReason = `Missing coverage for targets: ${missingTargets.join(", ")}`;
|
|
2334
|
+
} else if (typeof minPct === "number" && minPct < threshold) {
|
|
2335
|
+
disqualified = true;
|
|
2336
|
+
disqualifyReason = `Coverage below threshold (${minPct.toFixed(1)}% < ${threshold}%)`;
|
|
2337
|
+
} else if (minPct === null) {
|
|
2338
|
+
disqualified = true;
|
|
2339
|
+
disqualifyReason = "Coverage data missing (unable to evaluate threshold)";
|
|
2340
|
+
}
|
|
2341
|
+
} else if (effectiveMode2 === "delta") {
|
|
2342
|
+
if (missingTargets.length > 0) {
|
|
2343
|
+
disqualified = true;
|
|
2344
|
+
disqualifyReason = `Missing coverage for targets: ${missingTargets.join(", ")}`;
|
|
2345
|
+
} else if (typeof deltaAvgPct === "number" && deltaAvgPct < minDeltaPct) {
|
|
2346
|
+
disqualified = true;
|
|
2347
|
+
disqualifyReason = `Coverage improvement below minimum (${deltaAvgPct.toFixed(1)}pp < ${minDeltaPct}pp)`;
|
|
2348
|
+
} else if (deltaAvgPct === null) {
|
|
2349
|
+
disqualified = true;
|
|
2350
|
+
disqualifyReason = "Coverage data missing (unable to evaluate delta)";
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
let effectiveCandidate = candidate;
|
|
2356
|
+
if (effectiveCandidate.success && disqualified) {
|
|
2357
|
+
effectiveCandidate = {
|
|
2358
|
+
...effectiveCandidate,
|
|
2359
|
+
success: false,
|
|
2360
|
+
error: `Candidate gate failed: ${disqualifyReason ?? "coverage threshold"}`
|
|
2361
|
+
};
|
|
2362
|
+
candidates[idx] = effectiveCandidate;
|
|
2363
|
+
}
|
|
2364
|
+
if (effectiveCandidate.success && typeof avgPct === "number") {
|
|
2365
|
+
effectiveCandidate = { ...effectiveCandidate, score: avgPct };
|
|
2366
|
+
candidates[idx] = effectiveCandidate;
|
|
2367
|
+
coverageDataAvailable = true;
|
|
2368
|
+
}
|
|
2369
|
+
perCandidateCoverage.push({
|
|
2370
|
+
provider: effectiveCandidate.variant.provider,
|
|
2371
|
+
model: effectiveCandidate.variant.model,
|
|
2372
|
+
strategy: effectiveCandidate.variant.strategy,
|
|
2373
|
+
worktreePath,
|
|
2374
|
+
success: effectiveCandidate.success,
|
|
2375
|
+
avgPct,
|
|
2376
|
+
minPct,
|
|
2377
|
+
maxTargetLines,
|
|
2378
|
+
baselineAvgPct,
|
|
2379
|
+
deltaAvgPct,
|
|
2380
|
+
byTarget,
|
|
2381
|
+
missingTargets,
|
|
2382
|
+
disqualified: disqualified || void 0,
|
|
2383
|
+
disqualifyReason
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
try {
|
|
2387
|
+
await artifactStore.save(stage.id, "candidate-coverage", "json", {
|
|
2388
|
+
taskId,
|
|
2389
|
+
stageId: stage.id,
|
|
2390
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2391
|
+
summaryPath,
|
|
2392
|
+
gateConfig: {
|
|
2393
|
+
mode: coverageMode,
|
|
2394
|
+
threshold,
|
|
2395
|
+
minDeltaPct,
|
|
2396
|
+
largeFileLineThreshold
|
|
2397
|
+
},
|
|
2398
|
+
targets: coverageConfig.targets,
|
|
2399
|
+
baseline: {
|
|
2400
|
+
avgPct: effectiveBaselineAvgPct,
|
|
2401
|
+
minPct: baselineStats.minPct ?? baselineFromPrompt,
|
|
2402
|
+
totalLines: baselineStats.totalLines,
|
|
2403
|
+
maxTargetLines: baselineStats.maxTargetLines,
|
|
2404
|
+
byTarget: baselineStats.byTarget,
|
|
2405
|
+
missingTargets: baselineStats.missingTargets
|
|
2406
|
+
},
|
|
2407
|
+
candidates: perCandidateCoverage
|
|
2408
|
+
});
|
|
2409
|
+
} catch (error) {
|
|
2410
|
+
if (options.verbose) {
|
|
2411
|
+
console.warn(
|
|
2412
|
+
chalk.yellow(` Warning: Failed to persist candidate coverage artifacts: ${error}`)
|
|
2413
|
+
);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
usedCoverageScoring = coverageDataAvailable;
|
|
2417
|
+
}
|
|
2418
|
+
recordDeterministicTestSignalObservation(candidates, options.verbose);
|
|
2419
|
+
const expectedAllowlist = computeExpectedAllowlist(stage);
|
|
2420
|
+
const { cost: totalCost, costUnavailableReason } = resolveCompetitionCostAggregate(candidates);
|
|
2421
|
+
const finishedCandidates = candidates.filter(
|
|
2422
|
+
(c) => finishedExecutionKeys.has(variantIdForSpec(c.variant))
|
|
2423
|
+
);
|
|
2424
|
+
const shouldInvokeAiJudgeForFinished = finishedCandidates.length >= 2 && config.judgeConfig?.disableAiJudge !== true;
|
|
2425
|
+
const allCandidatesDisqualified = candidates.every((c) => !c.success);
|
|
2426
|
+
if (allCandidatesDisqualified && verificationPolicy === "blocking" && !shouldInvokeAiJudgeForFinished) {
|
|
2427
|
+
let disqualificationSummary = "Competition failed: All candidates disqualified by verification gates";
|
|
2428
|
+
const testGateUnavailable = candidates.filter(
|
|
2429
|
+
(c) => c.error?.includes("touched tests unavailable")
|
|
2430
|
+
);
|
|
2431
|
+
const testGateFailures = candidates.filter(
|
|
2432
|
+
(c) => !c.error?.includes("touched tests unavailable") && (c.error?.includes("touched tests") || c.error?.includes("Candidate gate failed"))
|
|
2433
|
+
);
|
|
2434
|
+
const coverageGateFailures = candidates.filter((c) => c.error?.includes("coverage"));
|
|
2435
|
+
const verifyFailures = candidates.filter(
|
|
2436
|
+
(c) => c.error?.includes("Verify stage failed") || c.error?.includes("verify.commands")
|
|
2437
|
+
);
|
|
2438
|
+
const requireChangesNoops = candidates.filter(
|
|
2439
|
+
(c) => c.error?.includes("validation.requireChanges is enabled")
|
|
2440
|
+
);
|
|
2441
|
+
const rootCauses = [];
|
|
2442
|
+
if (testGateUnavailable.length > 0) {
|
|
2443
|
+
rootCauses.push(
|
|
2444
|
+
`${testGateUnavailable.length} candidate(s) had unavailable deterministic test verification (touched tests unavailable)`
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
if (testGateFailures.length > 0) {
|
|
2448
|
+
rootCauses.push(
|
|
2449
|
+
`${testGateFailures.length} candidate(s) failed deterministic test gate (touched tests failed)`
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
if (coverageGateFailures.length > 0) {
|
|
2453
|
+
rootCauses.push(
|
|
2454
|
+
`${coverageGateFailures.length} candidate(s) failed coverage gate (below threshold)`
|
|
2455
|
+
);
|
|
2456
|
+
}
|
|
2457
|
+
if (verifyFailures.length > 0) {
|
|
2458
|
+
rootCauses.push(`${verifyFailures.length} candidate(s) failed verify stage commands`);
|
|
2459
|
+
}
|
|
2460
|
+
if (requireChangesNoops.length > 0) {
|
|
2461
|
+
rootCauses.push(
|
|
2462
|
+
`${requireChangesNoops.length} candidate(s) produced no applicable changes while validation.requireChanges is enabled`
|
|
2463
|
+
);
|
|
2464
|
+
}
|
|
2465
|
+
if (rootCauses.length > 0) {
|
|
2466
|
+
disqualificationSummary += `. Root cause: ${rootCauses.join("; ")}`;
|
|
2467
|
+
}
|
|
2468
|
+
const candidateErrors = candidates.filter((c) => c.error).map((c) => {
|
|
2469
|
+
const variantId = formatCompetitionCandidateVariantDisplay(c);
|
|
2470
|
+
return `${variantId} - ${c.error}`;
|
|
2471
|
+
}).join("; ");
|
|
2472
|
+
if (candidateErrors) {
|
|
2473
|
+
disqualificationSummary += `. Candidate details: ${candidateErrors}`;
|
|
2474
|
+
}
|
|
2475
|
+
const result2 = {
|
|
2476
|
+
stageId: stage.id,
|
|
2477
|
+
stageType: "competition",
|
|
2478
|
+
validationPassed: false,
|
|
2479
|
+
validationScore: 0,
|
|
2480
|
+
cost: totalCost,
|
|
2481
|
+
costUnavailableReason,
|
|
2482
|
+
summary: disqualificationSummary,
|
|
2483
|
+
durationMs: Date.now() - startTime,
|
|
2484
|
+
candidates,
|
|
2485
|
+
winner: null,
|
|
2486
|
+
winnerApplied: false,
|
|
2487
|
+
scoringMode: "deterministic",
|
|
2488
|
+
competitionJudgeResult: {
|
|
2489
|
+
judgeType: config.judgeConfig?.type ?? "ai",
|
|
2490
|
+
aiJudgeAttempted: false,
|
|
2491
|
+
aiJudgeInvoked: false,
|
|
2492
|
+
aiJudgeError: void 0,
|
|
2493
|
+
judgeInvocationReason: "no-successful-candidates",
|
|
2494
|
+
rankings: [],
|
|
2495
|
+
wasTie: false,
|
|
2496
|
+
noWinnerReason: "all-failed"
|
|
2497
|
+
}
|
|
2498
|
+
};
|
|
2499
|
+
try {
|
|
2500
|
+
await artifactStore.save(stage.id, "candidates", "json", {
|
|
2501
|
+
taskId,
|
|
2502
|
+
variantCount: candidates.length,
|
|
2503
|
+
successCount: 0,
|
|
2504
|
+
candidates: candidates.map((c) => ({
|
|
2505
|
+
provider: c.variant.provider,
|
|
2506
|
+
model: c.variant.model,
|
|
2507
|
+
strategy: c.variant.strategy,
|
|
2508
|
+
success: c.success,
|
|
2509
|
+
error: c.error,
|
|
2510
|
+
cost: c.cost,
|
|
2511
|
+
costUnavailableReason: c.costUnavailableReason
|
|
2512
|
+
})),
|
|
2513
|
+
winner: null,
|
|
2514
|
+
rankings: [],
|
|
2515
|
+
allDisqualifiedByTestGate: true,
|
|
2516
|
+
aiJudgeInvoked: result2.competitionJudgeResult?.aiJudgeInvoked ?? false,
|
|
2517
|
+
scoringMode: result2.scoringMode ?? "deterministic",
|
|
2518
|
+
judgeInvocationReason: result2.competitionJudgeResult?.judgeInvocationReason ?? "no-successful-candidates"
|
|
2519
|
+
});
|
|
2520
|
+
} catch (error) {
|
|
2521
|
+
if (options.verbose) {
|
|
2522
|
+
console.warn(chalk.yellow(` Warning: Failed to persist failure artifacts: ${error}`));
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
await finalizeDeferredHandle(
|
|
2526
|
+
createEvaluationHandleFinalState({ outcome: "all_failed", winner: null })
|
|
2527
|
+
);
|
|
2528
|
+
await cleanupSynthesisInputPatches(basicResult.variants, {
|
|
2529
|
+
expectedRoot: resolveSynthesisInputPatchDir(
|
|
2530
|
+
competitionOptions.executionContext.poeticDir,
|
|
2531
|
+
taskId
|
|
2532
|
+
)
|
|
2533
|
+
});
|
|
2534
|
+
return result2;
|
|
2535
|
+
}
|
|
2536
|
+
const shouldInvokeAiJudge = shouldInvokeAiJudgeForFinished;
|
|
2537
|
+
if (shouldInvokeAiJudge) {
|
|
2538
|
+
if (options.verbose) {
|
|
2539
|
+
console.log(chalk.blue(" Invoking AI judge for competition evaluation..."));
|
|
2540
|
+
}
|
|
2541
|
+
const judgeVisibleVariantResults = buildJudgeVisibleVariantResults(
|
|
2542
|
+
finishedCandidates,
|
|
2543
|
+
basicResult.variants
|
|
2544
|
+
);
|
|
2545
|
+
if (judgeVisibleVariantResults.length < 2) {
|
|
2546
|
+
if (options.verbose) {
|
|
2547
|
+
console.warn(
|
|
2548
|
+
chalk.yellow(
|
|
2549
|
+
` Skipping AI judge: expected \u22652 finished variants but resolved ${judgeVisibleVariantResults.length}`
|
|
2550
|
+
)
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
} else {
|
|
2554
|
+
aiJudgeAttempted = true;
|
|
2555
|
+
try {
|
|
2556
|
+
const { aiJudgeRun, aiJudgePrimary } = deriveAiJudgeInvocationArgs(config.judgeConfig);
|
|
2557
|
+
eligibleVariantResultsForMatrix = judgeVisibleVariantResults;
|
|
2558
|
+
matrixDefaultWinnerSource = aiJudgePrimary;
|
|
2559
|
+
const judgeResult = await selectWinnerWithJudge(
|
|
2560
|
+
resolvedPrompt,
|
|
2561
|
+
judgeVisibleVariantResults,
|
|
2562
|
+
{
|
|
2563
|
+
taskId,
|
|
2564
|
+
aiJudgeTelemetry: true,
|
|
2565
|
+
aiJudgeRun,
|
|
2566
|
+
aiJudgePrimary,
|
|
2567
|
+
anonymizeJudge: config.judgeConfig?.anonymizeJudge,
|
|
2568
|
+
// The flywheel owns the explicit Matrix escalation block below;
|
|
2569
|
+
// opt out of the coordinator's automatic Matrix run to avoid a
|
|
2570
|
+
// duplicate Matrix call.
|
|
2571
|
+
autoMatrix: false
|
|
2572
|
+
}
|
|
2573
|
+
);
|
|
2574
|
+
latestMainJudgeResult = judgeResult;
|
|
2575
|
+
if (isJudgeType(judgeResult.synthesisContext?.selectedJudge)) {
|
|
2576
|
+
matrixDefaultWinnerSource = judgeResult.synthesisContext.selectedJudge;
|
|
2577
|
+
}
|
|
2578
|
+
latestJudgeEscalation = judgeResult.decision?.escalation;
|
|
2579
|
+
judgedWinner = judgeResult.winner;
|
|
2580
|
+
aiJudgeInvoked = true;
|
|
2581
|
+
for (const candidate of candidates) {
|
|
2582
|
+
if (!finishedExecutionKeys.has(variantIdForSpec(candidate.variant))) continue;
|
|
2583
|
+
const matchingResult = matchVariantResult(candidate.variant, basicResult.variants);
|
|
2584
|
+
if (!matchingResult) continue;
|
|
2585
|
+
const updated = variantResultToCandidate(candidate.variant, matchingResult);
|
|
2586
|
+
candidate.score = updated.score;
|
|
2587
|
+
candidate.feedback = updated.feedback;
|
|
2588
|
+
}
|
|
2589
|
+
recordDeterministicTestSignalObservation(candidates, options.verbose);
|
|
2590
|
+
if (options.verbose) {
|
|
2591
|
+
console.log(chalk.green(" ok AI judge evaluation complete"));
|
|
2592
|
+
}
|
|
2593
|
+
} catch (error) {
|
|
2594
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
2595
|
+
if (options.verbose) {
|
|
2596
|
+
console.warn(chalk.yellow(` AI judge invocation failed: ${errorMsg}`));
|
|
2597
|
+
}
|
|
2598
|
+
aiJudgeError = errorMsg;
|
|
2599
|
+
aiJudgeInvoked = false;
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
let winnerInfo = aiJudgeInvoked ? buildWinnerInfoFromJudgeVerdict(candidates, judgedWinner, finishedCandidates) : determineWinner(candidates, config, expectedAllowlist);
|
|
2604
|
+
if (aiJudgeError && shouldInvokeAiJudge) {
|
|
2605
|
+
winnerInfo = {
|
|
2606
|
+
winner: null,
|
|
2607
|
+
rankings: [],
|
|
2608
|
+
wasTie: false,
|
|
2609
|
+
noWinnerReason: "judge-error",
|
|
2610
|
+
tieBreaker: void 0
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2613
|
+
let tieBreakAiJudgeInvoked = false;
|
|
2614
|
+
if (!aiJudgeInvoked && usedCoverageScoring && winnerInfo.wasTie && config.judgeConfig && candidates.length > 1) {
|
|
2615
|
+
const successful = candidates.filter((c) => c.success && typeof c.score === "number");
|
|
2616
|
+
const SCORE_COLLISION_DECIMALS = 6;
|
|
2617
|
+
const SCORE_COLLISION_MULTIPLIER = 10 ** SCORE_COLLISION_DECIMALS;
|
|
2618
|
+
const quantizeScore = (score) => {
|
|
2619
|
+
if (!Number.isFinite(score)) return 0;
|
|
2620
|
+
return Math.round(score * SCORE_COLLISION_MULTIPLIER) / SCORE_COLLISION_MULTIPLIER;
|
|
2621
|
+
};
|
|
2622
|
+
const topScoreRaw = successful.reduce((max, c) => Math.max(max, c.score ?? 0), -Infinity);
|
|
2623
|
+
const topScoreQuantized = quantizeScore(topScoreRaw);
|
|
2624
|
+
const tiedAtTop = successful.filter(
|
|
2625
|
+
(c) => quantizeScore(Number(c.score ?? 0)) === topScoreQuantized
|
|
2626
|
+
);
|
|
2627
|
+
if (tiedAtTop.length >= 2) {
|
|
2628
|
+
const first = tiedAtTop[0];
|
|
2629
|
+
const getCandidateChangedFileCount = (candidate) => Array.isArray(candidate.changedFiles) ? candidate.changedFiles.length : 0;
|
|
2630
|
+
const getCandidateDriftViolations = (candidate) => {
|
|
2631
|
+
if (!Array.isArray(candidate.changedFiles) || candidate.changedFiles.length === 0)
|
|
2632
|
+
return 0;
|
|
2633
|
+
if (!Array.isArray(expectedAllowlist) || expectedAllowlist.length === 0) return 0;
|
|
2634
|
+
return findAllowlistViolations(candidate.changedFiles, expectedAllowlist).length;
|
|
2635
|
+
};
|
|
2636
|
+
const allSameDrift = first ? tiedAtTop.every(
|
|
2637
|
+
(c) => getCandidateDriftViolations(c) === getCandidateDriftViolations(first)
|
|
2638
|
+
) : false;
|
|
2639
|
+
const allSameDiff = first ? tiedAtTop.every(
|
|
2640
|
+
(c) => getCandidateChangedFileCount(c) === getCandidateChangedFileCount(first)
|
|
2641
|
+
) : false;
|
|
2642
|
+
if (allSameDrift && allSameDiff && typeof options.workerCwd === "string") {
|
|
2643
|
+
try {
|
|
2644
|
+
const { aiJudgeRun, aiJudgePrimary } = deriveAiJudgeInvocationArgs(config.judgeConfig);
|
|
2645
|
+
const tiedVariantResults = tiedAtTop.map((candidate) => matchVariantResult(candidate.variant, basicResult.variants)).filter(Boolean);
|
|
2646
|
+
if (tiedVariantResults.length >= 2) {
|
|
2647
|
+
const tiebreakJudgeResult = await selectWinnerWithJudge(
|
|
2648
|
+
resolvedPrompt,
|
|
2649
|
+
tiedVariantResults,
|
|
2650
|
+
{
|
|
2651
|
+
taskId,
|
|
2652
|
+
evaluationPhase: "tiebreak",
|
|
2653
|
+
aiJudgeTelemetry: true,
|
|
2654
|
+
aiJudgeRun,
|
|
2655
|
+
aiJudgePrimary,
|
|
2656
|
+
anonymizeJudge: config.judgeConfig?.anonymizeJudge,
|
|
2657
|
+
// Matrix escalation for this stage is owned by the explicit
|
|
2658
|
+
// block keyed off the main judge's escalation; keep the
|
|
2659
|
+
// tie-breaker from launching its own automatic Matrix run.
|
|
2660
|
+
autoMatrix: false
|
|
2661
|
+
}
|
|
2662
|
+
);
|
|
2663
|
+
latestTiebreakJudgeResult = tiebreakJudgeResult;
|
|
2664
|
+
const tiebreakWinner = tiebreakJudgeResult.winner;
|
|
2665
|
+
if (tiebreakWinner) {
|
|
2666
|
+
const winningCandidate = findCandidateForVariantResult(candidates, tiebreakWinner);
|
|
2667
|
+
if (winningCandidate) {
|
|
2668
|
+
tieBreakAiJudgeInvoked = true;
|
|
2669
|
+
winnerInfo = {
|
|
2670
|
+
...winnerInfo,
|
|
2671
|
+
winner: winningCandidate
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
} catch (error) {
|
|
2677
|
+
if (options.verbose) {
|
|
2678
|
+
console.warn(chalk.yellow(` AI judge tie-breaker failed: ${String(error)}`));
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
const defaultWinnerCandidate = winnerInfo.winner;
|
|
2685
|
+
if (latestJudgeEscalation?.recommended === "matrix" && eligibleVariantResultsForMatrix.length >= 2) {
|
|
2686
|
+
const matrixPolicy = resolveMatrixAuthorityPolicy(config.judgeConfig?.matrixAuthority);
|
|
2687
|
+
effectiveMatrixAuthority = matrixPolicy;
|
|
2688
|
+
try {
|
|
2689
|
+
const matrixCoordinator = new JudgeCoordinator();
|
|
2690
|
+
const matrixResult = await matrixCoordinator.evaluateProfileMatrix(
|
|
2691
|
+
eligibleVariantResultsForMatrix,
|
|
2692
|
+
resolvedPrompt,
|
|
2693
|
+
{
|
|
2694
|
+
taskId,
|
|
2695
|
+
anonymizeJudge: config.judgeConfig?.anonymizeJudge,
|
|
2696
|
+
evaluationContext: latestMainJudgeResult?.evaluationContext,
|
|
2697
|
+
matrixEscalationContext: {
|
|
2698
|
+
reasons: latestJudgeEscalation.reasons
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
);
|
|
2702
|
+
const defaultWinnerResult = basicResult.variants.find(
|
|
2703
|
+
(variant) => defaultWinnerCandidate ? candidateMatchesVariantResult(defaultWinnerCandidate, variant) : false
|
|
2704
|
+
);
|
|
2705
|
+
const defaultWinner = defaultWinnerResult ? `${defaultWinnerResult.provider}:${defaultWinnerResult.variant}` : "none";
|
|
2706
|
+
const authorityDecision = evaluateMatrixAuthority({
|
|
2707
|
+
policy: matrixPolicy,
|
|
2708
|
+
defaultWinner,
|
|
2709
|
+
defaultWinnerSource: matrixDefaultWinnerSource,
|
|
2710
|
+
matrixEvaluatorType: matrixResult.matrixEvaluatorType,
|
|
2711
|
+
matrixResult,
|
|
2712
|
+
variants: eligibleVariantResultsForMatrix
|
|
2713
|
+
});
|
|
2714
|
+
matrixRan = true;
|
|
2715
|
+
matrixProfileAgreement = authorityDecision.profileAgreement;
|
|
2716
|
+
if (authorityDecision.selectedByMatrix && authorityDecision.matrixWinner && isAcceptedMatrixVerdict(authorityDecision.winnerStatus)) {
|
|
2717
|
+
const matrixWinnerCandidate = findCandidateForVariantResult(
|
|
2718
|
+
candidates,
|
|
2719
|
+
authorityDecision.matrixWinner
|
|
2720
|
+
);
|
|
2721
|
+
if (matrixWinnerCandidate) {
|
|
2722
|
+
winnerInfo = {
|
|
2723
|
+
...winnerInfo,
|
|
2724
|
+
winner: matrixWinnerCandidate
|
|
2725
|
+
};
|
|
2726
|
+
} else {
|
|
2727
|
+
matrixAuthorityWarnings.push(
|
|
2728
|
+
"Matrix authority selected a variant that could not be resolved to a candidate"
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
} else {
|
|
2732
|
+
if (!isAcceptedMatrixVerdict(authorityDecision.winnerStatus) && authorityDecision.nonSelectionReasons.length === 0) {
|
|
2733
|
+
matrixAuthorityNonSelectionReasons.push(
|
|
2734
|
+
`matrix winner status is ${authorityDecision.winnerStatus}`
|
|
2735
|
+
);
|
|
2736
|
+
}
|
|
2737
|
+
if (authorityDecision.winnerStatus === "conditional") {
|
|
2738
|
+
matrixAuthorityNonSelectionReasons.push(
|
|
2739
|
+
...authorityDecision.winnerCaveats.slice(0, 3)
|
|
2740
|
+
);
|
|
2741
|
+
}
|
|
2742
|
+
if (authorityDecision.nonSelectionReasons.length > 0) {
|
|
2743
|
+
matrixAuthorityNonSelectionReasons.push(
|
|
2744
|
+
...authorityDecision.nonSelectionReasons.slice(0, 3)
|
|
2745
|
+
);
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
} catch (error) {
|
|
2749
|
+
matrixAuthorityWarnings.push(`Matrix authority evaluation failed: ${String(error)}`);
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
const successCount = candidates.filter((c) => c.success).length;
|
|
2753
|
+
const persistedAiJudgeInvoked = tieBreakAiJudgeInvoked || aiJudgeInvoked;
|
|
2754
|
+
const persistedScoringMode = aiJudgeInvoked ? "ai-judge" : tieBreakAiJudgeInvoked ? "hybrid" : "deterministic";
|
|
2755
|
+
const persistedJudgeInvocationReason = aiJudgeError ? "error" : tieBreakAiJudgeInvoked || aiJudgeInvoked ? "multiple-successful-candidates" : successCount === 0 ? "no-successful-candidates" : successCount === 1 ? "single-successful-candidate" : "deterministic-shortcut";
|
|
2756
|
+
const judgeResultForEvidence = latestMainJudgeResult ?? latestTiebreakJudgeResult;
|
|
2757
|
+
const hasNewJudgeSchemaFields = config.judgeConfig?.judgeRun !== void 0 || config.judgeConfig?.matrixAuthority !== void 0 || matrixRan;
|
|
2758
|
+
const persistedMatrixAuthority = effectiveMatrixAuthority ?? (config.judgeConfig?.matrixAuthority !== void 0 ? resolveMatrixAuthorityPolicy(config.judgeConfig.matrixAuthority) : void 0);
|
|
2759
|
+
const { judgeRunRequested } = deriveAiJudgeInvocationArgs(config.judgeConfig);
|
|
2760
|
+
const multiJudgeEvidence = hasNewJudgeSchemaFields ? buildMultiJudgeEvidenceBlock({
|
|
2761
|
+
judgeResult: judgeResultForEvidence,
|
|
2762
|
+
judgeRunRequested,
|
|
2763
|
+
matrixAuthority: persistedMatrixAuthority,
|
|
2764
|
+
matrixRan,
|
|
2765
|
+
matrixProfileAgreement,
|
|
2766
|
+
matrixNonSelectionReasons: matrixAuthorityNonSelectionReasons
|
|
2767
|
+
}) : void 0;
|
|
2768
|
+
try {
|
|
2769
|
+
await artifactStore.save(stage.id, "candidates", "json", {
|
|
2770
|
+
taskId,
|
|
2771
|
+
variantCount: candidates.length,
|
|
2772
|
+
successCount: candidates.filter((c) => c.success).length,
|
|
2773
|
+
candidates: candidates.map((c) => ({
|
|
2774
|
+
provider: c.variant.provider,
|
|
2775
|
+
model: c.variant.model,
|
|
2776
|
+
strategy: c.variant.strategy,
|
|
2777
|
+
success: c.success,
|
|
2778
|
+
score: c.score,
|
|
2779
|
+
error: c.error,
|
|
2780
|
+
cost: c.cost,
|
|
2781
|
+
costUnavailableReason: c.costUnavailableReason
|
|
2782
|
+
})),
|
|
2783
|
+
winner: winnerInfo.winner ? {
|
|
2784
|
+
provider: winnerInfo.winner.variant.provider,
|
|
2785
|
+
model: winnerInfo.winner.variant.model,
|
|
2786
|
+
score: winnerInfo.winner.score
|
|
2787
|
+
} : null,
|
|
2788
|
+
rankings: winnerInfo.rankings,
|
|
2789
|
+
aiJudgeInvoked: persistedAiJudgeInvoked,
|
|
2790
|
+
scoringMode: persistedScoringMode,
|
|
2791
|
+
judgeInvocationReason: persistedJudgeInvocationReason,
|
|
2792
|
+
...multiJudgeEvidence ? { multiJudgeEvidence } : {}
|
|
2793
|
+
});
|
|
2794
|
+
await artifactStore.save(
|
|
2795
|
+
stage.id,
|
|
2796
|
+
"bundle",
|
|
2797
|
+
"text",
|
|
2798
|
+
buildCompetitionBundle(taskId, candidates, basicResult)
|
|
2799
|
+
);
|
|
2800
|
+
if (winnerInfo.winner) {
|
|
2801
|
+
await artifactStore.save(stage.id, "winner", "json", {
|
|
2802
|
+
variant: winnerInfo.winner.variant,
|
|
2803
|
+
score: winnerInfo.winner.score,
|
|
2804
|
+
feedback: winnerInfo.winner.feedback,
|
|
2805
|
+
commitSha: winnerInfo.winner.commitSha,
|
|
2806
|
+
changedFiles: winnerInfo.winner.changedFiles
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2809
|
+
const winnerResult = winnerInfo.winner ? matchVariantResult(winnerInfo.winner.variant, basicResult.variants) : void 0;
|
|
2810
|
+
const winnerDiff = typeof winnerResult?.worktreeDiff === "string" ? winnerResult.worktreeDiff : "";
|
|
2811
|
+
await artifactStore.save(stage.id, "winnerDiff", "diff", winnerDiff);
|
|
2812
|
+
let rationalePacket = basicResult.variants.find((v) => v.judgeEvaluation?.rationalePacket)?.judgeEvaluation?.rationalePacket;
|
|
2813
|
+
if (!rationalePacket) {
|
|
2814
|
+
rationalePacket = synthesizeDeterministicRationalePacket(candidates, winnerInfo, config);
|
|
2815
|
+
} else {
|
|
2816
|
+
const buildVariantId = (candidate) => {
|
|
2817
|
+
const parts = [candidate.variant.provider];
|
|
2818
|
+
if (candidate.variant.model) parts.push(candidate.variant.model);
|
|
2819
|
+
if (candidate.variant.strategy) parts.push(candidate.variant.strategy);
|
|
2820
|
+
return parts.join(":");
|
|
2821
|
+
};
|
|
2822
|
+
const finalWinnerId = winnerInfo.winner ? buildVariantId(winnerInfo.winner) : "none";
|
|
2823
|
+
const normalizedJudgeWinnerId = rationalePacket.winnerId ?? "none";
|
|
2824
|
+
if (normalizedJudgeWinnerId !== finalWinnerId) {
|
|
2825
|
+
rationalePacket = {
|
|
2826
|
+
...rationalePacket,
|
|
2827
|
+
rawWinnerId: rationalePacket.winnerId ?? void 0,
|
|
2828
|
+
winnerId: finalWinnerId,
|
|
2829
|
+
winnerOverridden: true
|
|
2830
|
+
};
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
await artifactStore.save(stage.id, "judgeRationale", "json", rationalePacket);
|
|
2834
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
2835
|
+
const provider = candidate.variant.provider;
|
|
2836
|
+
const suffix = provider ? `${provider}-${index + 1}` : `${index + 1}`;
|
|
2837
|
+
const artifactName = `candidate-${suffix}`;
|
|
2838
|
+
const matchingResult = matchVariantResult(candidate.variant, basicResult.variants);
|
|
2839
|
+
await artifactStore.save(stage.id, artifactName, "json", {
|
|
2840
|
+
candidate,
|
|
2841
|
+
variantResult: matchingResult ? {
|
|
2842
|
+
provider: matchingResult.provider,
|
|
2843
|
+
model: matchingResult.model,
|
|
2844
|
+
strategy: matchingResult.strategy,
|
|
2845
|
+
success: matchingResult.success,
|
|
2846
|
+
completeness: matchingResult.completeness,
|
|
2847
|
+
judgeScore: matchingResult.judgeScore,
|
|
2848
|
+
worktreeDiff: matchingResult.worktreeDiff,
|
|
2849
|
+
worktreeSummary: matchingResult.worktreeSummary,
|
|
2850
|
+
retainedWorktreePath: matchingResult.retainedWorktreePath,
|
|
2851
|
+
logFilePath: matchingResult.logFilePath,
|
|
2852
|
+
logTail: matchingResult.logTail,
|
|
2853
|
+
costMetrics: matchingResult.costMetrics,
|
|
2854
|
+
error: matchingResult.error?.message
|
|
2855
|
+
} : null
|
|
2856
|
+
});
|
|
2857
|
+
candidate.resultArtifactPath = `${stage.id}.${artifactName}`;
|
|
2858
|
+
}
|
|
2859
|
+
} catch (error) {
|
|
2860
|
+
if (options.verbose) {
|
|
2861
|
+
console.warn(chalk.yellow(` Warning: Failed to persist competition artifacts: ${error}`));
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
const coherenceMetrics = computeCoherenceMetrics(
|
|
2865
|
+
candidates,
|
|
2866
|
+
DEFAULT_COHERENCE_THRESHOLD,
|
|
2867
|
+
expectedAllowlist
|
|
2868
|
+
);
|
|
2869
|
+
const markedIncomparable = !coherenceMetrics.isCoherent;
|
|
2870
|
+
const warnings = [];
|
|
2871
|
+
if (markedIncomparable) {
|
|
2872
|
+
warnings.push(
|
|
2873
|
+
`Low coherence between successful candidates (avg ${coherenceMetrics.averageSimilarity.toFixed(2)} < ${coherenceMetrics.coherenceThreshold.toFixed(2)})`
|
|
2874
|
+
);
|
|
2875
|
+
}
|
|
2876
|
+
if (aiJudgeError) {
|
|
2877
|
+
warnings.push(`AI judge invocation failed: ${aiJudgeError}`);
|
|
2878
|
+
}
|
|
2879
|
+
if (winnerInfo.noWinnerDiagnostic) {
|
|
2880
|
+
warnings.push(winnerInfo.noWinnerDiagnostic);
|
|
2881
|
+
}
|
|
2882
|
+
warnings.push(...matrixAuthorityWarnings);
|
|
2883
|
+
if (winnerInfo.belowThresholdWinner) {
|
|
2884
|
+
warnings.push(
|
|
2885
|
+
`Winner selected below threshold (${winnerInfo.belowThresholdWinner.winnerScore} < ${winnerInfo.belowThresholdWinner.threshold})`
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
const driftContext = computeCompetitionDrift(candidates, expectedAllowlist, effectiveMode);
|
|
2889
|
+
try {
|
|
2890
|
+
await artifactStore.save(stage.id, "stage-change", "json", {
|
|
2891
|
+
stageId: stage.id,
|
|
2892
|
+
stageType: "competition",
|
|
2893
|
+
mode: effectiveMode,
|
|
2894
|
+
deliveredFiles: driftContext.deliveredFiles,
|
|
2895
|
+
expectedFiles: driftContext.expectedFiles,
|
|
2896
|
+
violations: driftContext.violations,
|
|
2897
|
+
hasDrift: driftContext.hasDrift,
|
|
2898
|
+
candidateCount: candidates.length,
|
|
2899
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2900
|
+
});
|
|
2901
|
+
await artifactStore.save(stage.id, "stage-change-summary", "text", driftContext.summary);
|
|
2902
|
+
} catch (error) {
|
|
2903
|
+
if (options.verbose) {
|
|
2904
|
+
console.warn(chalk.yellow(` Warning: Failed to persist drift context: ${error}`));
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
const effectiveWinnerInfo = winnerInfo;
|
|
2908
|
+
const winnerVerificationAllowsSuccess = effectiveWinnerInfo.winner ? verificationPolarityAllowsStageSuccess({
|
|
2909
|
+
verification: effectiveWinnerInfo.winner.verification,
|
|
2910
|
+
testStatus: effectiveWinnerInfo.winner.testStatus,
|
|
2911
|
+
rawTestStatus: effectiveWinnerInfo.winner.testStatus,
|
|
2912
|
+
exitCode: effectiveWinnerInfo.winner.testsExecuted?.exitCode
|
|
2913
|
+
}) : false;
|
|
2914
|
+
const validationPassed = successCount > 0 && effectiveWinnerInfo.winner !== null && winnerVerificationAllowsSuccess;
|
|
2915
|
+
let summary = buildCompetitionSummary(candidates, effectiveWinnerInfo, config);
|
|
2916
|
+
if (aiJudgeError && shouldInvokeAiJudge) {
|
|
2917
|
+
summary = `Competition failed: AI judge invocation failed: ${aiJudgeError}`;
|
|
2918
|
+
}
|
|
2919
|
+
if (markedIncomparable) {
|
|
2920
|
+
summary += ` (low coherence: ${coherenceMetrics.averageSimilarity.toFixed(2)})`;
|
|
2921
|
+
}
|
|
2922
|
+
const scoringMode = aiJudgeInvoked ? "ai-judge" : tieBreakAiJudgeInvoked ? "hybrid" : "deterministic";
|
|
2923
|
+
const judgeInvocationReason = aiJudgeError ? "error" : tieBreakAiJudgeInvoked || aiJudgeInvoked ? "multiple-successful-candidates" : successCount === 0 ? "no-successful-candidates" : successCount === 1 ? "single-successful-candidate" : "deterministic-shortcut";
|
|
2924
|
+
const winnerNeedsRepair = Boolean(
|
|
2925
|
+
effectiveWinnerInfo.winner?.verification && !effectiveWinnerInfo.winner.verification.passed
|
|
2926
|
+
);
|
|
2927
|
+
const stageVerification = effectiveWinnerInfo.winner?.verification;
|
|
2928
|
+
const result = {
|
|
2929
|
+
stageId: stage.id,
|
|
2930
|
+
stageType: "competition",
|
|
2931
|
+
competitionTaskId: taskId,
|
|
2932
|
+
validationPassed,
|
|
2933
|
+
validationScore: effectiveWinnerInfo.winner?.score,
|
|
2934
|
+
cost: totalCost,
|
|
2935
|
+
costUnavailableReason,
|
|
2936
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
2937
|
+
summary,
|
|
2938
|
+
durationMs: Date.now() - startTime,
|
|
2939
|
+
candidates,
|
|
2940
|
+
winner: effectiveWinnerInfo.winner,
|
|
2941
|
+
winnerApplied: false,
|
|
2942
|
+
// MVP: winner application happens in the workflow executor
|
|
2943
|
+
winnerNeedsRepair,
|
|
2944
|
+
verification: stageVerification,
|
|
2945
|
+
coherenceMetrics,
|
|
2946
|
+
markedIncomparable,
|
|
2947
|
+
scoringMode,
|
|
2948
|
+
competitionJudgeResult: {
|
|
2949
|
+
judgeType: config.judgeConfig?.type ?? "ai",
|
|
2950
|
+
aiJudgeAttempted,
|
|
2951
|
+
aiJudgeInvoked: tieBreakAiJudgeInvoked || aiJudgeInvoked,
|
|
2952
|
+
aiJudgeError,
|
|
2953
|
+
judgeInvocationReason,
|
|
2954
|
+
rankings: effectiveWinnerInfo.rankings,
|
|
2955
|
+
wasTie: effectiveWinnerInfo.wasTie,
|
|
2956
|
+
noWinnerReason: effectiveWinnerInfo.noWinnerReason,
|
|
2957
|
+
belowThresholdWinner: effectiveWinnerInfo.belowThresholdWinner,
|
|
2958
|
+
tieBreaker: effectiveWinnerInfo.tieBreaker,
|
|
2959
|
+
scoreCollisionReport: effectiveWinnerInfo.scoreCollisionReport
|
|
2960
|
+
},
|
|
2961
|
+
driftContext
|
|
2962
|
+
};
|
|
2963
|
+
if (options.verbose) {
|
|
2964
|
+
console.log(chalk.green(" ok Competition complete"));
|
|
2965
|
+
console.log(
|
|
2966
|
+
chalk.gray(
|
|
2967
|
+
` Winner: ${effectiveWinnerInfo.winner ? formatCompetitionCandidateVariantDisplay(effectiveWinnerInfo.winner) : "none"}`
|
|
2968
|
+
)
|
|
2969
|
+
);
|
|
2970
|
+
console.log(
|
|
2971
|
+
chalk.gray(
|
|
2972
|
+
` Total cost: ${costUnavailableReason !== void 0 ? "unavailable" : `$${totalCost.toFixed(4)}`}`
|
|
2973
|
+
)
|
|
2974
|
+
);
|
|
2975
|
+
console.log(
|
|
2976
|
+
chalk.gray(
|
|
2977
|
+
` Coherence: ${coherenceMetrics.averageSimilarity.toFixed(2)} (${coherenceMetrics.isCoherent ? "coherent" : "INCOHERENT"})`
|
|
2978
|
+
)
|
|
2979
|
+
);
|
|
2980
|
+
if (driftContext.hasDrift) {
|
|
2981
|
+
console.log(
|
|
2982
|
+
chalk.yellow(
|
|
2983
|
+
` Drift: ${driftContext.violations.length} file(s) outside allowlist (mode: ${effectiveMode})`
|
|
2984
|
+
)
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
const authoritativeWinner = effectiveWinnerInfo.winner ? basicResult.variants.find(
|
|
2989
|
+
(variant) => candidateMatchesVariantResult(effectiveWinnerInfo.winner, variant)
|
|
2990
|
+
) : void 0;
|
|
2991
|
+
if (effectiveWinnerInfo.winner && !authoritativeWinner) {
|
|
2992
|
+
const errorMessage = "Final competition winner could not be resolved to an executed variant";
|
|
2993
|
+
await finalizeDeferredHandle(
|
|
2994
|
+
createEvaluationHandleFinalState({ outcome: "error", winner: null, errorMessage })
|
|
2995
|
+
);
|
|
2996
|
+
await cleanupSynthesisInputPatches(basicResult.variants, {
|
|
2997
|
+
expectedRoot: resolveSynthesisInputPatchDir(
|
|
2998
|
+
competitionOptions.executionContext.poeticDir,
|
|
2999
|
+
taskId
|
|
3000
|
+
)
|
|
3001
|
+
});
|
|
3002
|
+
throw new Error(errorMessage);
|
|
3003
|
+
}
|
|
3004
|
+
await finalizeDeferredHandle(
|
|
3005
|
+
authoritativeWinner ? createEvaluationHandleFinalState({
|
|
3006
|
+
outcome: "winner_selected",
|
|
3007
|
+
winner: toEvaluationHandleWinnerMetadata(authoritativeWinner)
|
|
3008
|
+
}) : createEvaluationHandleFinalState({
|
|
3009
|
+
outcome: successCount === 0 ? "all_failed" : "no_winner",
|
|
3010
|
+
winner: null
|
|
3011
|
+
})
|
|
3012
|
+
);
|
|
3013
|
+
await cleanupSynthesisInputPatches(basicResult.variants, {
|
|
3014
|
+
expectedRoot: resolveSynthesisInputPatchDir(
|
|
3015
|
+
competitionOptions.executionContext.poeticDir,
|
|
3016
|
+
taskId
|
|
3017
|
+
)
|
|
3018
|
+
});
|
|
3019
|
+
return result;
|
|
3020
|
+
} catch (error) {
|
|
3021
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3022
|
+
if (!deferredHandleFinalized) {
|
|
3023
|
+
await finalizeEvaluationHandleAsync(
|
|
3024
|
+
taskId,
|
|
3025
|
+
createEvaluationHandleFinalState({ outcome: "error", winner: null, errorMessage })
|
|
3026
|
+
).catch(() => {
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3029
|
+
await cleanupSynthesisInputPatches(basicResult.variants, {
|
|
3030
|
+
expectedRoot: resolveSynthesisInputPatchDir(
|
|
3031
|
+
competitionOptions.executionContext.poeticDir,
|
|
3032
|
+
taskId
|
|
3033
|
+
)
|
|
3034
|
+
}).catch(() => {
|
|
3035
|
+
});
|
|
3036
|
+
return {
|
|
3037
|
+
stageId: stage.id,
|
|
3038
|
+
stageType: "competition",
|
|
3039
|
+
validationPassed: false,
|
|
3040
|
+
cost: 0,
|
|
3041
|
+
candidates: [],
|
|
3042
|
+
winner: null,
|
|
3043
|
+
summary: `Competition post-processing failed: ${errorMessage}`,
|
|
3044
|
+
durationMs: Date.now() - startTime,
|
|
3045
|
+
competitionJudgeResult: {
|
|
3046
|
+
judgeType: config.judgeConfig?.type ?? "ai",
|
|
3047
|
+
aiJudgeAttempted: false,
|
|
3048
|
+
aiJudgeInvoked: false,
|
|
3049
|
+
aiJudgeError: errorMessage,
|
|
3050
|
+
judgeInvocationReason: "error",
|
|
3051
|
+
rankings: [],
|
|
3052
|
+
wasTie: false,
|
|
3053
|
+
noWinnerReason: "judge-error"
|
|
3054
|
+
}
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
function buildCompetitionSummary(candidates, winnerInfo, config) {
|
|
3059
|
+
const successCount = candidates.filter((c) => c.success).length;
|
|
3060
|
+
const failCount = candidates.length - successCount;
|
|
3061
|
+
let summary = `Competition: ${successCount}/${candidates.length} variants succeeded`;
|
|
3062
|
+
if (failCount > 0) {
|
|
3063
|
+
summary += ` (${failCount} failed)`;
|
|
3064
|
+
}
|
|
3065
|
+
if (winnerInfo.winner) {
|
|
3066
|
+
summary += `. Winner: ${formatCompetitionCandidateVariantDisplay(winnerInfo.winner)}`;
|
|
3067
|
+
if (winnerInfo.winner.score !== void 0) {
|
|
3068
|
+
summary += ` (score: ${winnerInfo.winner.score})`;
|
|
3069
|
+
}
|
|
3070
|
+
if (winnerInfo.belowThresholdWinner) {
|
|
3071
|
+
summary += ` (below threshold: ${winnerInfo.belowThresholdWinner.winnerScore} < ${winnerInfo.belowThresholdWinner.threshold})`;
|
|
3072
|
+
}
|
|
3073
|
+
} else if (winnerInfo.noWinnerReason) {
|
|
3074
|
+
const reasons = {
|
|
3075
|
+
"all-failed": "all variants failed",
|
|
3076
|
+
tie: "tie between top variants",
|
|
3077
|
+
"below-threshold": `all scores below threshold (${config.judgeConfig?.threshold ?? 0})`,
|
|
3078
|
+
"judge-error": "judge evaluation failed",
|
|
3079
|
+
incomparable: "candidates touched disjoint files (low coherence)"
|
|
3080
|
+
};
|
|
3081
|
+
summary += `. No winner: ${reasons[winnerInfo.noWinnerReason] ?? winnerInfo.noWinnerReason}`;
|
|
3082
|
+
}
|
|
3083
|
+
return summary;
|
|
3084
|
+
}
|
|
3085
|
+
function isCompetitionStage(stage) {
|
|
3086
|
+
return stage.type === "competition" && stage.competition !== void 0;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
export {
|
|
3090
|
+
verificationPolarityAllowsStageSuccess,
|
|
3091
|
+
computeCoherenceMetrics,
|
|
3092
|
+
__internalDetermineWinner,
|
|
3093
|
+
__internalRecordDeterministicTestSignalObservation,
|
|
3094
|
+
__internalExtractChangedFilesFromResult,
|
|
3095
|
+
__internalGetVariantTelemetryStatePath,
|
|
3096
|
+
__internalHydrateCandidateCostsFromTelemetry,
|
|
3097
|
+
__internalVariantResultToCandidate,
|
|
3098
|
+
__internalMatchVariantResult,
|
|
3099
|
+
__internalCandidateMatchesVariantResult,
|
|
3100
|
+
__internalResolveCompetitionCostAggregate,
|
|
3101
|
+
executeCompetitionStage,
|
|
3102
|
+
isCompetitionStage
|
|
3103
|
+
};
|
|
3104
|
+
//# sourceMappingURL=chunk-7DHRDWFS.js.map
|