@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,1221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure BB presentation for the BPAU-03 sprint-composition lane.
|
|
3
|
+
*
|
|
4
|
+
* This module is presentation only. It maps already-canonical BPAU-03 evidence
|
|
5
|
+
* to bounded, plain-language rows and controls, and it converts a form draft into
|
|
6
|
+
* exactly one typed BPAU-03 request. It holds the same authority boundary as the
|
|
7
|
+
* rest of this plugin:
|
|
8
|
+
*
|
|
9
|
+
* - Poetic is authoritative. No capacity, readiness, integrity, membership, or
|
|
10
|
+
* resulting status is computed, merged, re-sorted, or defaulted here: every
|
|
11
|
+
* rendered number and state comes from a BPAU-03 projection, a BPAU-00B
|
|
12
|
+
* identity envelope, or an authoritative reread.
|
|
13
|
+
* - Absent evidence renders as an explicit `unavailable` with Poetic's own
|
|
14
|
+
* reason. A missing value is never replaced by a guess or an empty success.
|
|
15
|
+
* - The vocabulary is the closed BPAU-03 vocabulary. Sprint execution,
|
|
16
|
+
* complete/close/tidy/unlock/prune-missing, custom task creation, splitting,
|
|
17
|
+
* provider/model selection, bulk scheduling, and force/dry-run/no-sync have
|
|
18
|
+
* no control here and are refused with an explicit notice.
|
|
19
|
+
* - `addSprintWorkFromBacklog` is labelled "Add from backlog". It is never
|
|
20
|
+
* described as attaching an existing task.
|
|
21
|
+
* - A submission changes nothing on screen until Poetic's reread arrives: the
|
|
22
|
+
* awaiting phase renders the pre-submission evidence unchanged.
|
|
23
|
+
*
|
|
24
|
+
* Nothing here spawns a process, reads a file, or touches the network, and this
|
|
25
|
+
* module wires no shared application file: it is loadable on its own.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
requiresMembershipConsent,
|
|
30
|
+
requiresNewIdentityConsent,
|
|
31
|
+
SPRINT_COMPOSITION_DISCLOSURE,
|
|
32
|
+
SPRINT_COMPOSITION_EFFECT_COPY,
|
|
33
|
+
SPRINT_COMPOSITION_LABELS,
|
|
34
|
+
type SprintCompositionConsentState,
|
|
35
|
+
sprintCompositionConsentPayload,
|
|
36
|
+
sprintCompositionRequestedIdentities,
|
|
37
|
+
} from './sprint-composition-model.js';
|
|
38
|
+
import { sprintMembershipIds, sprintMembershipState } from './sprint-composition-readback.js';
|
|
39
|
+
import {
|
|
40
|
+
type ApplySprintCompositionInput,
|
|
41
|
+
type ApplySprintCompositionOutput,
|
|
42
|
+
applySprintCompositionInputSchema,
|
|
43
|
+
type GetSprintOutput,
|
|
44
|
+
type ListSprintsOutput,
|
|
45
|
+
SPRINT_COMPOSITION_OUTCOME_VERSION,
|
|
46
|
+
SPRINT_COMPOSITION_VOCABULARY,
|
|
47
|
+
type SprintCompositionAction,
|
|
48
|
+
type SprintCompositionEvidence,
|
|
49
|
+
type SprintStatusEnvelope,
|
|
50
|
+
} from './sprint-composition-schema.js';
|
|
51
|
+
import type { GetTaskDetailOutput } from './task-detail-schema.js';
|
|
52
|
+
|
|
53
|
+
export type { SprintCompositionConsentState };
|
|
54
|
+
|
|
55
|
+
export const SPRINT_COMPOSITION_VIEW_VERSION = '1.0.0' as const;
|
|
56
|
+
|
|
57
|
+
/** Bound on any single emitted line. */
|
|
58
|
+
export const SPRINT_COMPOSITION_MAX_LINE_CHARS = 240;
|
|
59
|
+
|
|
60
|
+
/** Bound on how many identities one row lists. */
|
|
61
|
+
export const SPRINT_COMPOSITION_LIST_LIMIT = 12;
|
|
62
|
+
|
|
63
|
+
/** Plain label for evidence Poetic did not publish. */
|
|
64
|
+
const UNAVAILABLE = 'unavailable';
|
|
65
|
+
|
|
66
|
+
export interface SprintCompositionRow {
|
|
67
|
+
/** Stable row id, usable as a render key. */
|
|
68
|
+
id: string;
|
|
69
|
+
label: string;
|
|
70
|
+
value: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function truncateLine(text: string): string {
|
|
74
|
+
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
75
|
+
if (normalized.length <= SPRINT_COMPOSITION_MAX_LINE_CHARS) return normalized;
|
|
76
|
+
return `${normalized.slice(0, SPRINT_COMPOSITION_MAX_LINE_CHARS - 3)}...`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function row(id: string, label: string, value: string): SprintCompositionRow {
|
|
80
|
+
return { id, label, value: truncateLine(value) };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Render a list of identities. An empty list is a published "none". */
|
|
84
|
+
function formatIdentities(values: readonly string[]): string {
|
|
85
|
+
if (values.length === 0) return 'none';
|
|
86
|
+
const shown = values.slice(0, SPRINT_COMPOSITION_LIST_LIMIT);
|
|
87
|
+
const remaining = values.length - shown.length;
|
|
88
|
+
return remaining > 0 ? `${shown.join(', ')} (+${remaining} more)` : shown.join(', ');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function formatOptional(value: string | null | undefined): string {
|
|
92
|
+
const trimmed = value?.trim() ?? '';
|
|
93
|
+
return trimmed.length > 0 ? trimmed : UNAVAILABLE;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Capacity exactly as Poetic published it. The three numbers are carried
|
|
98
|
+
* verbatim; utilization is never recomputed from the other two.
|
|
99
|
+
*/
|
|
100
|
+
function formatCapacity(capacity: {
|
|
101
|
+
allocatedHours: number;
|
|
102
|
+
totalHours: number;
|
|
103
|
+
utilizationPercent: number;
|
|
104
|
+
}): string {
|
|
105
|
+
return `${capacity.allocatedHours}h allocated of ${capacity.totalHours}h, ${capacity.utilizationPercent}% utilization (Poetic-computed)`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ------------------------------------------------------------------ *
|
|
109
|
+
* Read-only projections: sprint list and single-sprint composition
|
|
110
|
+
* ------------------------------------------------------------------ */
|
|
111
|
+
|
|
112
|
+
export interface SprintCompositionListView {
|
|
113
|
+
state: 'available' | 'unavailable';
|
|
114
|
+
scope: ListSprintsOutput['scope'];
|
|
115
|
+
headline: string;
|
|
116
|
+
rows: readonly SprintCompositionRow[];
|
|
117
|
+
/** Sprint ids Poetic published, in Poetic's own order. */
|
|
118
|
+
sprintIds: readonly string[];
|
|
119
|
+
notes: readonly string[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Render Poetic's sprint list. Order, totals, and per-sprint capacity are
|
|
124
|
+
* carried verbatim; an unavailable list is never an empty sprint list.
|
|
125
|
+
*/
|
|
126
|
+
export function buildSprintListView(output: ListSprintsOutput): SprintCompositionListView {
|
|
127
|
+
if (output.sprints.state !== 'available') {
|
|
128
|
+
return {
|
|
129
|
+
state: 'unavailable',
|
|
130
|
+
scope: output.scope,
|
|
131
|
+
headline: 'Sprint list unavailable',
|
|
132
|
+
rows: [],
|
|
133
|
+
sprintIds: [],
|
|
134
|
+
notes: [truncateLine(output.sprints.reason)],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const envelope = output.sprints.value;
|
|
138
|
+
return {
|
|
139
|
+
state: 'available',
|
|
140
|
+
scope: output.scope,
|
|
141
|
+
headline: `Sprints (${output.scope}): ${envelope.total}`,
|
|
142
|
+
rows: envelope.sprints.map((sprint) =>
|
|
143
|
+
row(
|
|
144
|
+
`sprint-${sprint.id}`,
|
|
145
|
+
`${sprint.name} (${sprint.id})`,
|
|
146
|
+
`${sprint.status}, ${sprint.startDate} to ${sprint.endDate}, ${sprint.taskCount} task(s), ${formatCapacity(sprint.capacity)}`
|
|
147
|
+
)
|
|
148
|
+
),
|
|
149
|
+
sprintIds: envelope.sprints.map((sprint) => sprint.id),
|
|
150
|
+
notes: [],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface SprintCompositionSprintView {
|
|
155
|
+
state: 'available' | 'unavailable';
|
|
156
|
+
sprintId: string;
|
|
157
|
+
headline: string;
|
|
158
|
+
rows: readonly SprintCompositionRow[];
|
|
159
|
+
/** Task ids Poetic lists as members, in Poetic's own order. */
|
|
160
|
+
membership: readonly string[];
|
|
161
|
+
/** Task ids the sprint references with no resolvable task file. */
|
|
162
|
+
missingTaskIds: readonly string[];
|
|
163
|
+
/** Integrity notes as Poetic reported them. BB reports, never repairs. */
|
|
164
|
+
integrityNotes: readonly string[];
|
|
165
|
+
notes: readonly string[];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function unavailableSprintView(
|
|
169
|
+
sprintId: string,
|
|
170
|
+
reason: string,
|
|
171
|
+
integrityNotes: readonly string[] = []
|
|
172
|
+
): SprintCompositionSprintView {
|
|
173
|
+
return {
|
|
174
|
+
state: 'unavailable',
|
|
175
|
+
sprintId,
|
|
176
|
+
headline: `Sprint ${sprintId} composition unavailable`,
|
|
177
|
+
rows: [],
|
|
178
|
+
membership: [],
|
|
179
|
+
missingTaskIds: [],
|
|
180
|
+
integrityNotes: integrityNotes.map(truncateLine),
|
|
181
|
+
notes: [truncateLine(reason)],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Render one sprint's composition from Poetic's status projection. Capacity,
|
|
187
|
+
* readiness, membership, and integrity are all Poetic-computed; the only thing
|
|
188
|
+
* added here is labelling.
|
|
189
|
+
*/
|
|
190
|
+
export function buildSprintCompositionSprintView(
|
|
191
|
+
sprintId: string,
|
|
192
|
+
sprint: SprintCompositionEvidence<SprintStatusEnvelope>,
|
|
193
|
+
integrityNotes: readonly string[] = []
|
|
194
|
+
): SprintCompositionSprintView {
|
|
195
|
+
if (sprint.state !== 'available') {
|
|
196
|
+
return unavailableSprintView(sprintId, sprint.reason, integrityNotes);
|
|
197
|
+
}
|
|
198
|
+
const value = sprint.value;
|
|
199
|
+
const progress = value.progress;
|
|
200
|
+
return {
|
|
201
|
+
state: 'available',
|
|
202
|
+
sprintId: value.sprintId,
|
|
203
|
+
headline: `Sprint ${value.name} (${value.sprintId}): ${value.status}`,
|
|
204
|
+
rows: [
|
|
205
|
+
row('sprint-id', 'Sprint', `${value.name} (${value.sprintId})`),
|
|
206
|
+
row('sprint-status', 'Status', `${value.status}${value.archived ? ', archived' : ''}`),
|
|
207
|
+
row(
|
|
208
|
+
'sprint-dates',
|
|
209
|
+
'Dates',
|
|
210
|
+
`${formatOptional(value.startDate)} to ${formatOptional(value.endDate)}`
|
|
211
|
+
),
|
|
212
|
+
row('sprint-goal', 'Goal', formatOptional(value.goal)),
|
|
213
|
+
row('sprint-capacity', 'Capacity', formatCapacity(value.capacity)),
|
|
214
|
+
row(
|
|
215
|
+
'sprint-completed-capacity',
|
|
216
|
+
'Completed capacity',
|
|
217
|
+
`${value.completedCapacity.totalDoneHours}h done (${value.completedCapacity.activeDoneHours}h active, ${value.completedCapacity.archivedDoneHours}h archived across ${value.completedCapacity.archivedTaskCount} archived task(s))`
|
|
218
|
+
),
|
|
219
|
+
row(
|
|
220
|
+
'sprint-progress',
|
|
221
|
+
'Progress',
|
|
222
|
+
`${progress.done} done, ${progress.in_progress} in progress, ${progress.review} in review, ${progress.todo} to do, ${progress.blocked} blocked, ${progress.cancelled} cancelled of ${progress.total}`
|
|
223
|
+
),
|
|
224
|
+
row(
|
|
225
|
+
'sprint-readiness',
|
|
226
|
+
'Readiness',
|
|
227
|
+
`all done ${progress.allDone ? 'yes' : 'no'}, all terminal ${progress.allTerminal ? 'yes' : 'no'}, closable ${progress.closable ? 'yes' : 'no'} (Poetic-computed)`
|
|
228
|
+
),
|
|
229
|
+
row(
|
|
230
|
+
'sprint-integrity',
|
|
231
|
+
'Integrity',
|
|
232
|
+
progress.integrityClean ? 'clean' : 'not clean (Poetic-reported)'
|
|
233
|
+
),
|
|
234
|
+
row('sprint-membership', 'Members', formatIdentities(sprintMembershipIds(value))),
|
|
235
|
+
row(
|
|
236
|
+
'sprint-missing-references',
|
|
237
|
+
'Missing task references',
|
|
238
|
+
formatIdentities(value.missingTaskIds)
|
|
239
|
+
),
|
|
240
|
+
],
|
|
241
|
+
membership: sprintMembershipIds(value),
|
|
242
|
+
missingTaskIds: value.missingTaskIds,
|
|
243
|
+
integrityNotes: integrityNotes.map(truncateLine),
|
|
244
|
+
notes: [],
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Render a `getSprint` projection, carrying its integrity notes through. */
|
|
249
|
+
export function buildSprintCompositionSprintViewFromOutput(
|
|
250
|
+
output: GetSprintOutput
|
|
251
|
+
): SprintCompositionSprintView {
|
|
252
|
+
return buildSprintCompositionSprintView(output.sprintId, output.sprint, output.integrityNotes);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ------------------------------------------------------------------ *
|
|
256
|
+
* Form: explicit identities, proportionate consent, one typed request
|
|
257
|
+
* ------------------------------------------------------------------ */
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Which identity a field names. Every action selects its identities explicitly:
|
|
261
|
+
* there is no implicit "current sprint", "next sprint", or "selected task".
|
|
262
|
+
*/
|
|
263
|
+
export type SprintCompositionFieldKind =
|
|
264
|
+
| 'sprint-id'
|
|
265
|
+
| 'source-sprint-id'
|
|
266
|
+
| 'target-sprint-id'
|
|
267
|
+
| 'backlog-item-id'
|
|
268
|
+
| 'task-id'
|
|
269
|
+
| 'text'
|
|
270
|
+
| 'date'
|
|
271
|
+
| 'hours'
|
|
272
|
+
| 'minutes'
|
|
273
|
+
| 'priority';
|
|
274
|
+
|
|
275
|
+
export interface SprintCompositionFormField {
|
|
276
|
+
id: string;
|
|
277
|
+
label: string;
|
|
278
|
+
kind: SprintCompositionFieldKind;
|
|
279
|
+
required: boolean;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const SPRINT_COMPOSITION_FIELDS: Readonly<
|
|
283
|
+
Record<SprintCompositionAction, readonly SprintCompositionFormField[]>
|
|
284
|
+
> = {
|
|
285
|
+
createSprint: [
|
|
286
|
+
{ id: 'name', label: 'Sprint name', kind: 'text', required: true },
|
|
287
|
+
{ id: 'start', label: 'Start date', kind: 'date', required: true },
|
|
288
|
+
{ id: 'end', label: 'End date', kind: 'date', required: true },
|
|
289
|
+
{ id: 'goal', label: 'Goal', kind: 'text', required: false },
|
|
290
|
+
{ id: 'hours', label: 'Capacity hours', kind: 'hours', required: false },
|
|
291
|
+
],
|
|
292
|
+
renameSprint: [
|
|
293
|
+
{ id: 'sprintId', label: 'Sprint', kind: 'sprint-id', required: true },
|
|
294
|
+
{ id: 'name', label: 'New sprint name', kind: 'text', required: true },
|
|
295
|
+
],
|
|
296
|
+
addSprintWorkFromBacklog: [
|
|
297
|
+
{ id: 'sprintId', label: 'Sprint', kind: 'sprint-id', required: true },
|
|
298
|
+
{ id: 'backlogItemId', label: 'Backlog item', kind: 'backlog-item-id', required: true },
|
|
299
|
+
{ id: 'estimate', label: 'Estimate hours', kind: 'hours', required: true },
|
|
300
|
+
{
|
|
301
|
+
id: 'expectedRuntimeMinutes',
|
|
302
|
+
label: 'Expected runtime minutes',
|
|
303
|
+
kind: 'minutes',
|
|
304
|
+
required: false,
|
|
305
|
+
},
|
|
306
|
+
{ id: 'priority', label: 'Priority', kind: 'priority', required: false },
|
|
307
|
+
],
|
|
308
|
+
removeSprintTask: [
|
|
309
|
+
{ id: 'sprintId', label: 'Sprint', kind: 'sprint-id', required: true },
|
|
310
|
+
{ id: 'taskId', label: 'Task', kind: 'task-id', required: true },
|
|
311
|
+
],
|
|
312
|
+
migrateSprintTask: [
|
|
313
|
+
{ id: 'taskId', label: 'Task', kind: 'task-id', required: true },
|
|
314
|
+
{ id: 'sourceSprintId', label: 'Source sprint', kind: 'source-sprint-id', required: true },
|
|
315
|
+
{ id: 'targetSprintId', label: 'Target sprint', kind: 'target-sprint-id', required: true },
|
|
316
|
+
],
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
export function sprintCompositionFormFields(
|
|
320
|
+
action: SprintCompositionAction
|
|
321
|
+
): readonly SprintCompositionFormField[] {
|
|
322
|
+
return SPRINT_COMPOSITION_FIELDS[action];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export const SPRINT_COMPOSITION_CONSENT_LABELS: Readonly<
|
|
326
|
+
Record<keyof SprintCompositionConsentState, string>
|
|
327
|
+
> = {
|
|
328
|
+
hostExecution: 'Poetic runs as my host user in the repository shown above.',
|
|
329
|
+
managedPlanningMutation: 'This mutates managed planning state that Poetic owns.',
|
|
330
|
+
automaticCommitAndPush:
|
|
331
|
+
"Poetic's built-in managed sync commits and pushes these planning changes.",
|
|
332
|
+
selectedRepositoryAndBranch: 'I mean this repository path and this branch.',
|
|
333
|
+
newIdentityCreation: 'A new Poetic-minted id will exist after this action.',
|
|
334
|
+
sprintMembershipChange: 'This changes which sprint holds the task.',
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
/** The consent lines an action requires; nothing more is asked for. */
|
|
338
|
+
export function sprintCompositionRequiredConsentKeys(
|
|
339
|
+
action: SprintCompositionAction
|
|
340
|
+
): Array<keyof SprintCompositionConsentState> {
|
|
341
|
+
const keys: Array<keyof SprintCompositionConsentState> = [
|
|
342
|
+
'hostExecution',
|
|
343
|
+
'managedPlanningMutation',
|
|
344
|
+
'automaticCommitAndPush',
|
|
345
|
+
'selectedRepositoryAndBranch',
|
|
346
|
+
];
|
|
347
|
+
if (requiresNewIdentityConsent(action)) keys.push('newIdentityCreation');
|
|
348
|
+
if (requiresMembershipConsent(action)) keys.push('sprintMembershipChange');
|
|
349
|
+
return keys;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface SprintCompositionConfirmation {
|
|
353
|
+
action: SprintCompositionAction;
|
|
354
|
+
/** The product label. Never "attach existing task". */
|
|
355
|
+
title: string;
|
|
356
|
+
/** What the command is asked to do, from BPAU-03's effect copy. */
|
|
357
|
+
effect: string;
|
|
358
|
+
/** Extra disclosures, present only where the effect earns them. */
|
|
359
|
+
disclosures: readonly string[];
|
|
360
|
+
requiredConsentKeys: ReadonlyArray<keyof SprintCompositionConsentState>;
|
|
361
|
+
/** True when the action changes which sprint holds a task. */
|
|
362
|
+
crossSprint: boolean;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const CROSS_SPRINT_DISCLOSURES: Readonly<Partial<Record<SprintCompositionAction, string[]>>> = {
|
|
366
|
+
removeSprintTask: [
|
|
367
|
+
'The task leaves this sprint. It stops counting toward this sprint capacity and is scheduled in no sprint until you add it to one.',
|
|
368
|
+
'Poetic keeps the task file. BB cannot read the sprint id recorded inside the task file, so a stale reference there would not be visible here.',
|
|
369
|
+
],
|
|
370
|
+
migrateSprintTask: [
|
|
371
|
+
'The task leaves the source sprint and joins the target sprint. Both sprint capacities change, and Poetic resets the task status to todo.',
|
|
372
|
+
'A mid-flight failure can leave the task listed by both sprints. BB reports what the sprint rereads say and repairs nothing.',
|
|
373
|
+
],
|
|
374
|
+
addSprintWorkFromBacklog: [
|
|
375
|
+
'Poetic creates a new task from the backlog item and attaches it to the sprint you named. The backlog item itself is not moved.',
|
|
376
|
+
'Poetic creates the task file before attaching it and has no rollback, so a created-but-unattached task is possible and is reported as such.',
|
|
377
|
+
],
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Build the confirmation for one action. Create and rename stay proportionate:
|
|
382
|
+
* they carry the effect copy and nothing more, because neither changes which
|
|
383
|
+
* sprint holds a task.
|
|
384
|
+
*/
|
|
385
|
+
export function buildSprintCompositionConfirmation(
|
|
386
|
+
action: SprintCompositionAction
|
|
387
|
+
): SprintCompositionConfirmation {
|
|
388
|
+
return {
|
|
389
|
+
action,
|
|
390
|
+
title: SPRINT_COMPOSITION_LABELS[action],
|
|
391
|
+
effect: SPRINT_COMPOSITION_EFFECT_COPY[action],
|
|
392
|
+
disclosures: (CROSS_SPRINT_DISCLOSURES[action] ?? []).map(truncateLine),
|
|
393
|
+
requiredConsentKeys: sprintCompositionRequiredConsentKeys(action),
|
|
394
|
+
crossSprint: requiresMembershipConsent(action),
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** The repository and project identity the request is bound to. */
|
|
399
|
+
export interface SprintCompositionSelection {
|
|
400
|
+
projectId: string;
|
|
401
|
+
sourceId: string;
|
|
402
|
+
repositoryPath: string;
|
|
403
|
+
branch: string | null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Form values as the operator left them. Every value is the raw string the
|
|
408
|
+
* control holds; an empty optional string is omitted from the request rather
|
|
409
|
+
* than sent as a default.
|
|
410
|
+
*/
|
|
411
|
+
export type SprintCompositionDraft =
|
|
412
|
+
| {
|
|
413
|
+
action: 'createSprint';
|
|
414
|
+
name: string;
|
|
415
|
+
start: string;
|
|
416
|
+
end: string;
|
|
417
|
+
goal: string;
|
|
418
|
+
hours: string;
|
|
419
|
+
}
|
|
420
|
+
| { action: 'renameSprint'; sprintId: string; name: string }
|
|
421
|
+
| {
|
|
422
|
+
action: 'addSprintWorkFromBacklog';
|
|
423
|
+
sprintId: string;
|
|
424
|
+
backlogItemId: string;
|
|
425
|
+
estimate: string;
|
|
426
|
+
expectedRuntimeMinutes: string;
|
|
427
|
+
priority: string;
|
|
428
|
+
}
|
|
429
|
+
| { action: 'removeSprintTask'; sprintId: string; taskId: string }
|
|
430
|
+
| {
|
|
431
|
+
action: 'migrateSprintTask';
|
|
432
|
+
taskId: string;
|
|
433
|
+
sourceSprintId: string;
|
|
434
|
+
targetSprintId: string;
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Canonical evidence the form reads. Nothing here is optional-with-a-default:
|
|
439
|
+
* a missing projection makes the affected control refuse rather than guess.
|
|
440
|
+
*/
|
|
441
|
+
export interface SprintCompositionCanonicalEvidence {
|
|
442
|
+
sprints: ListSprintsOutput;
|
|
443
|
+
/** The sprint the action names; the target sprint for a migration. */
|
|
444
|
+
sprint: GetSprintOutput | null;
|
|
445
|
+
/** The source sprint for a migration. */
|
|
446
|
+
sourceSprint: GetSprintOutput | null;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export type SprintCompositionDraftRefusalReason =
|
|
450
|
+
| 'incomplete'
|
|
451
|
+
| 'incomplete-consent'
|
|
452
|
+
| 'invalid-value'
|
|
453
|
+
| 'ambiguous-target'
|
|
454
|
+
| 'stale-membership';
|
|
455
|
+
|
|
456
|
+
export type SprintCompositionRequestDraft =
|
|
457
|
+
| { state: 'ready'; request: ApplySprintCompositionInput }
|
|
458
|
+
| {
|
|
459
|
+
state: 'refused';
|
|
460
|
+
reason: SprintCompositionDraftRefusalReason;
|
|
461
|
+
message: string;
|
|
462
|
+
/** Field ids the operator still has to resolve, when applicable. */
|
|
463
|
+
fieldIds: readonly string[];
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
type SprintCompositionDraftValues = Readonly<Record<string, string>>;
|
|
467
|
+
|
|
468
|
+
function trimmedDraftValues(draft: SprintCompositionDraft): SprintCompositionDraftValues {
|
|
469
|
+
const values: Record<string, string> = {};
|
|
470
|
+
for (const [key, value] of Object.entries(draft)) {
|
|
471
|
+
if (key === 'action') continue;
|
|
472
|
+
values[key] = typeof value === 'string' ? value.trim() : '';
|
|
473
|
+
}
|
|
474
|
+
return values;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** An absent field reads as empty text, never as `undefined`. */
|
|
478
|
+
function draftValue(values: SprintCompositionDraftValues, fieldId: string): string {
|
|
479
|
+
return values[fieldId] ?? '';
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function missingRequiredFieldIds(draft: SprintCompositionDraft): string[] {
|
|
483
|
+
const values = trimmedDraftValues(draft);
|
|
484
|
+
return sprintCompositionFormFields(draft.action)
|
|
485
|
+
.filter((field) => field.required && draftValue(values, field.id).length === 0)
|
|
486
|
+
.map((field) => field.id);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Optional numeric fields: an empty value is omitted, a bad value is refused. */
|
|
490
|
+
function optionalNumber(value: string): number | undefined | 'invalid' {
|
|
491
|
+
if (value.length === 0) return undefined;
|
|
492
|
+
const parsed = Number(value);
|
|
493
|
+
return Number.isFinite(parsed) ? parsed : 'invalid';
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function draftInput(
|
|
497
|
+
draft: SprintCompositionDraft
|
|
498
|
+
): { input: Record<string, unknown> } | { invalidFieldIds: string[] } {
|
|
499
|
+
const values = trimmedDraftValues(draft);
|
|
500
|
+
const invalidFieldIds: string[] = [];
|
|
501
|
+
const optional = (fieldId: string): number | undefined => {
|
|
502
|
+
const parsed = optionalNumber(draftValue(values, fieldId));
|
|
503
|
+
if (parsed === 'invalid') {
|
|
504
|
+
invalidFieldIds.push(fieldId);
|
|
505
|
+
return undefined;
|
|
506
|
+
}
|
|
507
|
+
return parsed;
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
let input: Record<string, unknown>;
|
|
511
|
+
switch (draft.action) {
|
|
512
|
+
case 'createSprint': {
|
|
513
|
+
const hours = optional('hours');
|
|
514
|
+
const goal = draftValue(values, 'goal');
|
|
515
|
+
input = {
|
|
516
|
+
name: draftValue(values, 'name'),
|
|
517
|
+
start: draftValue(values, 'start'),
|
|
518
|
+
end: draftValue(values, 'end'),
|
|
519
|
+
...(goal.length > 0 ? { goal } : {}),
|
|
520
|
+
...(hours === undefined ? {} : { hours }),
|
|
521
|
+
};
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
case 'renameSprint':
|
|
525
|
+
input = { sprintId: draftValue(values, 'sprintId'), name: draftValue(values, 'name') };
|
|
526
|
+
break;
|
|
527
|
+
case 'addSprintWorkFromBacklog': {
|
|
528
|
+
const estimate = Number(draftValue(values, 'estimate'));
|
|
529
|
+
if (!Number.isFinite(estimate)) invalidFieldIds.push('estimate');
|
|
530
|
+
const runtime = optional('expectedRuntimeMinutes');
|
|
531
|
+
const priority = draftValue(values, 'priority');
|
|
532
|
+
input = {
|
|
533
|
+
sprintId: draftValue(values, 'sprintId'),
|
|
534
|
+
backlogItemId: draftValue(values, 'backlogItemId'),
|
|
535
|
+
estimate,
|
|
536
|
+
...(runtime === undefined ? {} : { expectedRuntimeMinutes: runtime }),
|
|
537
|
+
...(priority.length > 0 ? { priority } : {}),
|
|
538
|
+
};
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
case 'removeSprintTask':
|
|
542
|
+
input = { sprintId: draftValue(values, 'sprintId'), taskId: draftValue(values, 'taskId') };
|
|
543
|
+
break;
|
|
544
|
+
case 'migrateSprintTask':
|
|
545
|
+
input = {
|
|
546
|
+
taskId: draftValue(values, 'taskId'),
|
|
547
|
+
sourceSprintId: draftValue(values, 'sourceSprintId'),
|
|
548
|
+
targetSprintId: draftValue(values, 'targetSprintId'),
|
|
549
|
+
};
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
return invalidFieldIds.length > 0 ? { invalidFieldIds } : { input };
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function membershipEvidence(
|
|
556
|
+
sprint: GetSprintOutput | null,
|
|
557
|
+
sprintId: string
|
|
558
|
+
): SprintCompositionEvidence<SprintStatusEnvelope> | null {
|
|
559
|
+
if (sprint === null || sprint.sprintId !== sprintId) return null;
|
|
560
|
+
return sprint.sprint;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Refuse a target BB cannot pin to canonical evidence, and a membership
|
|
565
|
+
* observation that no longer matches Poetic's own membership.
|
|
566
|
+
*
|
|
567
|
+
* A sprint id absent from the published sprint list is ambiguous, not simply
|
|
568
|
+
* wrong: BB will not submit a mutation against an identity Poetic has not
|
|
569
|
+
* confirmed. An unavailable list is ambiguous for the same reason.
|
|
570
|
+
*/
|
|
571
|
+
function targetRefusal(
|
|
572
|
+
draft: SprintCompositionDraft,
|
|
573
|
+
evidence: SprintCompositionCanonicalEvidence
|
|
574
|
+
): { reason: SprintCompositionDraftRefusalReason; message: string; fieldIds: string[] } | null {
|
|
575
|
+
const values = trimmedDraftValues(draft);
|
|
576
|
+
const list = evidence.sprints.sprints;
|
|
577
|
+
const knownSprintIds = list.state === 'available' ? list.value.sprints.map((s) => s.id) : null;
|
|
578
|
+
|
|
579
|
+
const sprintFields = sprintCompositionFormFields(draft.action).filter(
|
|
580
|
+
(field) =>
|
|
581
|
+
field.kind === 'sprint-id' ||
|
|
582
|
+
field.kind === 'source-sprint-id' ||
|
|
583
|
+
field.kind === 'target-sprint-id'
|
|
584
|
+
);
|
|
585
|
+
for (const field of sprintFields) {
|
|
586
|
+
const sprintId = draftValue(values, field.id);
|
|
587
|
+
if (knownSprintIds === null) {
|
|
588
|
+
return {
|
|
589
|
+
reason: 'ambiguous-target',
|
|
590
|
+
message: `Poetic did not publish a sprint list (${list.state === 'unavailable' ? list.reason : UNAVAILABLE}), so BB cannot confirm sprint ${sprintId} and will not submit.`,
|
|
591
|
+
fieldIds: [field.id],
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
if (!knownSprintIds.includes(sprintId)) {
|
|
595
|
+
return {
|
|
596
|
+
reason: 'ambiguous-target',
|
|
597
|
+
message: `Poetic does not list sprint ${sprintId}, so the ${field.label.toLowerCase()} is ambiguous and BB will not submit.`,
|
|
598
|
+
fieldIds: [field.id],
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (
|
|
604
|
+
draft.action === 'migrateSprintTask' &&
|
|
605
|
+
draftValue(values, 'sourceSprintId') === draftValue(values, 'targetSprintId')
|
|
606
|
+
) {
|
|
607
|
+
return {
|
|
608
|
+
reason: 'ambiguous-target',
|
|
609
|
+
message:
|
|
610
|
+
'The source sprint and the target sprint are the same sprint, so there is no migration to perform.',
|
|
611
|
+
fieldIds: ['sourceSprintId', 'targetSprintId'],
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (draft.action === 'removeSprintTask' || draft.action === 'migrateSprintTask') {
|
|
616
|
+
const isRemove = draft.action === 'removeSprintTask';
|
|
617
|
+
const sprintId = draftValue(values, isRemove ? 'sprintId' : 'sourceSprintId');
|
|
618
|
+
const taskId = draftValue(values, 'taskId');
|
|
619
|
+
const sprint = isRemove
|
|
620
|
+
? membershipEvidence(evidence.sprint, sprintId)
|
|
621
|
+
: membershipEvidence(evidence.sourceSprint, sprintId);
|
|
622
|
+
const fieldIds = isRemove ? ['taskId'] : ['taskId', 'sourceSprintId'];
|
|
623
|
+
if (sprint === null || sprint.state !== 'available') {
|
|
624
|
+
return {
|
|
625
|
+
reason: 'stale-membership',
|
|
626
|
+
message: `BB has no canonical membership for sprint ${sprintId}${sprint !== null && sprint.state === 'unavailable' ? ` (${sprint.reason})` : ''}, so it will not submit a membership change it cannot confirm.`,
|
|
627
|
+
fieldIds,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
const state = sprintMembershipState(sprint.value, taskId);
|
|
631
|
+
if (state !== 'present') {
|
|
632
|
+
return {
|
|
633
|
+
reason: 'stale-membership',
|
|
634
|
+
message:
|
|
635
|
+
state === 'missing-reference'
|
|
636
|
+
? `Sprint ${sprintId} references task ${taskId} as a task id with no resolvable task file, so BB will not submit.`
|
|
637
|
+
: `Poetic does not list task ${taskId} as a member of sprint ${sprintId}, so the membership you are looking at is stale.`,
|
|
638
|
+
fieldIds,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/** Membership as last read, so BPAU-03 can refuse a drifted submission. */
|
|
646
|
+
function observedMembership(
|
|
647
|
+
draft: SprintCompositionDraft,
|
|
648
|
+
evidence: SprintCompositionCanonicalEvidence
|
|
649
|
+
): string[] {
|
|
650
|
+
const values = trimmedDraftValues(draft);
|
|
651
|
+
if (draft.action === 'removeSprintTask') {
|
|
652
|
+
const sprint = membershipEvidence(evidence.sprint, draftValue(values, 'sprintId'));
|
|
653
|
+
return sprint !== null && sprint.state === 'available' ? sprintMembershipIds(sprint.value) : [];
|
|
654
|
+
}
|
|
655
|
+
if (draft.action === 'migrateSprintTask') {
|
|
656
|
+
const sprint = membershipEvidence(evidence.sourceSprint, draftValue(values, 'sourceSprintId'));
|
|
657
|
+
return sprint !== null && sprint.state === 'available' ? sprintMembershipIds(sprint.value) : [];
|
|
658
|
+
}
|
|
659
|
+
return [];
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Convert a confirmed draft into exactly one typed BPAU-03 request.
|
|
664
|
+
*
|
|
665
|
+
* The request is produced by the BPAU-03 schema itself, so this cannot smuggle a
|
|
666
|
+
* field the lane does not accept, and a value Poetic would refuse is refused
|
|
667
|
+
* here instead of being sent. Consent conversion is BPAU-03's, so a disabled
|
|
668
|
+
* submit control and a refused submission always agree.
|
|
669
|
+
*/
|
|
670
|
+
export function buildSprintCompositionRequest(input: {
|
|
671
|
+
draft: SprintCompositionDraft;
|
|
672
|
+
consent: SprintCompositionConsentState;
|
|
673
|
+
selection: SprintCompositionSelection;
|
|
674
|
+
evidence: SprintCompositionCanonicalEvidence;
|
|
675
|
+
}): SprintCompositionRequestDraft {
|
|
676
|
+
const { draft, consent, selection, evidence } = input;
|
|
677
|
+
|
|
678
|
+
const missing = missingRequiredFieldIds(draft);
|
|
679
|
+
if (missing.length > 0) {
|
|
680
|
+
return {
|
|
681
|
+
state: 'refused',
|
|
682
|
+
reason: 'incomplete',
|
|
683
|
+
message: 'Every required identity and value must be selected explicitly before submitting.',
|
|
684
|
+
fieldIds: missing,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const built = draftInput(draft);
|
|
689
|
+
if ('invalidFieldIds' in built) {
|
|
690
|
+
return {
|
|
691
|
+
state: 'refused',
|
|
692
|
+
reason: 'invalid-value',
|
|
693
|
+
message: 'A numeric field does not hold a number, so BB will not submit it.',
|
|
694
|
+
fieldIds: built.invalidFieldIds,
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const ambiguity = targetRefusal(draft, evidence);
|
|
699
|
+
if (ambiguity !== null) {
|
|
700
|
+
return {
|
|
701
|
+
state: 'refused',
|
|
702
|
+
reason: ambiguity.reason,
|
|
703
|
+
message: truncateLine(ambiguity.message),
|
|
704
|
+
fieldIds: ambiguity.fieldIds,
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const consentPayload = sprintCompositionConsentPayload(draft.action, consent);
|
|
709
|
+
if (consentPayload === null) {
|
|
710
|
+
return {
|
|
711
|
+
state: 'refused',
|
|
712
|
+
reason: 'incomplete-consent',
|
|
713
|
+
message: 'Every consent line this action requires must be acknowledged before submitting.',
|
|
714
|
+
fieldIds: [],
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
const candidate = {
|
|
719
|
+
projectId: selection.projectId,
|
|
720
|
+
sourceId: selection.sourceId,
|
|
721
|
+
action: draft.action,
|
|
722
|
+
input: built.input,
|
|
723
|
+
consent: consentPayload,
|
|
724
|
+
expected: {
|
|
725
|
+
repositoryPath: selection.repositoryPath,
|
|
726
|
+
branch: selection.branch,
|
|
727
|
+
entityIds: [] as string[],
|
|
728
|
+
observedMembership: observedMembership(draft, evidence),
|
|
729
|
+
},
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
const parsed = applySprintCompositionInputSchema.safeParse(candidate);
|
|
733
|
+
if (!parsed.success) {
|
|
734
|
+
return {
|
|
735
|
+
state: 'refused',
|
|
736
|
+
reason: 'invalid-value',
|
|
737
|
+
message: `Poetic's sprint-composition contract refused this input: ${parsed.error.issues[0]?.message ?? 'invalid request'}`,
|
|
738
|
+
fieldIds: parsed.error.issues.flatMap((issue) =>
|
|
739
|
+
issue.path.length > 0 ? [String(issue.path[issue.path.length - 1])] : []
|
|
740
|
+
),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// The declared identities come from BPAU-03's own derivation, so consent and
|
|
745
|
+
// the request always name the same entities.
|
|
746
|
+
const identities = [...new Set(sprintCompositionRequestedIdentities(parsed.data))];
|
|
747
|
+
const withIdentities = applySprintCompositionInputSchema.safeParse({
|
|
748
|
+
...candidate,
|
|
749
|
+
expected: { ...candidate.expected, entityIds: identities },
|
|
750
|
+
});
|
|
751
|
+
if (!withIdentities.success) {
|
|
752
|
+
return {
|
|
753
|
+
state: 'refused',
|
|
754
|
+
reason: 'invalid-value',
|
|
755
|
+
message: 'The declared identities did not satisfy the sprint-composition contract.',
|
|
756
|
+
fieldIds: [],
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
return { state: 'ready', request: withIdentities.data };
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/* ------------------------------------------------------------------ *
|
|
763
|
+
* Prohibited actions
|
|
764
|
+
* ------------------------------------------------------------------ */
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Controls this lane deliberately does not offer. They are named so a refusal
|
|
768
|
+
* is explicit rather than a control that silently does nothing.
|
|
769
|
+
*/
|
|
770
|
+
export const SPRINT_COMPOSITION_PROHIBITED_ACTIONS = [
|
|
771
|
+
'createCustomTask',
|
|
772
|
+
'completeSprint',
|
|
773
|
+
'closeSprint',
|
|
774
|
+
'tidySprint',
|
|
775
|
+
'unlockSprint',
|
|
776
|
+
'pruneMissingTasks',
|
|
777
|
+
'runSprint',
|
|
778
|
+
'applySprint',
|
|
779
|
+
'splitTask',
|
|
780
|
+
'selectProvider',
|
|
781
|
+
'selectModel',
|
|
782
|
+
'bulkSchedule',
|
|
783
|
+
'dragAndDropSchedule',
|
|
784
|
+
'forceMutation',
|
|
785
|
+
'dryRun',
|
|
786
|
+
'suppressSync',
|
|
787
|
+
] as const;
|
|
788
|
+
|
|
789
|
+
export type SprintCompositionProhibitedAction =
|
|
790
|
+
(typeof SPRINT_COMPOSITION_PROHIBITED_ACTIONS)[number];
|
|
791
|
+
|
|
792
|
+
const PROHIBITED_NOTICES: Readonly<Record<SprintCompositionProhibitedAction, string>> = {
|
|
793
|
+
createCustomTask:
|
|
794
|
+
'Creating a custom task is a different product and is not offered here. "Add from backlog" creates a task from an existing backlog item.',
|
|
795
|
+
completeSprint: 'Completing a sprint is not offered here.',
|
|
796
|
+
closeSprint: 'Closing a sprint is not offered here.',
|
|
797
|
+
tidySprint: 'Tidying a sprint is not offered here.',
|
|
798
|
+
unlockSprint: 'Unlocking a sprint is not offered here.',
|
|
799
|
+
pruneMissingTasks:
|
|
800
|
+
'Repairing sprint integrity is not offered here. BB reports missing task references and does not prune them.',
|
|
801
|
+
runSprint: 'Sprint execution is not offered here. This surface only composes sprints.',
|
|
802
|
+
applySprint: 'Applying sprint results is not offered here.',
|
|
803
|
+
splitTask: 'Splitting work is not offered here.',
|
|
804
|
+
selectProvider: 'Provider selection is not offered here.',
|
|
805
|
+
selectModel: 'Model selection is not offered here.',
|
|
806
|
+
bulkSchedule:
|
|
807
|
+
'Bulk scheduling is not offered here. Each action names its own sprint, task, and backlog identities.',
|
|
808
|
+
dragAndDropSchedule:
|
|
809
|
+
'Drag-and-drop scheduling is not offered here: presentation never changes before Poetic confirms the change.',
|
|
810
|
+
forceMutation: 'BB never passes --force.',
|
|
811
|
+
dryRun: 'BB never passes --dry-run.',
|
|
812
|
+
suppressSync: "BB never passes --no-sync: Poetic's managed sync always runs.",
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
export function isSprintCompositionAction(value: string): value is SprintCompositionAction {
|
|
816
|
+
return (SPRINT_COMPOSITION_VOCABULARY as readonly string[]).includes(value);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Explicit refusal for anything outside the closed vocabulary. A named excluded
|
|
821
|
+
* control gets its own reason; anything else is refused as out of vocabulary.
|
|
822
|
+
*/
|
|
823
|
+
export function sprintCompositionProhibitedRefusal(
|
|
824
|
+
requestedAction: string
|
|
825
|
+
): { action: string; message: string } | null {
|
|
826
|
+
if (isSprintCompositionAction(requestedAction)) return null;
|
|
827
|
+
const known = (SPRINT_COMPOSITION_PROHIBITED_ACTIONS as readonly string[]).includes(
|
|
828
|
+
requestedAction
|
|
829
|
+
);
|
|
830
|
+
return {
|
|
831
|
+
action: requestedAction,
|
|
832
|
+
message: truncateLine(
|
|
833
|
+
known
|
|
834
|
+
? PROHIBITED_NOTICES[requestedAction as SprintCompositionProhibitedAction]
|
|
835
|
+
: `"${requestedAction}" is not a sprint-composition action, so BB will not submit it.`
|
|
836
|
+
),
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/** Every excluded control, as notices for the surface to render. */
|
|
841
|
+
export function sprintCompositionProhibitedNotices(): readonly string[] {
|
|
842
|
+
return SPRINT_COMPOSITION_PROHIBITED_ACTIONS.map((action) =>
|
|
843
|
+
truncateLine(PROHIBITED_NOTICES[action])
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/* ------------------------------------------------------------------ *
|
|
848
|
+
* Outcome presentation
|
|
849
|
+
* ------------------------------------------------------------------ */
|
|
850
|
+
|
|
851
|
+
export type SprintCompositionOutcomeState =
|
|
852
|
+
| 'applied'
|
|
853
|
+
| 'applied-incomplete'
|
|
854
|
+
| 'overlap-conflict'
|
|
855
|
+
| 'refused'
|
|
856
|
+
| 'partial-effect'
|
|
857
|
+
| 'unknown';
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* Overlap recovery as Poetic published it. Recovery is a Poetic CLI action, so
|
|
861
|
+
* this carries guidance only and offers no BB control.
|
|
862
|
+
*/
|
|
863
|
+
export interface SprintCompositionOverlapRecovery {
|
|
864
|
+
conflictingSprintId: string | null;
|
|
865
|
+
guidance: string;
|
|
866
|
+
/** Recovery is never a BB control. */
|
|
867
|
+
control: null;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export interface SprintCompositionOutcomeView {
|
|
871
|
+
action: SprintCompositionAction;
|
|
872
|
+
actionLabel: string;
|
|
873
|
+
state: SprintCompositionOutcomeState;
|
|
874
|
+
headline: string;
|
|
875
|
+
rows: readonly SprintCompositionRow[];
|
|
876
|
+
notes: readonly string[];
|
|
877
|
+
/** Present only for a create that Poetic refused as an overlap. */
|
|
878
|
+
recovery: SprintCompositionOverlapRecovery | null;
|
|
879
|
+
/** True when the reported effect is not a clean applied outcome. */
|
|
880
|
+
degraded: boolean;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
const OUTCOME_STATES: Readonly<
|
|
884
|
+
Record<ApplySprintCompositionOutput['effect']['phase'], SprintCompositionOutcomeState>
|
|
885
|
+
> = {
|
|
886
|
+
applied: 'applied',
|
|
887
|
+
'applied-incomplete': 'applied-incomplete',
|
|
888
|
+
'overlap-conflict': 'overlap-conflict',
|
|
889
|
+
'refused-before-launch': 'refused',
|
|
890
|
+
'refused-before-effect': 'refused',
|
|
891
|
+
'failed-after-partial-effect': 'partial-effect',
|
|
892
|
+
'unknown-after-timeout': 'unknown',
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
const OUTCOME_HEADLINES: Readonly<Record<SprintCompositionOutcomeState, string>> = {
|
|
896
|
+
applied: 'applied',
|
|
897
|
+
'applied-incomplete': 'applied, with unconfirmed effects',
|
|
898
|
+
'overlap-conflict': 'refused: sprint dates overlap an existing sprint',
|
|
899
|
+
refused: 'refused; nothing changed',
|
|
900
|
+
'partial-effect': 'failed after a partial effect',
|
|
901
|
+
unknown: 'outcome unknown',
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Resulting task status from the authoritative reread only. A status BB could not
|
|
906
|
+
* reread is unavailable; it is never predicted from the action that just ran.
|
|
907
|
+
*/
|
|
908
|
+
function taskStatusRowValue(
|
|
909
|
+
evidence: SprintCompositionEvidence<GetTaskDetailOutput> | undefined
|
|
910
|
+
): string {
|
|
911
|
+
if (evidence === undefined) return UNAVAILABLE;
|
|
912
|
+
if (evidence.state !== 'available') return `${UNAVAILABLE}: ${evidence.reason}`;
|
|
913
|
+
const task = evidence.value.task;
|
|
914
|
+
if (task.state === 'missing') return 'missing';
|
|
915
|
+
if (task.state === 'unavailable') return `${UNAVAILABLE}: ${task.reason}`;
|
|
916
|
+
return formatOptional(task.value.status);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
function overlapRecovery(
|
|
920
|
+
outcome: ApplySprintCompositionOutput
|
|
921
|
+
): SprintCompositionOverlapRecovery | null {
|
|
922
|
+
const identity = outcome.identityOutcome;
|
|
923
|
+
if (identity === null || identity.kind !== 'sprintCreateV1') return null;
|
|
924
|
+
if (identity.value.state !== 'overlap-conflict') return null;
|
|
925
|
+
return {
|
|
926
|
+
conflictingSprintId: identity.value.conflictingSprintId ?? null,
|
|
927
|
+
guidance: truncateLine(
|
|
928
|
+
identity.value.recoveryText ??
|
|
929
|
+
'Poetic published no recovery text for this overlap. Choose dates that do not overlap the conflicting sprint, or resolve the overlap with the Poetic CLI.'
|
|
930
|
+
),
|
|
931
|
+
control: null,
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
function commandNotes(outcome: ApplySprintCompositionOutput): string[] {
|
|
936
|
+
const notes: string[] = [];
|
|
937
|
+
switch (outcome.command.state) {
|
|
938
|
+
case 'timed_out':
|
|
939
|
+
notes.push(
|
|
940
|
+
'Poetic did not answer before this action timed out. Nothing was retried, and whether the change applied is unknown until you reread the sprint.'
|
|
941
|
+
);
|
|
942
|
+
break;
|
|
943
|
+
case 'failed':
|
|
944
|
+
notes.push(
|
|
945
|
+
`Poetic reported a failure${outcome.command.exitCode === null ? '' : ` (exit ${outcome.command.exitCode})`}${outcome.command.diagnostics === null ? '.' : `: ${outcome.command.diagnostics}`}`
|
|
946
|
+
);
|
|
947
|
+
break;
|
|
948
|
+
case 'ambiguous':
|
|
949
|
+
notes.push(
|
|
950
|
+
"Poetic's answer was ambiguous: BB could not establish what changed and reports neither success nor failure."
|
|
951
|
+
);
|
|
952
|
+
break;
|
|
953
|
+
default:
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
// Only the two identity-minting actions publish a BPAU-00B envelope, so a
|
|
957
|
+
// missing envelope is a gap for those and expected for the other three.
|
|
958
|
+
if (
|
|
959
|
+
outcome.identityOutcome === null &&
|
|
960
|
+
requiresNewIdentityConsent(outcome.action) &&
|
|
961
|
+
outcome.command.state !== 'failed'
|
|
962
|
+
) {
|
|
963
|
+
notes.push(
|
|
964
|
+
'Poetic published no structured identity evidence for this action, so BB reports the effect as unconfirmed rather than substituting the newest sprint it can see.'
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
if (outcome.sync.state !== 'remote_verified') {
|
|
968
|
+
notes.push(
|
|
969
|
+
'A zero exit code is not proof of a remote push. The sync state above is what Poetic reported on a fresh reread.'
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
return notes;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Render one BPAU-03 outcome. Every value comes from the outcome record: the
|
|
977
|
+
* effect phase is reported, never inferred from the exit code, and the resulting
|
|
978
|
+
* status comes from the authoritative reread rather than from a prediction.
|
|
979
|
+
*/
|
|
980
|
+
export function buildSprintCompositionOutcomeView(
|
|
981
|
+
outcome: ApplySprintCompositionOutput
|
|
982
|
+
): SprintCompositionOutcomeView {
|
|
983
|
+
const state = OUTCOME_STATES[outcome.effect.phase];
|
|
984
|
+
const label = SPRINT_COMPOSITION_LABELS[outcome.action];
|
|
985
|
+
const rows: SprintCompositionRow[] = [
|
|
986
|
+
row('outcome-action', 'Action', label),
|
|
987
|
+
row('outcome-phase', 'Effect', outcome.effect.phase),
|
|
988
|
+
row(
|
|
989
|
+
'outcome-created',
|
|
990
|
+
'Created identities',
|
|
991
|
+
formatIdentities(outcome.effect.createdIdentities)
|
|
992
|
+
),
|
|
993
|
+
row(
|
|
994
|
+
'outcome-affected',
|
|
995
|
+
'Affected identities',
|
|
996
|
+
formatIdentities(outcome.effect.affectedIdentities)
|
|
997
|
+
),
|
|
998
|
+
row('outcome-requested', 'Requested identities', formatIdentities(outcome.requestedIdentities)),
|
|
999
|
+
row(
|
|
1000
|
+
'outcome-command',
|
|
1001
|
+
'Poetic command',
|
|
1002
|
+
`${outcome.command.state}, exit ${outcome.command.exitCode === null ? UNAVAILABLE : outcome.command.exitCode}, ${outcome.command.attempts} attempt`
|
|
1003
|
+
),
|
|
1004
|
+
row(
|
|
1005
|
+
'outcome-sync',
|
|
1006
|
+
'Planning sync',
|
|
1007
|
+
`${outcome.sync.state}${outcome.sync.detail === null ? '' : `: ${outcome.sync.detail}`}`
|
|
1008
|
+
),
|
|
1009
|
+
row(
|
|
1010
|
+
'outcome-task-status',
|
|
1011
|
+
'Task status (canonical reread)',
|
|
1012
|
+
taskStatusRowValue(outcome.canonicalRereads.task)
|
|
1013
|
+
),
|
|
1014
|
+
];
|
|
1015
|
+
|
|
1016
|
+
const identity = outcome.identityOutcome;
|
|
1017
|
+
if (identity !== null && identity.kind === 'sprintAddTaskV1') {
|
|
1018
|
+
rows.push(
|
|
1019
|
+
row(
|
|
1020
|
+
'outcome-add-capacity',
|
|
1021
|
+
'Sprint capacity after add',
|
|
1022
|
+
`${identity.value.capacity.allocatedHours ?? UNAVAILABLE} of ${identity.value.capacity.totalHours ?? UNAVAILABLE} hours (Poetic-reported)`
|
|
1023
|
+
),
|
|
1024
|
+
row(
|
|
1025
|
+
'outcome-add-estimate',
|
|
1026
|
+
'Estimate applied',
|
|
1027
|
+
`${identity.value.estimatedHours} hours from ${identity.value.estimateSource}`
|
|
1028
|
+
)
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
const recovery = overlapRecovery(outcome);
|
|
1033
|
+
if (recovery !== null) {
|
|
1034
|
+
rows.push(
|
|
1035
|
+
row(
|
|
1036
|
+
'outcome-conflicting-sprint',
|
|
1037
|
+
'Conflicting sprint',
|
|
1038
|
+
recovery.conflictingSprintId ?? UNAVAILABLE
|
|
1039
|
+
),
|
|
1040
|
+
row('outcome-recovery', 'Recovery', recovery.guidance)
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return {
|
|
1045
|
+
action: outcome.action,
|
|
1046
|
+
actionLabel: label,
|
|
1047
|
+
state,
|
|
1048
|
+
headline: truncateLine(`${label} ${OUTCOME_HEADLINES[state]}`),
|
|
1049
|
+
rows,
|
|
1050
|
+
notes: [...outcome.integrityNotes, ...outcome.syncWarnings, ...commandNotes(outcome)].map(
|
|
1051
|
+
truncateLine
|
|
1052
|
+
),
|
|
1053
|
+
recovery,
|
|
1054
|
+
degraded: state !== 'applied',
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/* ------------------------------------------------------------------ *
|
|
1059
|
+
* Composed view
|
|
1060
|
+
* ------------------------------------------------------------------ */
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* Presentation phase.
|
|
1064
|
+
*
|
|
1065
|
+
* `awaiting-poetic` renders the pre-submission evidence unchanged: BB shows no
|
|
1066
|
+
* optimistic membership, capacity, or status while a submission is in flight.
|
|
1067
|
+
*/
|
|
1068
|
+
export type SprintCompositionPhase =
|
|
1069
|
+
| { kind: 'idle' }
|
|
1070
|
+
| { kind: 'awaiting-poetic'; request: ApplySprintCompositionInput }
|
|
1071
|
+
| { kind: 'settled'; outcome: ApplySprintCompositionOutput };
|
|
1072
|
+
|
|
1073
|
+
export interface SprintCompositionSubmitControl {
|
|
1074
|
+
id: 'submit';
|
|
1075
|
+
label: string;
|
|
1076
|
+
enabled: boolean;
|
|
1077
|
+
/** Null only when the control is enabled. */
|
|
1078
|
+
disabledReason: string | null;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
export interface SprintCompositionView {
|
|
1082
|
+
viewVersion: typeof SPRINT_COMPOSITION_VIEW_VERSION;
|
|
1083
|
+
outcomeVersion: typeof SPRINT_COMPOSITION_OUTCOME_VERSION;
|
|
1084
|
+
phase: SprintCompositionPhase['kind'];
|
|
1085
|
+
action: SprintCompositionAction;
|
|
1086
|
+
actionLabel: string;
|
|
1087
|
+
headline: string;
|
|
1088
|
+
/** Poetic's own lane disclosure, carried verbatim. */
|
|
1089
|
+
disclosure: typeof SPRINT_COMPOSITION_DISCLOSURE;
|
|
1090
|
+
fields: readonly SprintCompositionFormField[];
|
|
1091
|
+
confirmation: SprintCompositionConfirmation;
|
|
1092
|
+
submit: SprintCompositionSubmitControl;
|
|
1093
|
+
/** The single typed request a confirmed draft would emit; null otherwise. */
|
|
1094
|
+
request: ApplySprintCompositionInput | null;
|
|
1095
|
+
/** Why the draft cannot be submitted, when it cannot. */
|
|
1096
|
+
refusal: Extract<SprintCompositionRequestDraft, { state: 'refused' }> | null;
|
|
1097
|
+
sprints: SprintCompositionListView;
|
|
1098
|
+
sprint: SprintCompositionSprintView | null;
|
|
1099
|
+
sourceSprint: SprintCompositionSprintView | null;
|
|
1100
|
+
outcome: SprintCompositionOutcomeView | null;
|
|
1101
|
+
/** True while BB is waiting for Poetic's reread. */
|
|
1102
|
+
awaitingCanonicalReread: boolean;
|
|
1103
|
+
notes: readonly string[];
|
|
1104
|
+
prohibited: readonly string[];
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
export interface SprintCompositionViewInput {
|
|
1108
|
+
phase: SprintCompositionPhase;
|
|
1109
|
+
selection: SprintCompositionSelection;
|
|
1110
|
+
draft: SprintCompositionDraft;
|
|
1111
|
+
consent: SprintCompositionConsentState;
|
|
1112
|
+
evidence: SprintCompositionCanonicalEvidence;
|
|
1113
|
+
/** True when a submission for this scope is already in flight. */
|
|
1114
|
+
submissionInFlight?: boolean;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
function sprintViewFor(output: GetSprintOutput | null): SprintCompositionSprintView | null {
|
|
1118
|
+
return output === null ? null : buildSprintCompositionSprintViewFromOutput(output);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Sprint views after a settled submission come from the outcome's own rereads,
|
|
1123
|
+
* which are the authority for the resulting composition. A member the reread
|
|
1124
|
+
* could not supply stays explicitly unavailable.
|
|
1125
|
+
*/
|
|
1126
|
+
function settledSprintViews(outcome: ApplySprintCompositionOutput): {
|
|
1127
|
+
sprint: SprintCompositionSprintView | null;
|
|
1128
|
+
sourceSprint: SprintCompositionSprintView | null;
|
|
1129
|
+
} {
|
|
1130
|
+
const rereads = outcome.canonicalRereads;
|
|
1131
|
+
const primary = rereads.targetSprint ?? rereads.sprint;
|
|
1132
|
+
const primaryId =
|
|
1133
|
+
primary !== undefined && primary.state === 'available' ? primary.value.sprintId : UNAVAILABLE;
|
|
1134
|
+
const sourceId =
|
|
1135
|
+
rereads.sourceSprint !== undefined && rereads.sourceSprint.state === 'available'
|
|
1136
|
+
? rereads.sourceSprint.value.sprintId
|
|
1137
|
+
: UNAVAILABLE;
|
|
1138
|
+
return {
|
|
1139
|
+
sprint: primary === undefined ? null : buildSprintCompositionSprintView(primaryId, primary),
|
|
1140
|
+
sourceSprint:
|
|
1141
|
+
rereads.sourceSprint === undefined
|
|
1142
|
+
? null
|
|
1143
|
+
: buildSprintCompositionSprintView(sourceId, rereads.sourceSprint),
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Build the whole sprint-composition surface for one phase.
|
|
1149
|
+
*
|
|
1150
|
+
* Deterministic in its inputs: the same evidence and draft always render the
|
|
1151
|
+
* same view, and no field is derived from anything other than those inputs.
|
|
1152
|
+
*/
|
|
1153
|
+
export function buildSprintCompositionView(
|
|
1154
|
+
input: SprintCompositionViewInput
|
|
1155
|
+
): SprintCompositionView {
|
|
1156
|
+
const { phase, draft, consent, selection, evidence } = input;
|
|
1157
|
+
const action = draft.action;
|
|
1158
|
+
const label = SPRINT_COMPOSITION_LABELS[action];
|
|
1159
|
+
const inFlight = input.submissionInFlight === true || phase.kind === 'awaiting-poetic';
|
|
1160
|
+
|
|
1161
|
+
const draftResult = buildSprintCompositionRequest({ draft, consent, selection, evidence });
|
|
1162
|
+
const refusal = draftResult.state === 'refused' ? draftResult : null;
|
|
1163
|
+
|
|
1164
|
+
const disabledReason = inFlight
|
|
1165
|
+
? 'A sprint-composition submission is already in flight for this action. BB submits it once and waits for Poetic.'
|
|
1166
|
+
: (refusal?.message ?? null);
|
|
1167
|
+
|
|
1168
|
+
const listView = buildSprintListView(evidence.sprints);
|
|
1169
|
+
const settled = phase.kind === 'settled' ? settledSprintViews(phase.outcome) : null;
|
|
1170
|
+
const outcomeView =
|
|
1171
|
+
phase.kind === 'settled' ? buildSprintCompositionOutcomeView(phase.outcome) : null;
|
|
1172
|
+
|
|
1173
|
+
const notes: string[] = [];
|
|
1174
|
+
if (phase.kind === 'awaiting-poetic') {
|
|
1175
|
+
notes.push(
|
|
1176
|
+
'Waiting for Poetic. The composition shown below is the evidence read before this submission; nothing changes until Poetic answers and BB rereads.'
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
if (settled !== null) {
|
|
1180
|
+
notes.push(
|
|
1181
|
+
'The composition shown below comes from the reread Poetic answered with after this action.'
|
|
1182
|
+
);
|
|
1183
|
+
if (settled.sprint === null && settled.sourceSprint === null) {
|
|
1184
|
+
notes.push(
|
|
1185
|
+
'Poetic supplied no sprint reread for this action, so the resulting composition is unavailable.'
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
return {
|
|
1191
|
+
viewVersion: SPRINT_COMPOSITION_VIEW_VERSION,
|
|
1192
|
+
outcomeVersion: SPRINT_COMPOSITION_OUTCOME_VERSION,
|
|
1193
|
+
phase: phase.kind,
|
|
1194
|
+
action,
|
|
1195
|
+
actionLabel: label,
|
|
1196
|
+
headline:
|
|
1197
|
+
outcomeView !== null
|
|
1198
|
+
? outcomeView.headline
|
|
1199
|
+
: phase.kind === 'awaiting-poetic'
|
|
1200
|
+
? `${label}: waiting for Poetic`
|
|
1201
|
+
: `${label}: review and confirm`,
|
|
1202
|
+
disclosure: SPRINT_COMPOSITION_DISCLOSURE,
|
|
1203
|
+
fields: sprintCompositionFormFields(action),
|
|
1204
|
+
confirmation: buildSprintCompositionConfirmation(action),
|
|
1205
|
+
submit: {
|
|
1206
|
+
id: 'submit',
|
|
1207
|
+
label,
|
|
1208
|
+
enabled: disabledReason === null,
|
|
1209
|
+
disabledReason,
|
|
1210
|
+
},
|
|
1211
|
+
request: phase.kind === 'idle' && draftResult.state === 'ready' ? draftResult.request : null,
|
|
1212
|
+
refusal,
|
|
1213
|
+
sprints: listView,
|
|
1214
|
+
sprint: settled === null ? sprintViewFor(evidence.sprint) : settled.sprint,
|
|
1215
|
+
sourceSprint: settled === null ? sprintViewFor(evidence.sourceSprint) : settled.sourceSprint,
|
|
1216
|
+
outcome: outcomeView,
|
|
1217
|
+
awaitingCanonicalReread: phase.kind === 'awaiting-poetic',
|
|
1218
|
+
notes: notes.map(truncateLine),
|
|
1219
|
+
prohibited: sprintCompositionProhibitedNotices(),
|
|
1220
|
+
};
|
|
1221
|
+
}
|