elanous 0.2.35 → 0.2.37
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/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → 8kITumG9GAZ1LwT9POrAR}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/1041-5841aae848fb6403.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{9952.5daf5f94063a2b3e.js → 1262.a89bb27a5b2f844e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1746.3563617ea64023a3.js +115 -0
- package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1dc5a567.9b092bfae3d7099b.js → 1ed5e8af.cf424815c7c0efad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4705-194e64e47ca0fbdb.js → 2002-a43a3f380df873ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{13.02a07436dec15f89.js → 210.90b2cbd64926cf34.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9512.5a76207a730e0491.js → 2283.edd9627b7bdfb546.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{6866-79aa5b4e47cac6aa.js → 2318-450e75d07605b8fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{938.66ad1ef0e5abae1c.js → 2375.bf364c85dbb6f085.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +148 -0
- package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +27 -0
- package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9214.63a510d39178e997.js → 3578.4e9f9948a9a6f2f4.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +36 -0
- package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +90 -0
- package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +226 -0
- package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +287 -0
- package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2018.a741297bce759490.js → 4313.76f232c304a15bde.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1165.bad13fc9151a7288.js → 4324.c99ba3e83eb1b691.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3f7c4ee5.3dde54f01a816613.js → 4337e36d.f42c3b391b3d8f20.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7385.50a308a477bdfc21.js → 4383.18e5c54db3a22c88.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8557-e7898769499cd56f.js → 4725-34bed25720cc326b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5483-dd5d7697f6bdb106.js → 4833-7934c592c5569f00.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{8444.4c26b379ca2b9596.js → 4931.95cc6dbd230774ca.js} +17 -17
- package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3408.21d1570602f4b6c0.js → 5046.7fd5cbd859299448.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +1 -0
- package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/58edce7d.f1b0c72acf13b123.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b6705a4f-b9a9047de9eecfd0.js → 5f6af561-f90b7a67f4f75d13.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6252.240578f10952e091.js +34 -0
- package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5101.e32282718f99ed6f.js → 6680.6a693c28aae4cd19.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4718-17d2af636796a330.js → 6745-5a63492933959dd9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{6236.e18cced2d5ba6afb.js → 6819.be5c9c4d67f22922.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2833-0fe47af99ed13c29.js → 6971-fb5f9dc0a2cb5d2d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{da5176c6.6773b6c5994e1d99.js → 709a918c.4fd3b4e2a32cb4e3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +41 -0
- package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7424.c0fe2a595d4232b5.js +23 -0
- package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +1 -0
- package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7644.17e37ba6f1d4226e.js → 7867.e8725745ddd1d940.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{0368f25d-ad84af92fefee68f.js → 7c5ed21f-f286708e57cf88f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{359-2250789a2d3499e7.js → 8080-40d781e7704d3671.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +77 -0
- package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +1 -0
- package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +286 -0
- package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +79 -0
- package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b2f6ba4d.fb56fdbbf798df33.js → 8c58d09b.e8724a299658d86f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1530.0e612369b6fd7ea0.js → 9151.a2c51e93f9156dae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4441-875b97f5821ed58a.js → 9175-7d383df15a82e2be.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +1 -0
- package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +94 -0
- package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +1 -0
- package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +64 -0
- package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-3337c6a1328c2674.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-47c5d4db587266bd.js → page-1e5da297557d2354.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-1f5a60f70cb4dd0c.js → page-88a1edbff62eaf1d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-bac7dee94e5eae4a.js → page-443364c9e4a23b31.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-dc0a532f5b9196ec.js → page-ac2c1e6169cfce57.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c1c80e345fa9d6f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d06f9160.a3d9062f95de8ad7.js → d9815f84.4918f682a45a8502.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{cbe38a15.5a032598e39970c6.js → de8446d3.31b73eb239fecd7b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +1 -0
- package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
- package/docs/goal-context/README.md +3 -0
- package/graphs/default-loop.yaml +6 -1
- package/graphs/drafts/recipes.yaml +27 -7
- package/graphs/implement-loop.yaml +24 -0
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +17 -4
- package/graphs/wizard/recipes.yaml +44 -0
- package/graphs/wizard/wizard-loop.yaml +44 -0
- package/graphs/work/draft-close.yaml +54 -0
- package/graphs/work/green-close.yaml +37 -0
- package/graphs/work/recipes.yaml +46 -1
- package/graphs/work/research-report.yaml +2 -0
- package/graphs/work/run-research.yaml +35 -0
- package/package.json +1 -1
- package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
- package/scripts/boundary-proof-mapping-audit.ts +88 -0
- package/scripts/ci-typecheck-changed.ts +139 -5
- package/scripts/codex-fallback-live-probe.ts +17 -15
- package/scripts/coord-role-pack.ts +1 -1
- package/scripts/first10-gate.ts +416 -0
- package/scripts/fleet/node-setup.sh +32 -2
- package/scripts/fleet/run-light-worker.sh +9 -0
- package/scripts/fleet/wsl-node-setup.sh +432 -0
- package/scripts/gate-0226-failure-census.ts +507 -0
- package/scripts/goals/authoring-metrics.ts +258 -0
- package/scripts/graph-units/draft-close-node.ts +222 -0
- package/scripts/hook-order-sweep.ts +7 -4
- package/scripts/land-global-checks.ts +69 -1
- package/scripts/measure-nl-routing-corpus.ts +207 -2
- package/scripts/release-loop/docs-node.ts +344 -8
- package/scripts/release-loop/gate-closure.ts +48 -0
- package/scripts/release-loop/gate-diff.ts +2 -1
- package/scripts/release-loop/gate-node.ts +249 -53
- package/scripts/release-loop/known-issues-node.ts +6 -4
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/notes-repair.ts +216 -0
- package/scripts/release-loop/prepare-node.ts +61 -5
- package/scripts/release-loop/resume-cap.ts +14 -34
- package/scripts/release-loop/resume-release.ts +151 -15
- package/scripts/release-loop/resume-test-traffic.ts +10 -0
- package/scripts/release-loop/traffic-node.ts +59 -0
- package/scripts/release-loop/traffic-transition.ts +159 -0
- package/scripts/release-loop/version-node.ts +81 -12
- package/scripts/rhythm/daily.ts +137 -3
- package/scripts/train/green-leg.ts +176 -0
- package/scripts/tui-continue-real-evidence.ts +47 -0
- package/scripts/ux-sim.ts +53 -0
- package/skills/README.md +1 -0
- package/src/acp/client.ts +31 -5
- package/src/acp/core-turn-bridge.ts +54 -6
- package/src/acp/stderr-summary.ts +49 -0
- package/src/agent/delegate-hint.ts +16 -0
- package/src/agent/monad-agent-turn.ts +1 -0
- package/src/agent/runner.ts +82 -2
- package/src/agent/task-notification.ts +56 -10
- package/src/agent/terminal-surface.ts +217 -0
- package/src/agent/types.ts +4 -0
- package/src/agent-substrate/pr-reviewer.ts +64 -4
- package/src/agent-substrate/review-intent.ts +29 -2
- package/src/agent-substrate/review-observation.ts +3 -0
- package/src/agent-substrate/self-review-cli.ts +490 -26
- package/src/autopilot/lineage/sources.ts +1 -1
- package/src/autopilot/mission-codebase-gate.ts +141 -12
- package/src/autopilot/pr-manager.ts +89 -18
- package/src/boot/daemon-runtime.ts +35 -3
- package/src/boot/daemon-tools/pty-shell.ts +2 -1
- package/src/boot/daemon-tools/self-implement.ts +1 -0
- package/src/budget/run-usage-rollup.ts +12 -7
- package/src/budget/unified-usage.ts +20 -0
- package/src/budget/usage-outcomes.ts +8 -4
- package/src/capture/tui-self-report.ts +132 -1
- package/src/chat/goal-continue-verdict.ts +41 -0
- package/src/chat/index.ts +30 -4
- package/src/chat/internal-turn-origin.ts +1 -0
- package/src/chat/paste-fold.ts +86 -0
- package/src/chat/tool-render/block.ts +32 -0
- package/src/chat/tool-render/dispatch.ts +2 -20
- package/src/chat/tool-render/result-text.ts +98 -0
- package/src/chat/turn-typeahead.ts +70 -7
- package/src/cli/autopilot-cli.ts +24 -9
- package/src/cli/config-audit.ts +119 -0
- package/src/cli/decisions-cli.ts +7 -4
- package/src/cli/doctor-cli.ts +137 -6
- package/src/cli/guardian-cli.ts +10 -0
- package/src/cli/herdr-cli.ts +34 -0
- package/src/cli/light-entry-route.ts +6 -3
- package/src/cli/log-event-names.ts +2 -0
- package/src/cli/logs-cli.ts +357 -2
- package/src/cli/make-cli.ts +247 -11
- package/src/cli/memory-cli.ts +30 -1
- package/src/cli/msg-cli.ts +132 -14
- package/src/cli/pr-cli.ts +29 -16
- package/src/cli/pr-granularity.ts +5 -3
- package/src/cli/pr-land-base-read.ts +11 -2
- package/src/cli/pr-land-heavy-remote.ts +6 -3
- package/src/cli/pr-land-overlap-evidence.ts +23 -4
- package/src/cli/pr-land-recovery.ts +117 -1
- package/src/cli/pty-takeover-cli.ts +8 -7
- package/src/cli/release-checklist-read-cli.ts +109 -4
- package/src/cli/release-cli.ts +64 -15
- package/src/cli/release-single-flight.ts +1 -1
- package/src/cli/self-update.ts +23 -5
- package/src/cli/self-utterances-cli.ts +13 -16
- package/src/cli/tasks-card-show.ts +162 -0
- package/src/cli/tasks-cli.ts +868 -352
- package/src/cli/tasks-read-cli.ts +197 -0
- package/src/cli/usage-cli.ts +12 -10
- package/src/context-bus/claude-memory-import.ts +99 -0
- package/src/context-bus/long-term-memory.ts +125 -0
- package/src/core-turn/run-core-turn.ts +4 -2
- package/src/core-turn/run-goal-loop.ts +76 -16
- package/src/core-turn/types.ts +8 -1
- package/src/dashboard/chat/acp-chat.ts +9 -0
- package/src/dashboard/context/keys.ts +8 -31
- package/src/dashboard/index.ts +299 -62
- package/src/dashboard/input/agent-wake.ts +50 -1
- package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
- package/src/dashboard/input/chat-main-slash-command.ts +4 -2
- package/src/dashboard/input/goal-continue.ts +210 -0
- package/src/dashboard/input/goal-interim.ts +2 -0
- package/src/dashboard/input/internal-turn.ts +2 -8
- package/src/dashboard/input/seat-autowake.ts +9 -7
- package/src/dashboard/input/turn-autoheal.ts +52 -0
- package/src/dashboard/replay-preview.ts +25 -0
- package/src/dashboard/seat-boot-preamble.ts +132 -5
- package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -10
- package/src/dashboard/slash-runtime/model-choices.ts +15 -0
- package/src/dashboard/stale-install-check.ts +3 -99
- package/src/dashboard/synchronized-frame-output.ts +74 -0
- package/src/debug/batch-queue.ts +119 -0
- package/src/debug/tui-log-tag.ts +67 -0
- package/src/display/agent-surface.ts +7 -0
- package/src/display/coordinator.ts +45 -12
- package/src/display/resize-listener.ts +41 -20
- package/src/display/synchronized-output-region.ts +60 -0
- package/src/domains/standalone-log-sink.ts +15 -2
- package/src/domains/surface-events.ts +80 -1
- package/src/esc-abort-gate.ts +69 -0
- package/src/exec-requests/planner.ts +37 -2
- package/src/execution-loop/launch-gate.ts +4 -3
- package/src/git-fs/cli-stderr.ts +45 -0
- package/src/git-fs/gh-cli.ts +6 -3
- package/src/git-fs/git-cli.ts +11 -5
- package/src/git-fs/worktree.ts +95 -1
- package/src/graph-runner/graph-cli.ts +44 -2
- package/src/graph-runner/graph-run-api.ts +3 -2
- package/src/graph-runner/runner.ts +37 -16
- package/src/graph-wizard/generate.ts +131 -4
- package/src/graph-wizard/steps.ts +15 -0
- package/src/grounding/proactive-ground.ts +86 -0
- package/src/harness/control-inbox.ts +49 -1
- package/src/harness/harness-cli-command.ts +230 -40
- package/src/harness/harness-incidents.ts +52 -1
- package/src/harness/pod-control-send.ts +33 -5
- package/src/harness/review-adapter.ts +26 -6
- package/src/harness/self-send-remote.ts +69 -0
- package/src/harness/self-send-routing-guard.ts +6 -0
- package/src/harness/self-send-target.ts +4 -3
- package/src/index.ts +443 -25
- package/src/input-core/context-key-runtime.ts +21 -0
- package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
- package/src/light-cli.ts +6 -1
- package/src/llm/route-decision.ts +13 -0
- package/src/llm-tool-name.ts +37 -0
- package/src/llm-tool-schema.ts +35 -0
- package/src/llm-wellformed.ts +70 -0
- package/src/llm.ts +158 -15
- package/src/loops/checker.ts +100 -0
- package/src/loops/consensus.ts +26 -2
- package/src/loops/loop-cli.ts +9 -4
- package/src/loops/msg-wake.ts +35 -39
- package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
- package/src/loops/orchestrator/inbox.ts +59 -11
- package/src/loops/orchestrator/knowhow-pack.ts +364 -0
- package/src/loops/orchestrator/tick.ts +54 -5
- package/src/maturity/feature-maturity.ts +1 -1
- package/src/model-tier/llm-tier-map.ts +12 -17
- package/src/models/prompts.ts +17 -2
- package/src/msg/msg-post-office.ts +116 -0
- package/src/msg/msg-store.ts +17 -0
- package/src/mss/logging/log-store.ts +79 -22
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/decisions-route.ts +38 -18
- package/src/nexus/api/graph-wizard-api.ts +46 -3
- package/src/nexus/api/grid.ts +24 -4
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/ops-api.ts +14 -6
- package/src/nexus/boot/register-mcp-clients.ts +263 -38
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
- package/src/nexus/state/state.ts +7 -1
- package/src/oauth/codex-account-store.ts +34 -1
- package/src/onboarding/first-run.ts +37 -6
- package/src/onboarding/web-first.ts +43 -11
- package/src/ops/loops-map.ts +46 -0
- package/src/ops/overview-cache.ts +22 -4
- package/src/ops/overview-collect.ts +12 -6
- package/src/ops/overview.ts +44 -8
- package/src/persona/loader.ts +11 -0
- package/src/persona/types.ts +8 -0
- package/src/policy/llm-policy.ts +3 -1
- package/src/prompt-enhance/enhance.ts +4 -4
- package/src/prompt-library/session-guidance.ts +14 -0
- package/src/provider-summary.ts +8 -0
- package/src/pty-shell/availability.ts +7 -0
- package/src/pty-shell/herdr-agent-report.ts +155 -37
- package/src/pty-shell/herdr-prompt.ts +266 -0
- package/src/pty-shell/herdr-prune-stale.ts +17 -0
- package/src/pty-shell/herdr-sequence-lease.ts +60 -0
- package/src/pty-shell/pty-control-ipc.ts +327 -15
- package/src/pty-shell/pty-special-keys.ts +42 -2
- package/src/pty-shell/registry.ts +25 -15
- package/src/pty-shell/stale-install-check.ts +99 -0
- package/src/pty-shell/tui-run-state.ts +249 -3
- package/src/release-loop/auto-start.ts +20 -2
- package/src/release-loop/checklist.ts +126 -9
- package/src/release-loop/feature-store.ts +9 -9
- package/src/release-loop/landed-but-yellow.ts +93 -12
- package/src/release-loop/rehearsal.ts +36 -20
- package/src/repl/index.ts +27 -1
- package/src/seat-loop/knowhow-lint.ts +1 -1
- package/src/seat-loop/seat-report.ts +1 -0
- package/src/self-dev/ask-launch-flow.ts +86 -10
- package/src/self-dev/decompose-proposal.ts +183 -20
- package/src/self-dev/decompose.ts +61 -0
- package/src/self-dev/dev-cli.ts +37 -3
- package/src/self-dev/dev-pipeline.ts +37 -9
- package/src/self-dev/draft-sweep.ts +241 -16
- package/src/self-dev/draft-triage-rules.ts +50 -5
- package/src/self-dev/glm-credential-guard.ts +77 -0
- package/src/self-dev/graph-journey-nodes.ts +1 -0
- package/src/self-dev/graph-journey-route.ts +12 -2
- package/src/self-dev/orchestrate-cli.ts +68 -3
- package/src/self-dev/orchestrate.ts +116 -17
- package/src/self-dev/review-provider-fallback.ts +45 -7
- package/src/self-dev/run-supervisor.ts +55 -2
- package/src/self-dev/run-types.ts +1 -1
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-run.ts +50 -3
- package/src/self-health/autoheal.ts +153 -0
- package/src/self-health/signatures.ts +6 -0
- package/src/self-implement/device-first.ts +116 -0
- package/src/self-implement/doctor-visit.ts +322 -1
- package/src/self-implement/evidence-command-budget.ts +80 -0
- package/src/self-implement/gate-artifacts.ts +6 -2
- package/src/self-implement/gate-baseline.ts +64 -1
- package/src/self-implement/gate-cli.ts +93 -9
- package/src/self-implement/gate-remote.ts +28 -4
- package/src/self-implement/gate-scope.ts +13 -1
- package/src/self-implement/goal-author-cli.ts +1 -0
- package/src/self-implement/goal-author-decompose.ts +265 -4
- package/src/self-implement/goal-author.ts +366 -26
- package/src/self-implement/goal-elaborate.ts +176 -22
- package/src/self-implement/goal-refine.ts +3 -0
- package/src/self-implement/goal-supervisor-fill.ts +75 -26
- package/src/self-implement/graph-variant.ts +40 -6
- package/src/self-implement/headless-elanous-driver.ts +19 -3
- package/src/self-implement/importer-test-index.ts +215 -2
- package/src/self-implement/knowhow-pack.ts +5 -5
- package/src/self-implement/off-diff-evidence.ts +58 -6
- package/src/self-implement/orchestrator.ts +536 -42
- package/src/self-implement/pod-warm-pool-profile.ts +1 -0
- package/src/self-implement/pwa-import-graph.ts +1 -1
- package/src/self-implement/review-round-brief.ts +300 -0
- package/src/self-implement/rework-policy.ts +44 -0
- package/src/self-implement/run-ledger.ts +278 -6
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/run-ttl.ts +38 -24
- package/src/self-implement/running-runs.ts +17 -3
- package/src/self-implement/scope-adjacency.ts +3 -1
- package/src/self-implement/seams.ts +72 -10
- package/src/self-implement/stop-autoheal.ts +1 -0
- package/src/self-implement/test-seams.ts +13 -1
- package/src/self-implement/train-reach-grouping.ts +8 -2
- package/src/self-implement/wiring-check.ts +358 -0
- package/src/session/chat.ts +7 -1
- package/src/session/id-prefix.ts +60 -0
- package/src/session/index.ts +4 -0
- package/src/session-runtime/index.ts +9 -1
- package/src/shell-env-bootstrap.ts +11 -4
- package/src/skills/runner.ts +4 -2
- package/src/skills/tools/agent.ts +290 -48
- package/src/skills/tools/pty.ts +5 -0
- package/src/skills/tools/schedule-wakeup.ts +23 -4
- package/src/skills/tools/shell.ts +61 -6
- package/src/skills/tools/terminal-modal-inject.ts +1 -2
- package/src/skills/tools/terminal-modal.ts +10 -8
- package/src/skills/url-router.ts +41 -1
- package/src/smart-wizard/run.ts +66 -0
- package/src/status/bar.ts +34 -6
- package/src/status/metrics.ts +12 -1
- package/src/status/status-provider-info.ts +37 -6
- package/src/steward/rejudge-tick.ts +22 -7
- package/src/steward/resync-tick.ts +31 -4
- package/src/steward/ta-repair-event-collect.ts +17 -6
- package/src/task-agent/actions.ts +202 -5
- package/src/task-agent/boundary-proof-mapping.ts +12 -0
- package/src/task-agent/boundary-proof-producer.ts +147 -0
- package/src/task-agent/completion-evidence.ts +2 -1
- package/src/task-agent/green-close-recipe.ts +239 -0
- package/src/task-agent/green-sweep.ts +64 -10
- package/src/task-agent/land-queue.ts +21 -8
- package/src/task-agent/live-moves.ts +70 -9
- package/src/task-agent/map-host-adapter.ts +134 -0
- package/src/task-agent/map-reduce.ts +158 -0
- package/src/task-agent/map-run-ledger.ts +226 -0
- package/src/task-agent/mission.ts +30 -0
- package/src/task-agent/parent-host.ts +21 -11
- package/src/task-agent/rejudge-on-head.ts +87 -5
- package/src/task-agent/repair-cycle.ts +179 -32
- package/src/task-agent/repair-next-move.ts +42 -4
- package/src/task-agent/repair-outcomes.ts +29 -0
- package/src/task-agent/repair-worker.ts +14 -4
- package/src/task-agent/review-prior-fix.ts +12 -2
- package/src/task-agent/shadow.ts +229 -8
- package/src/task-agent/task-card-prefix.ts +2 -0
- package/src/task-agent/task-hand.ts +630 -30
- package/src/task-agent/task-parent-role-llm.ts +45 -0
- package/src/task-agent/tier-split.ts +80 -10
- package/src/task-agent/work-order.ts +53 -2
- package/src/task-orchestrator/dispatcher.ts +46 -1
- package/src/task-orchestrator/generator-prompt.ts +6 -0
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +9 -0
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
- package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +86 -5
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
- package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +11 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +126 -8
- package/src/task-orchestrator/surfaces/pod-provenance.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
- package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
- package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +491 -36
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +612 -54
- package/src/task-orchestrator/surfaces/self-implement.ts +46 -2
- package/src/testing/linux-env.ts +177 -0
- package/src/tool-runtime/index.ts +15 -2
- package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
- package/src/tty-foreground.ts +155 -0
- package/src/tui/chat/goal-interim.ts +177 -0
- package/src/tui/chat/log-view.ts +205 -18
- package/src/tui/chat/self-health-status.ts +232 -0
- package/src/tui/entry.ts +623 -80
- package/src/tui/input/at-picker.ts +55 -0
- package/src/tui/input/composer.ts +8 -1
- package/src/tui/slash/compact-command.ts +7 -0
- package/src/tui/slash/compact.ts +1 -7
- package/src/tui/slash/resume.ts +98 -0
- package/src/tui/slash/signals.ts +114 -0
- package/src/tui/slash/term-next.ts +71 -0
- package/src/tui-client/local-chat-turn.ts +49 -5
- package/src/tui-client/next-dashboard-runtime.ts +8 -0
- package/src/tui-client/next-loop-command.ts +70 -0
- package/src/tui-client/next-wakeup.ts +191 -0
- package/src/tui.ts +37 -0
- package/src/ui/modal-adapter.ts +2 -2
- package/src/user-config.ts +19 -1
- package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
- package/src/ux-sim/classic-tui-seat-scenarios.ts +670 -0
- package/src/ux-sim/cli-config-audit-device.ts +121 -0
- package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
- package/src/ux-sim/event-monkey.ts +3 -2
- package/src/ux-sim/fake-bin.ts +45 -0
- package/src/ux-sim/fake-gh.ts +174 -0
- package/src/ux-sim/fake-herdr.ts +238 -0
- package/src/ux-sim/fake-kubectl.ts +142 -0
- package/src/ux-sim/fake-llm.ts +116 -6
- package/src/ux-sim/fault-glm-no-credential.ts +116 -0
- package/src/ux-sim/fault-nextmove-dispatch.ts +102 -1
- package/src/ux-sim/fault-scope-escape-lift.ts +33 -6
- package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
- package/src/ux-sim/goal-device.ts +619 -0
- package/src/ux-sim/in-process-cli.ts +22 -5
- package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
- package/src/ux-sim/mock-authoring-first-run.ts +97 -0
- package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
- package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
- package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
- package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +749 -0
- package/src/ux-sim/onboarding-first-run-device.ts +269 -0
- package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
- package/src/ux-sim/resume-picker-device.ts +173 -0
- package/src/ux-sim/session-id-seed.ts +60 -0
- package/src/ux-sim/skills-tools-shell-device.ts +156 -0
- package/src/ux-sim/subagent-tools-device.ts +81 -0
- package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
- package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
- package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +0 -41
- package/apps/pwa/out/_next/static/chunks/1674.2a65fd5668e1cc5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +0 -74
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +0 -148
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +0 -34
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +0 -77
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +0 -62
- package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +0 -90
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3589.5444a06bcf6e775c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3677-4215f826f6aa68e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +0 -79
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4346.8601952e73bf5803.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +0 -24
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +0 -23
- package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +0 -94
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/56d372f2.681ab4ec4c998fae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5852.db1f7449f4f74612.js +0 -287
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +0 -1
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +0 -8
- package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +0 -93
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +0 -149
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +0 -104
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8437-8d5492094b166cfa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +0 -226
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +0 -64
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8637.47f5b35afcae5e6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +0 -115
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-26e6c18a1a750cf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.js +0 -1
- /package/apps/pwa/out/_next/static/{T1mBQqmkwKDLGtyisDCOd → 8kITumG9GAZ1LwT9POrAR}/_ssgManifest.js +0 -0
|
@@ -14,24 +14,46 @@
|
|
|
14
14
|
//
|
|
15
15
|
// index.ts 의 액션은 옵션 파싱과 실제 의존 배선만 남는다(얇은 껍데기).
|
|
16
16
|
|
|
17
|
-
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
18
18
|
import { homedir, tmpdir } from 'node:os';
|
|
19
19
|
import { dirname, join } from 'node:path';
|
|
20
20
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
21
21
|
import { tierModel } from '../llm/model-defaults.js';
|
|
22
22
|
import { buildReviewObservation, safeLogText } from './review-observation.js';
|
|
23
|
+
import { checkCitedReviewPathsAtHead } from './review-finding-key.js';
|
|
23
24
|
import { DEFAULT_REVIEW_BACKEND, defaultAcpReviewTimeoutSec } from './acp-reviewer.js';
|
|
24
25
|
import { ZAI_OPENROUTER_FALLBACK_MODEL } from '../llm/zai-coding-plan.js';
|
|
25
26
|
import { debug } from '../debug/log.js';
|
|
26
27
|
import { ACP_BACKENDS, canonicalizeBackendId } from '../acp/backend-registry.js';
|
|
27
28
|
import { buildManualReviewIntent, intentFromPr, prIntentSectionCoverage, reviewIntentTruncationFromPr, reviewIntentTruncationObservation } from './review-intent.js';
|
|
28
|
-
import { budgetReviewerContext, reviewDiffBudgetObservation, splitDiffByFile, type ReviewImage, type ReviewInput, type ReviewerContextItem, type ReviewResult } from './pr-reviewer.js';
|
|
29
|
+
import { budgetReviewerContext, isNoneSentinelFinding, reviewDiffBudgetObservation, splitDiffByFile, type ReviewImage, type ReviewInput, type ReviewerContextItem, type ReviewResult } from './pr-reviewer.js';
|
|
29
30
|
import type { ReferencedFileReader } from '../self-implement/goal-file-reader.js';
|
|
30
|
-
import { getUserConfig, type LLMProviderName, type RoleLlmSpec, type SubscriptionReviewerSpec } from '../user-config.js';
|
|
31
|
+
import { getUserConfig, type LLMProviderName, type ReviewerMixSpec, type RoleLlmSpec, type SubscriptionReviewerSpec } from '../user-config.js';
|
|
32
|
+
import { loadLlmPolicy } from '../policy/llm-policy.js';
|
|
31
33
|
import { listRunLedgers, lookupPrGoalAcceptance, lookupRunLedger, type PrGoalAcceptanceLookup, type RunLedgerEntry, type RunLedgerLookup } from '../self-implement/run-ledger.js';
|
|
32
34
|
|
|
33
35
|
/** SUBSCRIPTION-EXHAUST-REROUTE — API reviewer when the configured `roleLlm.reviewer` lane is unavailable (off codex). */
|
|
34
36
|
export const ROLE_REVIEWER_FALLBACK_MODEL = 'openrouter/z-ai/glm-5.3';
|
|
37
|
+
export const DEFAULT_REVIEWER_MIX: ReviewerMixSpec = { sol: 1, claude: 1, glm: 1 };
|
|
38
|
+
type ReviewLane = keyof ReviewerMixSpec;
|
|
39
|
+
const REVIEW_LANES: readonly ReviewLane[] = ['sol', 'claude', 'glm'];
|
|
40
|
+
|
|
41
|
+
/** A PR keeps the same primary lane through every review round, regardless of head SHA. */
|
|
42
|
+
export function reviewLaneOrder(pr: string, mix: ReviewerMixSpec): ReviewLane[] {
|
|
43
|
+
if (!/^\d+$/.test(pr)) return [];
|
|
44
|
+
const total = REVIEW_LANES.reduce((sum, lane) => sum + mix[lane], 0);
|
|
45
|
+
if (!Number.isSafeInteger(total) || total <= 0) return [];
|
|
46
|
+
const slot = Number(BigInt(pr) % BigInt(total));
|
|
47
|
+
let offset = 0;
|
|
48
|
+
let primary: ReviewLane | undefined;
|
|
49
|
+
for (const lane of REVIEW_LANES) {
|
|
50
|
+
offset += mix[lane];
|
|
51
|
+
if (slot < offset) { primary = lane; break; }
|
|
52
|
+
}
|
|
53
|
+
if (!primary) return [];
|
|
54
|
+
const start = REVIEW_LANES.indexOf(primary);
|
|
55
|
+
return [...REVIEW_LANES.slice(start), ...REVIEW_LANES.slice(0, start)].filter(lane => mix[lane] > 0);
|
|
56
|
+
}
|
|
35
57
|
|
|
36
58
|
/** Only an explicit provider+model role setting selects the API review model. */
|
|
37
59
|
export function apiReviewModelFromRoleSpec(spec: RoleLlmSpec | undefined): string | undefined {
|
|
@@ -54,6 +76,15 @@ export interface SelfReviewCliOpts {
|
|
|
54
76
|
reviewDenyBackends?: string[] | undefined;
|
|
55
77
|
/** `roleLlm.reviewer` (same resolution as the harness). Used only when no explicit reviewer flag is given. */
|
|
56
78
|
roleReviewer?: SubscriptionReviewerSpec | undefined;
|
|
79
|
+
/** Default resolves from policy/config; null keeps the legacy single reviewer for isolated callers. */
|
|
80
|
+
reviewerMix?: ReviewerMixSpec | null | undefined;
|
|
81
|
+
/** Internal route metadata; the user-facing mix is selected once per PR. */
|
|
82
|
+
reviewerMixPrimaryLane?: ReviewLane | undefined;
|
|
83
|
+
reviewerMixAttemptLane?: ReviewLane | undefined;
|
|
84
|
+
reviewerMixExpectedHead?: string | undefined;
|
|
85
|
+
/** Internal: the same command already claimed its single over-cap exception for this pinned head. */
|
|
86
|
+
reviewerMixCapClaimed?: boolean | undefined;
|
|
87
|
+
disableClaudeGlmFallback?: boolean | undefined;
|
|
57
88
|
acpTimeout?: string | undefined;
|
|
58
89
|
context?: string[] | undefined;
|
|
59
90
|
contextText?: string[] | undefined;
|
|
@@ -67,6 +98,8 @@ export interface SelfReviewCliOpts {
|
|
|
67
98
|
|
|
68
99
|
/** 셸/네트워크/로그 경계 — 테스트는 전부 대역으로 채운다. */
|
|
69
100
|
export interface SelfReviewCliDeps {
|
|
101
|
+
/** Explicit repository root for exact-head cited-path checks; absent means unmeasured. */
|
|
102
|
+
reviewRepositoryPath?: string;
|
|
70
103
|
/** `gh` 호출. 실패도 예외 없이 `{status, stdout, stderr}` 로 돌려준다(spawnSync 동형). */
|
|
71
104
|
gh(args: string[], timeoutMs: number): { status: number | null; stdout: string; stderr: string };
|
|
72
105
|
/** ⭐ `git` 호출(선택). 주입되면 리뷰 증거를 **이 PR 이 저작한 변경**으로 좁힌다(아래 참조).
|
|
@@ -139,27 +172,36 @@ export interface SelfReviewCliOutcome {
|
|
|
139
172
|
}
|
|
140
173
|
|
|
141
174
|
/** Saved results are round evidence only when their PR, exact head and reviewed status agree. */
|
|
142
|
-
|
|
175
|
+
function savedReviewRecords(pr: string, root = effectiveInstanceRoot()): Array<{ head: string; reviewedAt: number }> {
|
|
143
176
|
const dir = join(root, 'review-results');
|
|
144
177
|
let names: string[];
|
|
145
178
|
try { names = readdirSync(dir); } catch { return []; }
|
|
146
179
|
// Manual review saves in the operating house also use head10; the JSON's full head is authoritative.
|
|
147
180
|
const matching = new RegExp(`^.+-${pr}-([a-f0-9]{7,40})\\.json$`, 'i');
|
|
148
|
-
const
|
|
181
|
+
const records = new Map<string, { head: string; reviewedAt: number }>();
|
|
149
182
|
for (const name of names) {
|
|
150
183
|
const match = matching.exec(name);
|
|
151
184
|
if (!match) continue;
|
|
152
185
|
try {
|
|
153
|
-
const
|
|
186
|
+
const recordPath = join(dir, name);
|
|
187
|
+
const raw: unknown = JSON.parse(readFileSync(recordPath, 'utf8'));
|
|
154
188
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
|
|
155
189
|
const result = raw as Record<string, unknown>;
|
|
156
190
|
const head = result.headCommit;
|
|
157
191
|
if (String(result.pr) !== pr || result.reviewed !== true || typeof head !== 'string'
|
|
158
192
|
|| !COMMIT_OID.test(head) || !head.toLowerCase().startsWith(match[1]!.toLowerCase())) continue;
|
|
159
|
-
|
|
193
|
+
const normalized = head.toLowerCase();
|
|
194
|
+
const existing = records.get(normalized);
|
|
195
|
+
const reviewedAt = typeof result.reviewedAt === 'number' && Number.isFinite(result.reviewedAt)
|
|
196
|
+
? result.reviewedAt : statSync(recordPath).mtimeMs;
|
|
197
|
+
if (!existing || reviewedAt > existing.reviewedAt) records.set(normalized, { head: normalized, reviewedAt });
|
|
160
198
|
} catch { /* corrupt or partial result is not a completed round */ }
|
|
161
199
|
}
|
|
162
|
-
return [...
|
|
200
|
+
return [...records.values()];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
|
|
204
|
+
return savedReviewRecords(pr, root).map(({ head }) => head);
|
|
163
205
|
}
|
|
164
206
|
|
|
165
207
|
function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string | null {
|
|
@@ -178,14 +220,42 @@ function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string |
|
|
|
178
220
|
} catch { return null; }
|
|
179
221
|
}
|
|
180
222
|
|
|
223
|
+
function readCapOverride(pr: string): { head: string; reason: string } | undefined {
|
|
224
|
+
try {
|
|
225
|
+
const value = JSON.parse(readFileSync(join(effectiveInstanceRoot(), 'review-results', `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
|
|
226
|
+
if (String(value.pr) !== pr || typeof value.head !== 'string' || !COMMIT_OID.test(value.head)
|
|
227
|
+
|| typeof value.reason !== 'string' || !value.reason.trim()) return undefined;
|
|
228
|
+
return { head: value.head.toLowerCase(), reason: value.reason };
|
|
229
|
+
} catch { return undefined; }
|
|
230
|
+
}
|
|
231
|
+
|
|
181
232
|
function claimCapOverride(pr: string, head: string, reason: string, now: number): boolean {
|
|
182
233
|
const dir = join(effectiveInstanceRoot(), 'review-results');
|
|
183
234
|
try {
|
|
184
235
|
mkdirSync(dir, { recursive: true });
|
|
185
|
-
|
|
186
|
-
|
|
236
|
+
const normalizedHead = head.toLowerCase();
|
|
237
|
+
const authorizationPath = join(dir, `cap-override-${pr}.json`);
|
|
238
|
+
// The first over-cap review creates the durable, PR-scoped authorization record atomically.
|
|
239
|
+
writeFileSync(authorizationPath, JSON.stringify({ pr, head: normalizedHead, reason, claimedAt: now, use: 'initial-authorization' }) + '\n', { flag: 'wx' });
|
|
187
240
|
return true;
|
|
188
|
-
} catch {
|
|
241
|
+
} catch {
|
|
242
|
+
// An OP authorization applies to later heads of this PR while the allowlist remains active.
|
|
243
|
+
// Keep the initial claim immutable, and atomically record each additional head separately so
|
|
244
|
+
// retries of the same head cannot spend the grant twice.
|
|
245
|
+
try {
|
|
246
|
+
const authorization = JSON.parse(readFileSync(join(dir, `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
|
|
247
|
+
const authorizedHead = authorization.head;
|
|
248
|
+
if (String(authorization.pr) !== pr || typeof authorization.reason !== 'string' || !authorization.reason.trim()
|
|
249
|
+
|| authorization.reason !== reason
|
|
250
|
+
|| typeof authorizedHead !== 'string' || !COMMIT_OID.test(authorizedHead)
|
|
251
|
+
|| authorizedHead.toLowerCase() === head.toLowerCase()) return false;
|
|
252
|
+
const normalizedHead = head.toLowerCase();
|
|
253
|
+
writeFileSync(join(dir, `cap-override-${pr}-head-${normalizedHead}.json`), JSON.stringify({
|
|
254
|
+
pr, head: normalizedHead, reason, claimedAt: now, use: 'subsequent-head', authorizationHead: authorizedHead.toLowerCase(),
|
|
255
|
+
}) + '\n', { flag: 'wx' });
|
|
256
|
+
return true;
|
|
257
|
+
} catch { return false; }
|
|
258
|
+
}
|
|
189
259
|
}
|
|
190
260
|
|
|
191
261
|
/** OP owns this list. Missing, unreadable, or malformed traffic never grants a review exception. */
|
|
@@ -1334,6 +1404,105 @@ function createDetachedReviewWorktree(commit: string, deps: SelfReviewCliDeps):
|
|
|
1334
1404
|
return { cwd, commit, remove };
|
|
1335
1405
|
}
|
|
1336
1406
|
|
|
1407
|
+
// ── 착지 관문(landing gate) — requested/actual ────────────────────────────────────────────
|
|
1408
|
+
//
|
|
1409
|
+
// ⚠️ 왜 생산자(여기)에 있나: 착지 관문(`src/cli/pr-land-overlap-evidence.ts`)도 결과 JSON 을 읽어
|
|
1410
|
+
// 같은 대조를 하지만, 그 파일을 **만드는 자리**가 틀린 requested/actual 을 적으면 관문은 그
|
|
1411
|
+
// 거짓을 근거로 판정한다. 그리고 `acp.reviewDenyBackends` 가 금지한 백엔드가 낸 판정은 파일이
|
|
1412
|
+
// 되기 **전에** 거부돼야 `--save` 로도 착지 근거가 될 수 없다(fail-closed).
|
|
1413
|
+
//
|
|
1414
|
+
// ⛔ 못 잰 값(`unmeasured`)을 «일치»로 적지 않는다 — 부재와 미지를 같은 값으로 두지 않는다.
|
|
1415
|
+
|
|
1416
|
+
/** 사람이 요청한 리뷰어. `value` 는 화면·로그에 그대로 나가는 **요청 원문**이다. */
|
|
1417
|
+
interface LandingGateRequest {
|
|
1418
|
+
kind: 'api-model' | 'acp-backend' | 'role-lane';
|
|
1419
|
+
value: string;
|
|
1420
|
+
/** api-model 요청의 정규화된 기대 모델(짧은 별칭 → 정본 ID). */
|
|
1421
|
+
model?: string;
|
|
1422
|
+
/** acp-backend 요청의 기대 백엔드. */
|
|
1423
|
+
backend?: string;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
/** 실제로 판정을 낸 리뷰어. `value` 는 실측 원문(`api:<model>` · `acp:<backend>` · `unmeasured`). */
|
|
1427
|
+
interface LandingGateActual {
|
|
1428
|
+
kind: 'api' | 'acp' | 'unknown';
|
|
1429
|
+
value: string;
|
|
1430
|
+
model?: string;
|
|
1431
|
+
backend?: string;
|
|
1432
|
+
respondedProvider?: string;
|
|
1433
|
+
respondedModel?: string;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
type LandingGateOutcome =
|
|
1437
|
+
| { state: 'consistent'; requested: string; actual: string }
|
|
1438
|
+
| { state: 'mismatch'; requested: string; actual: string; warning: string }
|
|
1439
|
+
| { state: 'denied'; requested: string; actual: string; warning: string; refusal: 'review-forbidden-acp-backend'; deniedBackend: string };
|
|
1440
|
+
|
|
1441
|
+
function normalizedReviewBackend(value: string | undefined): string {
|
|
1442
|
+
return canonicalizeBackendId((value ?? '').trim()).trim().toLowerCase();
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/** 금지 목록 대조. 문자열 엔트리와 구조형(`{backend, expiresAt}`) 엔트리가 같은 값으로 접힌다. */
|
|
1446
|
+
function deniedReviewBackend(backend: string | undefined, denyBackends: readonly string[]): boolean {
|
|
1447
|
+
const target = normalizedReviewBackend(backend);
|
|
1448
|
+
if (!target) return false;
|
|
1449
|
+
return denyBackends.some((denied) => normalizedReviewBackend(denied) === target);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
function landingGateAgrees(request: LandingGateRequest, actual: LandingGateActual): boolean {
|
|
1453
|
+
// ⛔ 실측을 못 잰 것을 «일치»로 적지 않는다(요청이 있으면 불일치로 남긴다).
|
|
1454
|
+
if (actual.kind === 'unknown') return false;
|
|
1455
|
+
if (request.kind === 'api-model') {
|
|
1456
|
+
if (actual.kind !== 'api') return false;
|
|
1457
|
+
const requested = (request.model ?? request.value).trim().toLowerCase();
|
|
1458
|
+
const selected = (actual.model ?? '').trim().toLowerCase();
|
|
1459
|
+
if (selected && selected === requested) return true;
|
|
1460
|
+
const respondedProvider = (actual.respondedProvider ?? '').trim().toLowerCase();
|
|
1461
|
+
const respondedModel = (actual.respondedModel ?? '').trim().toLowerCase();
|
|
1462
|
+
// 요청이 공급자 한정 형태(`openrouter/<model>`)일 때만 공급자·응답 모델을 대조한다 —
|
|
1463
|
+
// 맨 모델 ID(`gpt-6-sol`·`claude-sonnet-4`)는 공급자와 비교할 수 없다.
|
|
1464
|
+
const slash = requested.indexOf('/');
|
|
1465
|
+
if (slash <= 0) return false;
|
|
1466
|
+
const requestedProvider = requested.slice(0, slash);
|
|
1467
|
+
const requestedTail = requested.slice(slash + 1);
|
|
1468
|
+
return Boolean(respondedProvider) && respondedProvider === requestedProvider
|
|
1469
|
+
&& Boolean(respondedModel) && (respondedModel === requestedTail || respondedModel === requested);
|
|
1470
|
+
}
|
|
1471
|
+
if (request.kind === 'acp-backend') {
|
|
1472
|
+
return actual.kind === 'acp' && normalizedReviewBackend(actual.backend) === normalizedReviewBackend(request.backend);
|
|
1473
|
+
}
|
|
1474
|
+
// role-lane: 설정이 고른 레인은 provider 표기(`claude-acp`)와 백엔드 표기(`claude`)가 달라
|
|
1475
|
+
// 백엔드 이름으로 비교하지 않는다 — 「ACP 레인으로 판정했나」만 본다.
|
|
1476
|
+
return actual.kind === 'acp';
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
function landingGateOutcome(input: {
|
|
1480
|
+
pr: string;
|
|
1481
|
+
reviewRoute: 'api' | 'acp' | 'acp-fallback';
|
|
1482
|
+
request?: LandingGateRequest | undefined;
|
|
1483
|
+
actual: LandingGateActual;
|
|
1484
|
+
deniedBackends: readonly string[];
|
|
1485
|
+
}): LandingGateOutcome {
|
|
1486
|
+
const requested = input.request?.value ?? '(none)';
|
|
1487
|
+
const actual = input.actual.value;
|
|
1488
|
+
if (input.actual.kind === 'acp' && deniedReviewBackend(input.actual.backend, input.deniedBackends)) {
|
|
1489
|
+
const deniedBackend = normalizedReviewBackend(input.actual.backend);
|
|
1490
|
+
return {
|
|
1491
|
+
state: 'denied', requested, actual, refusal: 'review-forbidden-acp-backend', deniedBackend,
|
|
1492
|
+
warning: `⛔ LANDING GATE DENY (fail-closed): requested=${requested} actual=${actual} denied=${deniedBackend} reviewRoute=${input.reviewRoute} — acp.reviewDenyBackends 가 금지한 백엔드가 판정을 냈습니다. PR ${input.pr} 의 이 리뷰는 착지 근거가 아니며 self review 는 실패(rc≠0)로 끝납니다.`,
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
if (!input.request || landingGateAgrees(input.request, input.actual)) return { state: 'consistent', requested, actual };
|
|
1496
|
+
const responded = [
|
|
1497
|
+
input.actual.respondedProvider ? `respondedProvider=${input.actual.respondedProvider}` : '',
|
|
1498
|
+
input.actual.respondedModel ? `respondedModel=${input.actual.respondedModel}` : '',
|
|
1499
|
+
].filter(Boolean).join(' ');
|
|
1500
|
+
return {
|
|
1501
|
+
state: 'mismatch', requested, actual,
|
|
1502
|
+
warning: `⚠️ LANDING GATE REQUESTED/ACTUAL MISMATCH: requested=${requested} actual=${actual} reviewRoute=${input.reviewRoute}${responded ? ` ${responded}` : ''} — 요청한 리뷰어와 실제로 판정을 낸 리뷰어가 다릅니다(PR ${input.pr}). 이 리뷰를 착지 근거로 쓰기 전에 확인하세요.`,
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1337
1506
|
/** `elanous self review <pr...>` 본문. read-only — 머지하지 않는다. */
|
|
1338
1507
|
/**
|
|
1339
1508
|
* `self review --json` stdout 한 줄 — 결과가 하나면 객체, 여럿이면 배열. index.ts 액션이 이것을 그대로 쓴다.
|
|
@@ -1343,6 +1512,20 @@ export function selfReviewJsonLine(results: readonly unknown[]): string {
|
|
|
1343
1512
|
return JSON.stringify(results.length === 1 ? results[0] : results) + '\n';
|
|
1344
1513
|
}
|
|
1345
1514
|
|
|
1515
|
+
function normalizeSavedReviewMustFix(result: Record<string, unknown>): { result: Record<string, unknown>; count: number } {
|
|
1516
|
+
if (!Array.isArray(result.mustFix)) return { result, count: 0 };
|
|
1517
|
+
const noFindingNotes = result.mustFix.filter((finding): finding is string =>
|
|
1518
|
+
typeof finding === 'string' && isNoneSentinelFinding(finding));
|
|
1519
|
+
if (noFindingNotes.length === 0) return { result, count: 0 };
|
|
1520
|
+
const retained = result.mustFix.filter((finding) =>
|
|
1521
|
+
typeof finding !== 'string' || !isNoneSentinelFinding(finding));
|
|
1522
|
+
const existingNotes = Array.isArray(result.noFindingNotes) ? result.noFindingNotes : [];
|
|
1523
|
+
return {
|
|
1524
|
+
result: { ...result, mustFix: retained, noFindingNotes: [...existingNotes, ...noFindingNotes] },
|
|
1525
|
+
count: noFindingNotes.length,
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1346
1529
|
export async function runSelfReviewCliCommand(
|
|
1347
1530
|
prArgs: string[],
|
|
1348
1531
|
opts: SelfReviewCliOpts,
|
|
@@ -1350,6 +1533,103 @@ export async function runSelfReviewCliCommand(
|
|
|
1350
1533
|
): Promise<SelfReviewCliOutcome> {
|
|
1351
1534
|
const pins: ReviewWorktree[] = [];
|
|
1352
1535
|
try {
|
|
1536
|
+
// Resolve inside the leaf CLI seam so src/index.ts needs no mix-specific registration.
|
|
1537
|
+
const reviewerMix = opts.reviewerMix === undefined
|
|
1538
|
+
? loadLlmPolicy().policy.roles.reviewerMix ?? getUserConfig().roleLlm?.reviewerMix ?? DEFAULT_REVIEWER_MIX
|
|
1539
|
+
: opts.reviewerMix;
|
|
1540
|
+
// The route is chosen outside the existing single-review pipeline so explicit CLI flags retain
|
|
1541
|
+
// their exact behavior. A failed reviewer is retried on the same pinned PR diff by the next lane.
|
|
1542
|
+
if (reviewerMix && (opts.save === undefined || /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(opts.save)) &&
|
|
1543
|
+
!opts.model?.trim() && !opts.acp && !opts.acpBackend && !opts.acpModel && !deps.envModel()) {
|
|
1544
|
+
const results: Array<Record<string, unknown>> = [];
|
|
1545
|
+
let failed = 0;
|
|
1546
|
+
for (const arg of prArgs) {
|
|
1547
|
+
const pr = normalizeReviewPrArg(arg, deps);
|
|
1548
|
+
const lanes = pr ? reviewLaneOrder(pr, reviewerMix) : [];
|
|
1549
|
+
if (!pr || lanes.length === 0) {
|
|
1550
|
+
const outcome = await runSelfReviewCliCommandPinned([arg], { ...opts, reviewerMix: undefined }, deps, pins);
|
|
1551
|
+
results.push(...outcome.results);
|
|
1552
|
+
failed += outcome.failed;
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
const initialHead = prHeadCommit(pr, deps);
|
|
1556
|
+
if (initialHead.state !== 'known') {
|
|
1557
|
+
deps.log('review.lane-head-unknown', { pr, headState: initialHead.state }, { level: 'warn' });
|
|
1558
|
+
results.push({ pr, reviewed: false, refusal: 'reviewer-mix-head-unknown',
|
|
1559
|
+
failureReason: 'PR head could not be pinned before review', reviewerMixPrimaryLane: lanes[0] });
|
|
1560
|
+
failed += 1;
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1563
|
+
let completed: Record<string, unknown> | undefined;
|
|
1564
|
+
let last: Record<string, unknown> | undefined;
|
|
1565
|
+
let completedLane: ReviewLane | undefined;
|
|
1566
|
+
let attemptedLane: ReviewLane | undefined;
|
|
1567
|
+
let completedWithError = false;
|
|
1568
|
+
const pinnedHead = initialHead.value;
|
|
1569
|
+
let capClaimed = false;
|
|
1570
|
+
let pendingFallback: { from: ReviewLane; reason: string } | undefined;
|
|
1571
|
+
for (const [index, lane] of lanes.entries()) {
|
|
1572
|
+
const observedHead = prHeadCommit(pr, deps);
|
|
1573
|
+
if (observedHead.state !== 'known' || observedHead.value !== pinnedHead) {
|
|
1574
|
+
last = { pr, reviewed: false, refusal: 'reviewer-mix-head-changed', stale: true,
|
|
1575
|
+
expectedHeadCommit: pinnedHead, headCommit: observedHead.value };
|
|
1576
|
+
deps.log('review.lane-head-changed', { pr, expectedHead: pinnedHead,
|
|
1577
|
+
observedHead: observedHead.value }, { level: 'warn' });
|
|
1578
|
+
break;
|
|
1579
|
+
}
|
|
1580
|
+
const laneOpts: SelfReviewCliOpts = {
|
|
1581
|
+
...opts, reviewerMix: undefined, reviewerMixPrimaryLane: lanes[0], reviewerMixAttemptLane: lane,
|
|
1582
|
+
reviewerMixExpectedHead: pinnedHead, reviewerMixCapClaimed: capClaimed,
|
|
1583
|
+
disableClaudeGlmFallback: true, json: true,
|
|
1584
|
+
...(lane === 'claude' ? { acp: true, acpBackend: 'claude', model: undefined } :
|
|
1585
|
+
{ acp: false, acpBackend: undefined, model: lane === 'sol' ? 'gpt-6-sol' : ROLE_REVIEWER_FALLBACK_MODEL }),
|
|
1586
|
+
};
|
|
1587
|
+
let reviewerStarted = false;
|
|
1588
|
+
const laneDeps: SelfReviewCliDeps = { ...deps,
|
|
1589
|
+
reviewPullRequest: (input, llm) => { reviewerStarted = true; return deps.reviewPullRequest(input, llm); },
|
|
1590
|
+
observeDoctorReview: (event, data, options) => {
|
|
1591
|
+
if (event === 'cap-override') capClaimed = true;
|
|
1592
|
+
deps.observeDoctorReview?.(event, data, options);
|
|
1593
|
+
},
|
|
1594
|
+
};
|
|
1595
|
+
try {
|
|
1596
|
+
const outcome = await runSelfReviewCliCommandPinned([arg], laneOpts, laneDeps, pins);
|
|
1597
|
+
last = outcome.results[0];
|
|
1598
|
+
completedWithError = last?.reviewed === true && outcome.failed > 0;
|
|
1599
|
+
} catch (error) {
|
|
1600
|
+
last = { pr, reviewed: false, failureReason: safeLogText(error instanceof Error ? error.message : String(error), 400) };
|
|
1601
|
+
}
|
|
1602
|
+
if (last?.refusal === 'reviewer-mix-head-changed' || last?.refusal === 'cap-refused' || last?.stale === true) break;
|
|
1603
|
+
if (reviewerStarted) {
|
|
1604
|
+
attemptedLane = lane;
|
|
1605
|
+
deps.log('review.lane-chosen', { pr, lane, primaryLane: lanes[0], attempt: index + 1, weights: reviewerMix });
|
|
1606
|
+
}
|
|
1607
|
+
if (pendingFallback && reviewerStarted) {
|
|
1608
|
+
deps.log('review.lane-fallback', { pr, from: pendingFallback.from, to: lane,
|
|
1609
|
+
reason: pendingFallback.reason }, { level: 'warn' });
|
|
1610
|
+
pendingFallback = undefined;
|
|
1611
|
+
}
|
|
1612
|
+
if (last?.reviewed === true) {
|
|
1613
|
+
completed = last;
|
|
1614
|
+
completedLane = lane;
|
|
1615
|
+
break;
|
|
1616
|
+
}
|
|
1617
|
+
if (last?.refusal || last?.stale === true || index === lanes.length - 1) break;
|
|
1618
|
+
pendingFallback = { from: lane,
|
|
1619
|
+
reason: safeLogText(String(last?.failureReason ?? last?.error ?? 'reviewed=false'), 400) };
|
|
1620
|
+
}
|
|
1621
|
+
const result = completed ?? last;
|
|
1622
|
+
if (result) {
|
|
1623
|
+
const selectedLane = completedLane ?? attemptedLane;
|
|
1624
|
+
const enriched: Record<string, unknown> = { ...result, reviewerMixPrimaryLane: lanes[0],
|
|
1625
|
+
...(selectedLane ? { reviewerMixSelectedLane: selectedLane } : {}) };
|
|
1626
|
+
results.push(enriched);
|
|
1627
|
+
if (!opts.json) deps.print(`\n━━ PR ${pr} (${String(enriched.model ?? 'review failed')}) ━━\n${deps.renderReview(enriched as unknown as ReviewResult)}`);
|
|
1628
|
+
}
|
|
1629
|
+
if (!completed || completedWithError) failed += 1;
|
|
1630
|
+
}
|
|
1631
|
+
return { results, failed };
|
|
1632
|
+
}
|
|
1353
1633
|
return await runSelfReviewCliCommandPinned(prArgs, opts, deps, pins);
|
|
1354
1634
|
} finally {
|
|
1355
1635
|
for (const pin of pins) pin.remove();
|
|
@@ -1403,8 +1683,10 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1403
1683
|
deps.error(message);
|
|
1404
1684
|
return { results: opts.json ? [{ error: message }] : [], failed: 1 };
|
|
1405
1685
|
}
|
|
1406
|
-
|
|
1407
|
-
|
|
1686
|
+
// 이 명령이 실제로 적용하는 금지 목록 — 자동 폴백 후보에서 빼는 데 쓰이고(종전과 같은 값),
|
|
1687
|
+
// 이제 착지 관문이 «실제로 판정을 낸 백엔드»를 대조하는 데에도 같은 값으로 쓰인다.
|
|
1688
|
+
const effectiveReviewDenyBackends: string[] = opts.reviewDenyBackends === undefined ? configuredReviewDenyBackends : reviewDenyBackends;
|
|
1689
|
+
const automaticFallbacks = orderedAcpReviewFallbackBackends(opts.configuredAcpBackend, effectiveReviewDenyBackends);
|
|
1408
1690
|
const fallbackAcpBackends = opts.acpBackend
|
|
1409
1691
|
? [canonicalizeBackendId(opts.acpBackend)]
|
|
1410
1692
|
: automaticFallbacks.backends;
|
|
@@ -1440,7 +1722,9 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1440
1722
|
return { results: opts.json ? [{ error: message, requestedModel }] : [], failed: 1 };
|
|
1441
1723
|
}
|
|
1442
1724
|
const configuredReviewModel = opts.configuredReviewModel?.trim() || undefined;
|
|
1443
|
-
|
|
1725
|
+
// REVIEW-MODEL-ALIAS-PROVIDER: provider pinning needs GLM's OpenRouter model id, not the bare alias.
|
|
1726
|
+
const explicitApiModel = requestedModel?.toLowerCase() === 'glm' ? ROLE_REVIEWER_FALLBACK_MODEL : opts.model;
|
|
1727
|
+
const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (explicitApiModel || envModel || configuredReviewModel || roleFallbackModel || tierModel('better'));
|
|
1444
1728
|
const configuredReviewSelected = !opts.model?.trim() && !envModel && Boolean(configuredReviewModel);
|
|
1445
1729
|
let roleReviewer: { llm: (prompt: string, images?: readonly ReviewImage[]) => Promise<string>; model: string } | undefined;
|
|
1446
1730
|
let roleReviewerUnavailableReason: string | undefined;
|
|
@@ -1453,7 +1737,13 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1453
1737
|
const made = deps.makeRoleReviewerLlm
|
|
1454
1738
|
? deps.makeRoleReviewerLlm(opts.roleReviewer, { timeoutMs: acpTimeoutSec * 1000 })
|
|
1455
1739
|
: { reason: 'role-reviewer-seam-missing' };
|
|
1456
|
-
|
|
1740
|
+
// ⛔ 금지 목록(acp.reviewDenyBackends)은 «자동 폴백 후보»만이 아니라 **자동 선택 전부**를 막는다.
|
|
1741
|
+
// 역할 레인은 사람이 친 플래그가 아니라 설정이 고른 자동 선택이므로, 금지된 백엔드가 레인을
|
|
1742
|
+
// 잡으면 그 리뷰가 그대로 착지 근거가 됐다(fail-open). ⇒ 레인을 쓰지 않고 같은 사유 코드로
|
|
1743
|
+
// API 로 내려간다(`role-reviewer-fallback · stage=availability` 가 관측에 남는다).
|
|
1744
|
+
if ('llm' in made && deniedReviewBackend(made.backend, effectiveReviewDenyBackends)) {
|
|
1745
|
+
roleReviewerUnavailableReason = 'denied-by-acp.reviewDenyBackends';
|
|
1746
|
+
} else if ('llm' in made) roleReviewer = { llm: made.llm, model: `acp:${made.backend}` };
|
|
1457
1747
|
else roleReviewerUnavailableReason = safeLogText(made.reason, 400);
|
|
1458
1748
|
} catch (error) {
|
|
1459
1749
|
roleReviewerUnavailableReason = roleAcpErrorReason(error);
|
|
@@ -1482,16 +1772,17 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1482
1772
|
const previousHeads = savedReviewHeads(pr);
|
|
1483
1773
|
const previousRoundCount = previousHeads.length;
|
|
1484
1774
|
const reason = opts.overCapReason?.trim();
|
|
1775
|
+
const authorization = previousRoundCount >= 5 ? readCapOverride(pr) : undefined;
|
|
1485
1776
|
deps.observeDoctorReview?.('round-counted', { pr, previousRoundCount, round: previousRoundCount + 1 });
|
|
1486
1777
|
const opAllowed = previousRoundCount >= 5 && opAllowsReviewOverCap(pr);
|
|
1487
1778
|
if (previousRoundCount >= 5) {
|
|
1488
1779
|
deps.observeDoctorReview?.('cap-attempt', { pr, previousRoundCount, round: previousRoundCount + 1, reasonProvided: Boolean(reason), opAllowed }, { level: 'warn' });
|
|
1489
1780
|
}
|
|
1490
|
-
if (previousRoundCount >= 5 && (!
|
|
1781
|
+
if (previousRoundCount >= 5 && (!opAllowed || (!authorization && !reason && !opts.reviewerMixCapClaimed))) {
|
|
1491
1782
|
const refusalHead = prHeadCommit(pr, deps).value;
|
|
1492
1783
|
const message = !opAllowed
|
|
1493
1784
|
? `PR ${pr}: r5 상한 초과 리뷰는 OP traffic.json reviewOverCapAllow 허용 목록에 있어야 합니다.`
|
|
1494
|
-
: `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다.
|
|
1785
|
+
: `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. OP 허용 상태와 --over-cap-reason <사유>가 필요합니다.`;
|
|
1495
1786
|
deps.observeDoctorReview?.('cap-refused', { pr, head: refusalHead, previousRoundCount, round: previousRoundCount + 1, reason: opAllowed ? 'missing-reason' : 'not-op-allowlisted' }, { level: 'warn' });
|
|
1496
1787
|
deps.error(message);
|
|
1497
1788
|
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: refusalHead });
|
|
@@ -1499,9 +1790,81 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1499
1790
|
continue;
|
|
1500
1791
|
}
|
|
1501
1792
|
const diffRead = readDiffAtHead(pr, deps);
|
|
1502
|
-
if (
|
|
1503
|
-
|
|
1504
|
-
|
|
1793
|
+
if (opts.reviewerMixExpectedHead && diffRead.headCommit !== opts.reviewerMixExpectedHead) {
|
|
1794
|
+
const refusal = { pr, reviewed: false, verdict: null, mustFix: [], shouldFix: [],
|
|
1795
|
+
refusal: 'reviewer-mix-head-changed', stale: true, headCommit: diffRead.headCommit,
|
|
1796
|
+
expectedHeadCommit: opts.reviewerMixExpectedHead };
|
|
1797
|
+
deps.log('review.lane-head-changed', { pr, expectedHead: opts.reviewerMixExpectedHead,
|
|
1798
|
+
observedHead: diffRead.headCommit }, { level: 'warn' });
|
|
1799
|
+
if (opts.json || opts.save !== undefined) results.push(refusal);
|
|
1800
|
+
failed += 1;
|
|
1801
|
+
continue;
|
|
1802
|
+
}
|
|
1803
|
+
if (previousRoundCount >= 5 && authorization && diffRead.headCommit.toLowerCase() === authorization.head && !opts.reviewerMixCapClaimed) {
|
|
1804
|
+
const message = `PR ${pr}: 동일 head는 이미 승인 소모 기록이 있습니다.`;
|
|
1805
|
+
deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'same-head-already-used' }, { level: 'warn' });
|
|
1806
|
+
deps.error(message);
|
|
1807
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1808
|
+
failed += 1;
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1811
|
+
if (previousRoundCount >= 5 && authorization && reason && reason !== authorization.reason) {
|
|
1812
|
+
const message = `PR ${pr}: 기존 PR 승인의 사유와 일치하지 않습니다.`;
|
|
1813
|
+
deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'authorization-reason-mismatch' }, { level: 'warn' });
|
|
1814
|
+
deps.error(message);
|
|
1815
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1816
|
+
failed += 1;
|
|
1817
|
+
continue;
|
|
1818
|
+
}
|
|
1819
|
+
let mergeOnlyDeltaRange: { base: string; head: string } | undefined;
|
|
1820
|
+
if (previousRoundCount >= 5 && authorization && !opts.reviewerMixCapClaimed) {
|
|
1821
|
+
const git = deps.git;
|
|
1822
|
+
if (!git || diffRead.source !== 'sha-pinned' || diffRead.headCommitState !== 'known'
|
|
1823
|
+
|| diffRead.currentHeadCommitState !== 'known' || diffRead.stale || diffRead.diff.status !== 0) {
|
|
1824
|
+
const message = `PR ${pr}: 후속 head의 merge-only 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
|
|
1825
|
+
deps.error(message);
|
|
1826
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1827
|
+
failed += 1;
|
|
1828
|
+
continue;
|
|
1829
|
+
}
|
|
1830
|
+
const savedRecords = savedReviewRecords(pr);
|
|
1831
|
+
const latestReviewed = savedRecords.reduce<(typeof savedRecords)[number] | undefined>(
|
|
1832
|
+
(latest, record) => !latest || record.reviewedAt > latest.reviewedAt ? record : latest, undefined,
|
|
1833
|
+
);
|
|
1834
|
+
const classificationBase = latestReviewed?.head ?? authorization.head;
|
|
1835
|
+
const ancestry = git(['merge-base', '--is-ancestor', classificationBase, diffRead.headCommit], 10_000);
|
|
1836
|
+
const parents = git(['rev-list', '--parents', '-n', '1', diffRead.headCommit], 10_000);
|
|
1837
|
+
const parentFields = parents.stdout.trim().split(/\s+/);
|
|
1838
|
+
const headIsMerge = parentFields.length > 2;
|
|
1839
|
+
const deltaHead = headIsMerge ? parentFields[1] : diffRead.headCommit;
|
|
1840
|
+
if ((ancestry.status !== 0 && ancestry.status !== 1) || parents.status !== 0 || parentFields[0]?.toLowerCase() !== diffRead.headCommit.toLowerCase()
|
|
1841
|
+
|| !COMMIT_OID.test(deltaHead) || classificationBase === diffRead.headCommit.toLowerCase()) {
|
|
1842
|
+
const message = `PR ${pr}: 후속 head ancestry 또는 parent 정보를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
|
|
1843
|
+
deps.error(message);
|
|
1844
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1845
|
+
failed += 1;
|
|
1846
|
+
continue;
|
|
1847
|
+
}
|
|
1848
|
+
// A non-ancestor head can be a force-push rewind or rebase. It is still
|
|
1849
|
+
// reviewed from the pinned full PR diff; only a proven descendant can
|
|
1850
|
+
// qualify for the merge-only delta path.
|
|
1851
|
+
if (ancestry.status === 0) {
|
|
1852
|
+
// Non-merge commits brought in from main are reachable but are not on
|
|
1853
|
+
// this first-parent line. A merge-only head ends at its first parent;
|
|
1854
|
+
// a later PR commit remains in the candidate range.
|
|
1855
|
+
const commits = git(['rev-list', '--first-parent', '--no-merges', `${classificationBase}..${deltaHead}`], 10_000);
|
|
1856
|
+
if (commits.status !== 0) {
|
|
1857
|
+
const message = `PR ${pr}: 후속 head의 PR 변경 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
|
|
1858
|
+
deps.error(message);
|
|
1859
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1860
|
+
failed += 1;
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1863
|
+
if (commits.stdout.trim() === '') mergeOnlyDeltaRange = { base: classificationBase, head: diffRead.headCommit.toLowerCase() };
|
|
1864
|
+
}
|
|
1865
|
+
} else if (previousRoundCount >= 5 && reason && !opts.reviewerMixCapClaimed) {
|
|
1866
|
+
// Claim only the exact SHA-pinned diff that the reviewer will see; never spend an OP
|
|
1867
|
+
// authorization on a separately read head that may move before readDiffAtHead.
|
|
1505
1868
|
const claimable = diffRead.source === 'sha-pinned' && diffRead.headCommitState === 'known'
|
|
1506
1869
|
&& diffRead.currentHeadCommitState === 'known' && !diffRead.stale && diffRead.diff.status === 0;
|
|
1507
1870
|
if (!claimable || !claimCapOverride(pr, diffRead.headCommit, reason, deps.now())) {
|
|
@@ -1514,6 +1877,28 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1514
1877
|
}
|
|
1515
1878
|
deps.observeDoctorReview?.('cap-override', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason }, { level: 'warn' });
|
|
1516
1879
|
}
|
|
1880
|
+
if (mergeOnlyDeltaRange) {
|
|
1881
|
+
const delta = deps.git?.(['diff', '--no-ext-diff', `${mergeOnlyDeltaRange.base}...${mergeOnlyDeltaRange.head}`], 25_000);
|
|
1882
|
+
if (!delta || delta.status !== 0) {
|
|
1883
|
+
const message = `PR ${pr}: merge-only 후속 head의 delta diff를 고정할 수 없습니다.`;
|
|
1884
|
+
deps.error(message);
|
|
1885
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1886
|
+
failed += 1;
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1889
|
+
diffRead.diff = delta;
|
|
1890
|
+
diffRead.baseCommit = mergeOnlyDeltaRange.base;
|
|
1891
|
+
}
|
|
1892
|
+
if (previousRoundCount >= 5 && authorization && !opts.reviewerMixCapClaimed && !claimCapOverride(pr, diffRead.headCommit, authorization.reason, deps.now())) {
|
|
1893
|
+
const message = `PR ${pr}: 후속 head 승인 사용 기록을 남기지 못했습니다.`;
|
|
1894
|
+
deps.error(message);
|
|
1895
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
|
|
1896
|
+
failed += 1;
|
|
1897
|
+
continue;
|
|
1898
|
+
}
|
|
1899
|
+
if (previousRoundCount >= 5 && authorization && !opts.reviewerMixCapClaimed) {
|
|
1900
|
+
deps.observeDoctorReview?.('cap-override', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: authorization.reason }, { level: 'warn' });
|
|
1901
|
+
}
|
|
1517
1902
|
const localHeadComparison = compareLocalHead(pr, { value: diffRead.headCommit, state: diffRead.headCommitState }, deps);
|
|
1518
1903
|
const { diff } = diffRead;
|
|
1519
1904
|
const baseReviewerContext = hasProvidedReviewerContext
|
|
@@ -1789,7 +2174,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1789
2174
|
// An explicit `--acp-model` is the operator's model choice: it is not silently swapped for GLM.
|
|
1790
2175
|
// GLM that throws or also ends without a verdict keeps the claude result, and says so (`glmReviewed`).
|
|
1791
2176
|
let claudeFallbackGlm: { reason: string; model: string; glmReviewed: boolean; glmFailureReason?: string } | undefined;
|
|
1792
|
-
if (useAcp && !roleReview && !acpModel && canonicalizeBackendId(acpBackend) === 'claude' && review.reviewed !== true) {
|
|
2177
|
+
if (useAcp && !roleReview && !acpModel && !opts.disableClaudeGlmFallback && canonicalizeBackendId(acpBackend) === 'claude' && review.reviewed !== true) {
|
|
1793
2178
|
const reason = safeLogText(review.failureReason || 'reviewed=false', 400);
|
|
1794
2179
|
debug.log('review.acp', 'claude-fallback-glm', { reason }, { level: 'warn' });
|
|
1795
2180
|
fallbackAttempted = true;
|
|
@@ -1820,6 +2205,50 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1820
2205
|
...(reviewPin && reviewedOnPin ? { reviewCwdCommit: reviewPin.commit } : {}),
|
|
1821
2206
|
...(reviewCwdPinFallbackReason ? { reviewCwdPinFallbackReason } : {}),
|
|
1822
2207
|
};
|
|
2208
|
+
// ⭐ 착지 관문 — 요청한 리뷰어와 실제로 판정을 낸 리뷰어를 대조한다. 판정이 나온 리뷰에만
|
|
2209
|
+
// 의미가 있다(리뷰가 없으면 근거도 없고, 실패는 기존 회계가 이미 센다).
|
|
2210
|
+
const acpActual = (backendText: string | undefined): LandingGateActual => {
|
|
2211
|
+
const backend = normalizedReviewBackend(backendText);
|
|
2212
|
+
return backend ? { kind: 'acp', value: `acp:${backend}`, backend } : { kind: 'unknown', value: 'unmeasured' };
|
|
2213
|
+
};
|
|
2214
|
+
const landingGateRequest: LandingGateRequest | undefined = requestedModel
|
|
2215
|
+
? { kind: 'api-model', value: opts.model?.trim() || requestedModel, model: explicitApiModel ?? requestedModel }
|
|
2216
|
+
: useAcp
|
|
2217
|
+
? { kind: 'acp-backend', value: `acp:${canonicalizeBackendId(acpBackend)}`, backend: acpBackend }
|
|
2218
|
+
: reviewerSource === 'role-config' && opts.roleReviewer
|
|
2219
|
+
? { kind: 'role-lane', value: `acp:${opts.roleReviewer.provider}` }
|
|
2220
|
+
: undefined;
|
|
2221
|
+
const landingGateActual: LandingGateActual = reviewRoute === 'acp-fallback'
|
|
2222
|
+
? acpActual(fallbackBackend)
|
|
2223
|
+
: reviewRoute === 'acp'
|
|
2224
|
+
? acpActual(roleReview && prRoleReviewer ? prRoleReviewer.model.replace(/^acp:/, '') : acpBackend)
|
|
2225
|
+
: ((): LandingGateActual => {
|
|
2226
|
+
const apiModel = (selectedModel ?? '').trim();
|
|
2227
|
+
if (!apiModel) return { kind: 'unknown', value: 'unmeasured' };
|
|
2228
|
+
return {
|
|
2229
|
+
kind: 'api', value: `api:${apiModel}`, model: apiModel,
|
|
2230
|
+
...(responded.provider ? { respondedProvider: responded.provider } : {}),
|
|
2231
|
+
...(responded.model ? { respondedModel: responded.model } : {}),
|
|
2232
|
+
};
|
|
2233
|
+
})();
|
|
2234
|
+
const landingGate = review.reviewed === true
|
|
2235
|
+
? landingGateOutcome({ pr, reviewRoute, request: landingGateRequest, actual: landingGateActual, deniedBackends: effectiveReviewDenyBackends })
|
|
2236
|
+
: undefined;
|
|
2237
|
+
if (landingGate && landingGate.state !== 'consistent') {
|
|
2238
|
+
deps.error(landingGate.warning);
|
|
2239
|
+
deps.log('landing-gate', {
|
|
2240
|
+
pr: safeLogText(pr), decision: landingGate.state, reviewRoute,
|
|
2241
|
+
requested: safeLogText(landingGate.requested), actual: safeLogText(landingGate.actual),
|
|
2242
|
+
...(landingGate.state === 'denied' ? { deniedBackend: landingGate.deniedBackend } : {}),
|
|
2243
|
+
}, { level: 'warn' });
|
|
2244
|
+
}
|
|
2245
|
+
const landingGateAdmitted = landingGate?.state !== 'denied';
|
|
2246
|
+
const landingGateDeniedBackend = landingGate?.state === 'denied' ? landingGate.deniedBackend : undefined;
|
|
2247
|
+
const landingGateFields: Record<string, unknown> = landingGate?.state === 'mismatch'
|
|
2248
|
+
? { landingGateDecision: 'mismatch', landingGateRequested: landingGate.requested, landingGateActual: landingGate.actual }
|
|
2249
|
+
: landingGate?.state === 'denied'
|
|
2250
|
+
? { landingGateDecision: 'denied', landingGateRequested: landingGate.requested, landingGateActual: landingGate.actual, landingGateDeniedBackend: landingGate.deniedBackend }
|
|
2251
|
+
: {};
|
|
1823
2252
|
if (!fallbackAttempted) {
|
|
1824
2253
|
fallbackNotAttemptedReason = useAcp ? 'explicit-acp' : requestedModel && review.reviewed !== true ? 'explicit-model' : 'primary-review-succeeded';
|
|
1825
2254
|
}
|
|
@@ -1844,7 +2273,27 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1844
2273
|
const reviewerSelection = {
|
|
1845
2274
|
...reviewerSourceObservation(),
|
|
1846
2275
|
...(roleReviewerFallbackReason !== undefined ? { roleReviewerFallbackReason } : {}),
|
|
2276
|
+
...(opts.reviewerMixPrimaryLane ? { reviewerMixPrimaryLane: opts.reviewerMixPrimaryLane,
|
|
2277
|
+
reviewerMixSelectedLane: opts.reviewerMixAttemptLane } : {}),
|
|
1847
2278
|
};
|
|
2279
|
+
// The reviewer owns its finding severity. A missing citation is separate evidence,
|
|
2280
|
+
// never a new must-fix or a verified defect. Keep unreadable heads distinct too.
|
|
2281
|
+
const reviewRepositoryPath = deps.reviewRepositoryPath;
|
|
2282
|
+
const findingPathHeadChecks = review.reviewed === true && landingGateAdmitted
|
|
2283
|
+
&& diffRead.headCommitState === 'known' && reviewRepositoryPath
|
|
2284
|
+
? ([...review.mustFix.map(finding => ({ severity: 'mustFix' as const, finding })),
|
|
2285
|
+
...review.shouldFix.map(finding => ({ severity: 'shouldFix' as const, finding }))]
|
|
2286
|
+
.map(({ severity, finding }) => ({ severity, finding,
|
|
2287
|
+
...checkCitedReviewPathsAtHead(finding, reviewRepositoryPath, diffRead.headCommit) }))
|
|
2288
|
+
.filter(check => check.paths.length > 0))
|
|
2289
|
+
: [];
|
|
2290
|
+
const pathWarnings = findingPathHeadChecks.flatMap(check => check.paths
|
|
2291
|
+
.filter(path => path.status !== 'present')
|
|
2292
|
+
.map(path => `${path.status === 'missing' ? '경로 미확인' : '경로 검증 불가'}: ${path.path} (PR head ${check.head})`));
|
|
2293
|
+
if (pathWarnings.length) deps.log('finding-path-head-check', {
|
|
2294
|
+
pr, headCommit: diffRead.headCommit, missing: findingPathHeadChecks.flatMap(check => check.paths).filter(path => path.status === 'missing').length,
|
|
2295
|
+
unreadable: findingPathHeadChecks.flatMap(check => check.paths).filter(path => path.status === 'unreadable').length,
|
|
2296
|
+
}, { level: 'warn' });
|
|
1848
2297
|
// ⚠️ verdict=fail 은 **정상 동작**(리뷰가 일한 것)이라 warn 으로 올리지 않는다. 대신 `reviewed:false`
|
|
1849
2298
|
// (fail-soft pass·리뷰 미실행)는 조용히 통과로 읽히면 위험하므로 warn 이다.
|
|
1850
2299
|
deps.log('done',
|
|
@@ -1864,6 +2313,7 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1864
2313
|
acceptanceChars: goalAcceptance.acceptanceChars,
|
|
1865
2314
|
...reviewerSelection,
|
|
1866
2315
|
...reviewCwdOutput,
|
|
2316
|
+
...landingGateFields,
|
|
1867
2317
|
},
|
|
1868
2318
|
{ level: review.reviewed === false ? 'warn' : 'info' });
|
|
1869
2319
|
// --acp 는 대표가 명시 요청한 리뷰 — fail-soft(reviewed=false)면 조용히 pass 하지 말고 표면화(관측=acp-review).
|
|
@@ -1877,20 +2327,34 @@ async function runSelfReviewCliCommandPinned(
|
|
|
1877
2327
|
}
|
|
1878
2328
|
const contextOutput = reviewerContextOutput(reviewerContext, decompositionContext);
|
|
1879
2329
|
const jsonReview = review.reviewed === true ? review : { ...review, verdict: null };
|
|
1880
|
-
|
|
1881
|
-
|
|
2330
|
+
// ⛔ 금지 백엔드가 낸 판정은 «근거 거부»다 — verdict·mustFix 를 그대로 실어 보내면 읽는 쪽이
|
|
2331
|
+
// 그것을 착지 판정으로 쓴다(관문도 reviewed===true 를 근거 조건으로 본다).
|
|
2332
|
+
const refusalOverride = landingGateAdmitted ? {} : { reviewed: false, verdict: null, refusal: 'review-forbidden-acp-backend' as const };
|
|
2333
|
+
if (opts.json || opts.save !== undefined) results.push({ pr, model: selectedModel, ...jsonReview, ...reviewProvenance, ...respondedOutput, ...reviewerSelection, ...reviewCwdOutput, ...provenance, ...contextOutput, ...refusalOverride, ...landingGateFields, findingPathHeadChecks, pathWarnings, evidence: evidence.evidence, prDiffFiles: evidence.prDiffFiles, ...(evidence.authoredFiles !== undefined ? { authoredFiles: evidence.authoredFiles } : {}) });
|
|
2334
|
+
if (!opts.json) {
|
|
2335
|
+
if (!landingGateAdmitted) deps.print(`\n━━ PR ${pr} (${selectedModel}) ━━\n${renderProvenance(diffRead)}\n⛔ LANDING GATE: review-forbidden-acp-backend (${landingGateDeniedBackend ?? 'unknown'}) — 이 리뷰는 착지 근거가 아닙니다.\n${reviewerContextStatus}`);
|
|
2336
|
+
else deps.print(`\n━━ PR ${pr} (${selectedModel}) ━━\n${renderProvenance(diffRead)}\n${evidenceLine}\n${reviewerContextStatus}\n${deps.renderReview(review)}${pathWarnings.length ? `\n${pathWarnings.join('\n')}` : ''}`);
|
|
2337
|
+
}
|
|
1882
2338
|
// REVIEW-ERROR-RC — 기본(API)·role 경로가 1차·폴백 모두 실패해 reviewed≠true 로 끝나도 «못 리뷰한 PR» 이다(verdict:null).
|
|
1883
|
-
|
|
2339
|
+
// ⛔ 착지 관문 거부도 같은 회계다 — 금지 백엔드가 판정을 냈으면 리뷰가 «성공»해도 근거가 아니다(rc≠0).
|
|
2340
|
+
if (review.reviewed !== true || !landingGateAdmitted) failed += 1;
|
|
1884
2341
|
if (opts.save !== undefined) {
|
|
1885
|
-
if (
|
|
2342
|
+
if (!landingGateAdmitted) {
|
|
2343
|
+
deps.error(`PR ${pr}: --save 거부 — acp.reviewDenyBackends 가 금지한 백엔드(${landingGateDeniedBackend ?? 'unknown'})의 결과는 착지 근거로 저장하지 않습니다.`);
|
|
2344
|
+
} else if (review.reviewed !== true || diffRead.headCommitState !== 'known' || diffRead.currentHeadCommitState !== 'known' || diffRead.currentHeadCommit !== diffRead.headCommit || diffRead.headCommit.length !== 40) {
|
|
1886
2345
|
deps.error(`PR ${pr}: --save 불가 — 완료된 리뷰와 확인된 40자 PR head가 필요합니다.`);
|
|
1887
2346
|
if (review.reviewed === true) failed += 1;
|
|
1888
2347
|
} else {
|
|
1889
2348
|
const path = join(effectiveInstanceRoot(), 'review-results', `${opts.save}-${pr}-${diffRead.headCommit.slice(0, 12)}.json`);
|
|
1890
|
-
const
|
|
2349
|
+
const rawResult = results.at(-1);
|
|
2350
|
+
const normalized = rawResult && typeof rawResult === 'object'
|
|
2351
|
+
? normalizeSavedReviewMustFix(rawResult)
|
|
2352
|
+
: { result: rawResult, count: 0 };
|
|
2353
|
+
const result = normalized.result;
|
|
1891
2354
|
try {
|
|
1892
2355
|
mkdirSync(dirname(path), { recursive: true });
|
|
1893
2356
|
writeFileSync(path, selfReviewJsonLine([result]));
|
|
2357
|
+
if (normalized.count > 0) deps.log('mustfix-normalized', { pr, head: diffRead.headCommit, count: normalized.count });
|
|
1894
2358
|
} catch (error) {
|
|
1895
2359
|
failed += 1;
|
|
1896
2360
|
deps.error(`PR ${pr}: --save 실패: ${error instanceof Error ? error.message : String(error)}`);
|