elanous 0.2.38 → 0.2.40
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/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{7954.4f7a8832663ee979.js → 1060.014f1f01a17aec26.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 1281.d81877e35b9068f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2104.70e086d5174a4736.js → 1350.59f40e39e02d91b1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.162bb2d9d699e82a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +286 -0
- package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +90 -0
- package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +104 -0
- package/apps/pwa/out/_next/static/chunks/2047.8f23e210995d4548.js +2 -0
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.js → 2066.a77257c8c350770a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8019.21ca554a821dad01.js → 2177.df8547f9d7215c4e.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.js → 2226.2cf61ec781827219.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2281-b8cede695c6c650e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6493.27ad77de7aac7966.js → 2499.02fbfd18126c10c0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7628.6b16863ac3972333.js → 2522.f2766b76d22c8bdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9299.24e2a7d9b6d1f91b.js → 261.0d471e8aded799f3.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +27 -0
- package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2774-719820e3f5b2a3eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2829-734fe8bf2eee7347.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7524.ce973525d30b3d52.js → 3330.7443183b7e6fdbdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3124-561f7f037943cde2.js → 3746-f80a78f220bf37b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +24 -0
- package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{bb6987f9.3647e1a23b0e3217.js → 3b355b3d.6f73c98bf6f9c749.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +36 -0
- package/apps/pwa/out/_next/static/chunks/{8994d93e.33ba491f95345fc2.js → 409c787b.e48c5bec8ec10456.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5041-5aada92ca215ffdd.js → 413-24c8284bda08241d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +287 -0
- package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4351.0f37a6db2b34d50b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5638.107314dc479e2f37.js → 470.51a72a2348306455.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8487.291666583bebe640.js → 4769.9fd582071301f382.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8509.3a54d4e61893d7cb.js → 483.725e4a61be922788.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.js → 4864a2ca.1c1c280a7772c5e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +74 -0
- package/apps/pwa/out/_next/static/chunks/{8879.ac06755bcf3e44a1.js → 5383.bdfa5d886e39a826.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 5436.fdf6fa8ae3e9588d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5622.94893f5aea7185d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +8 -0
- package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +62 -0
- package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +94 -0
- package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7161-8f22db3ec5ed005e.js → 6051-0ae955eedb10adb9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3291.f6c1005387d514bd.js → 6257.c0037b8949239f5e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6624.981ef7caeb680560.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5203.51e5d8b5f1dcfe53.js → 6749.0744ce6eb08d40e9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1938.0e6c60ee91c4d7f5.js → 6908.06008c67f6380ea9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{de8b930d.d94c0f42acf807fc.js → 6cc1d1d6.9a98dd4622f1afc6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7515.1ad6efe157fa4448.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8086.1ab9103c41be884f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1026-44010f405704050c.js → 8272-025653884f9645d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.js → 8357.1aaa713b052a78b1.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4199-f7c6eb40cd0322f8.js → 8639-92c11d069792429e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9069.657590a84afb8fac.js +41 -0
- package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9175.2de5209a5ce6f68a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.js → 9189505a.980427ac048c8c60.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9992.07ce73c10bd5e6a1.js +79 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-866aac5ff226a7f3.js → page-ba957ff875a026a0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4edb8df90f4537ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-fca2e59a81744d9e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-139d722de1dcd6c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-ccde99f07aaf71f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → b84cad00.594027ebe0531fe2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → ca3702f8.2913182e73889fa2.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{3f0de3de-2340c532c00395db.js → d5d3cefc-373c4eb722ed848b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-4b12a946f352cee2.js → framework-002b472a66935d31.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
- package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
- package/graphs/demo/persona-marketer/recipes.yaml +19 -0
- package/graphs/video/explainer-line.yaml +4 -1
- package/package.json +1 -1
- package/scripts/dead-code/report.ts +169 -0
- package/scripts/lib/morning-report-options.ts +3 -4
- package/scripts/lib/tui-regress-evidence.ts +56 -0
- package/scripts/morning-report.ts +5 -1
- package/scripts/public-export.ts +15 -7
- package/scripts/release-loop/export-check-node.ts +21 -3
- package/scripts/release-loop/gate-node.ts +379 -48
- package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
- package/scripts/release-loop/gate-shard-receipts.ts +89 -0
- package/scripts/release-loop/gate-wall.ts +5 -5
- package/scripts/release-loop/preflight.ts +6 -2
- package/scripts/release-loop/resume-release.ts +20 -5
- package/scripts/release-loop/resume.ts +48 -0
- package/scripts/release-loop/version-node.ts +7 -2
- package/scripts/release-story/draft.ts +1 -1
- package/scripts/research-bench/README.md +53 -0
- package/scripts/research-bench/questions.json +66 -0
- package/scripts/research-bench/rubric.md +33 -0
- package/scripts/research-bench/run.ts +523 -0
- package/scripts/tui-regress.ts +85 -10
- package/src/acp/core-turn-bridge.ts +8 -0
- package/src/agent/autonomous-tools.ts +10 -3
- package/src/agent/monad-agent-turn.ts +4 -1
- package/src/agent/registry.ts +26 -2
- package/src/agent/shared-app-tools.ts +1 -1
- package/src/agent/surface-ux/build.ts +12 -3
- package/src/agent/surface-ux/types.ts +1 -1
- package/src/agent/task-notification.ts +75 -6
- package/src/agent/types.ts +3 -0
- package/src/agent-mission/driver.ts +29 -3
- package/src/agent-mission/mission-cli.ts +2 -1
- package/src/agent-substrate/review-context-pack.ts +365 -0
- package/src/agent-substrate/self-review-cli.ts +226 -17
- package/src/ask-user-question/index.ts +6 -0
- package/src/ask-user-question/inline-resolver.ts +49 -0
- package/src/auto-research/question-ladder-contract.ts +22 -3
- package/src/auto-research/research-turn.ts +350 -17
- package/src/autopilot/agent-loop.ts +1 -1
- package/src/autopilot/pty-control-loop.ts +8 -1
- package/src/boot/daemon-tools/index.ts +4 -3
- package/src/boot/daemon-tools/self-implement.ts +270 -2
- package/src/boot/daemon-tools/types.ts +2 -0
- package/src/budget/llm-cost.ts +44 -5
- package/src/budget/unified-usage.ts +17 -1
- package/src/capture/tui-self-report.ts +14 -0
- package/src/chat/index.ts +33 -7
- package/src/cli/agent-cli.ts +43 -8
- package/src/cli/intake-cli.ts +22 -1
- package/src/cli/lesson-cli.ts +19 -3
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/pod-cli.ts +17 -2
- package/src/cli/pty-takeover-cli.ts +67 -7
- package/src/cli/release-cli.ts +52 -6
- package/src/cli/repo-cli.ts +2 -1
- package/src/cli/tasks-cli.ts +36 -9
- package/src/control-plane/ledger.ts +21 -4
- package/src/core-turn/run-core-turn.ts +44 -3
- package/src/core-turn/run-goal-loop.ts +152 -8
- package/src/core-turn/types.ts +9 -0
- package/src/dashboard/chat/acp-chat.ts +2 -2
- package/src/dashboard/classic-sigquit.ts +16 -0
- package/src/dashboard/index.ts +321 -27
- package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
- package/src/dashboard/input/external-input-host.ts +2 -0
- package/src/dashboard/sidetab-runtime.ts +228 -0
- package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
- package/src/dashboard/term-slash-runtime.ts +16 -18
- package/src/dashboard/turn-preamble.ts +2 -0
- package/src/domains/knowledge.ts +1 -1
- package/src/esc-abort-gate.ts +33 -1
- package/src/execution-loop/launch-gate.ts +206 -1
- package/src/graph-runner/graph-cli.ts +6 -4
- package/src/graph-runner/runner.ts +31 -9
- package/src/graph-wizard/generate.ts +16 -7
- package/src/graph-wizard/mission-compose.ts +201 -0
- package/src/grok/agent-search.ts +8 -2
- package/src/grok/credential.ts +5 -0
- package/src/grounding/ref-index.ts +11 -0
- package/src/grounding/ref-vector.ts +61 -0
- package/src/grounding/sources-cli.ts +2 -2
- package/src/grounding/sources.ts +15 -1
- package/src/harness/harness-cli-command.ts +38 -9
- package/src/harness/harness-pod-dispatch.ts +7 -1
- package/src/index.ts +18 -4
- package/src/input/external-input-queue.ts +10 -0
- package/src/intake-plane/collect-telegram-saved.ts +36 -1
- package/src/intake-plane/intake-to-tasks.ts +246 -3
- package/src/lessons/friction-ledger.ts +154 -0
- package/src/live-supply/collector.ts +149 -0
- package/src/live-supply/probes.ts +52 -0
- package/src/live-supply/snapshot.ts +40 -0
- package/src/llm.ts +431 -76
- package/src/loops/orchestrator/tick.ts +8 -0
- package/src/nexus/api/harness-api.ts +2 -1
- package/src/pty/snapshot.py +132 -0
- package/src/pty-shell/pty-control-ipc.ts +29 -2
- package/src/pty-shell/pty-manifest.ts +59 -3
- package/src/pty-shell/registry.ts +2 -0
- package/src/pty-shell/tui-run-state.ts +80 -3
- package/src/release-loop/gate-host-reservation.ts +13 -4
- package/src/release-loop/gate-shard-ledger.ts +68 -0
- package/src/release-loop/merged-pr-checklist.ts +25 -2
- package/src/release-loop/rehearsal-shard-plan.ts +6 -1
- package/src/release-loop/rehearsal.ts +27 -0
- package/src/research/edge-decision.ts +124 -15
- package/src/research/gap-followup.ts +249 -0
- package/src/research/lenses/counter-evidence.ts +100 -0
- package/src/research/lenses/working-backwards.ts +89 -0
- package/src/research/plugin-discovery.ts +242 -0
- package/src/research-bridge/invoke.ts +4 -2
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/ask-launch-flow.ts +34 -106
- package/src/self-dev/dev-cli.ts +2 -0
- package/src/self-dev/dev-pipeline.ts +8 -4
- package/src/self-dev/graph-journey-route.ts +10 -2
- package/src/self-dev/launch-preflight-text.ts +2 -2
- package/src/self-dev/launch-preflight.ts +38 -7
- package/src/self-dev/orchestrate-cli.ts +1 -0
- package/src/self-dev/run-supervisor.ts +19 -0
- package/src/self-implement/device-first.ts +8 -2
- package/src/self-implement/doctor-visit.ts +76 -58
- package/src/self-implement/gate-artifacts.ts +3 -0
- package/src/self-implement/gate-baseline.ts +75 -4
- package/src/self-implement/gate-cli.ts +317 -9
- package/src/self-implement/gate-receipt-registry.ts +180 -0
- package/src/self-implement/gate-remote.ts +145 -22
- package/src/self-implement/goal-author-clarification.ts +178 -24
- package/src/self-implement/goal-author-decompose.ts +24 -15
- package/src/self-implement/goal-author.ts +9 -5
- package/src/self-implement/host-regate.ts +120 -45
- package/src/self-implement/impl-findings-feedback.ts +188 -0
- package/src/self-implement/knowhow-pack.ts +189 -10
- package/src/self-implement/off-diff-evidence.ts +124 -0
- package/src/self-implement/orchestrator.ts +85 -7
- package/src/self-implement/run-ledger.ts +46 -8
- package/src/self-implement/run-stop.ts +12 -0
- package/src/self-implement/seams.ts +6 -3
- package/src/self-implement/self-implement-cli.ts +4 -2
- package/src/session/chat.ts +89 -15
- package/src/session-runtime/provider-circuit.ts +140 -0
- package/src/shell-runner/file-engine.ts +1 -0
- package/src/shell-runner/types.ts +4 -0
- package/src/sidetab-core/model.ts +176 -0
- package/src/skills/tools/schedule-wakeup.ts +23 -1
- package/src/skills/tools/shell.ts +51 -5
- package/src/steward/directive-audit.ts +354 -0
- package/src/surface/child-process.ts +31 -0
- package/src/surface/tui-stderr-owner.ts +48 -0
- package/src/task-agent/cover.ts +30 -12
- package/src/task-agent/judge.ts +56 -0
- package/src/task-agent/postland-card.ts +35 -2
- package/src/task-agent/rejudge-on-head.ts +46 -2
- package/src/task-agent/repair-cycle.ts +1 -1
- package/src/task-agent/task-hand.ts +129 -24
- package/src/task-agent/tier-split.ts +105 -21
- package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
- package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +27 -2
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +186 -33
- package/src/tool-runtime/skill-exec-runtime.ts +95 -5
- package/src/tui/entry.ts +15 -2
- package/src/tui/inline-choice.ts +188 -0
- package/src/tui/sidetab/list.ts +2 -176
- package/src/tui/slash/term.ts +12 -1
- package/src/tui-client/dashboard-session.ts +7 -1
- package/src/user-config.ts +34 -4
- package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
- package/src/ux-sim/fake-land-queue.ts +88 -0
- package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
- package/src/ux-sim/goal-interim-trace.ts +24 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +8 -13
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/explainer.ts +54 -2
- package/src/web-search/grok.ts +32 -6
- package/src/web-search/index.ts +8 -7
- package/src/workflow-runtime/node-catalog.ts +53 -4
- package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
- package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/2415.738b777642a02233.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
- package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
- package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
- package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
- package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
- package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
- package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
- package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
- /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { randomUUID } from 'node:crypto';
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
|
-
import { join } from 'node:path/posix';
|
|
5
|
+
import { basename, join, resolve } from 'node:path/posix';
|
|
6
6
|
import { prepareDeterministicChildEnvironment } from '../../scripts/lib/deterministic-env.js';
|
|
7
7
|
import { audit as auditEntryBudget, entryBudgetAffected } from '../../scripts/ratchets/next-tui-entry-budget.js';
|
|
8
8
|
import { withGateTestEnv } from '../../scripts/lib/gate-test-env.js';
|
|
@@ -14,11 +14,12 @@ import { runIosUnitTestGate } from '../../scripts/ci-ios-unit-tests.js';
|
|
|
14
14
|
import { runPwaBuildGate } from '../../scripts/ci-pwa-build-gate.js';
|
|
15
15
|
import { runMockModuleRestoreGate } from '../../scripts/ci-mock-module-restore-gate.js';
|
|
16
16
|
import { parseReviewDepthFromFilesJson } from '../agent-mission/review-depth.js';
|
|
17
|
-
import { buildGateBaselineReport, calculateGateTestCountChange, formatGateBaselineNote, formatGateTestCountNote, isGateTestFile, recheckTimeoutOnlyIntroducedFailures, runGateBaseline, type BaselineProcessResult, type BaselineProcessStatus, type GateTestFailure, type TimeoutRecheckRecord, type TimeoutRerunObservation } from './gate-baseline.js';
|
|
17
|
+
import { buildGateBaselineReport, calculateGateTestCountChange, formatGateBaselineNote, formatGateTestCountNote, isGateTestFile, recheckOutsideScopeFailures, recheckTimeoutOnlyIntroducedFailures, runGateBaseline, type BaselineProcessResult, type BaselineProcessStatus, type GateBaselineReport, type GateTestFailure, type InterferenceRecheckRecord, type TimeoutRecheckRecord, type TimeoutRerunObservation } from './gate-baseline.js';
|
|
18
18
|
import { resolveGateScope } from './gate-scope.js';
|
|
19
19
|
import { publicExposureFiles, runExposeGate } from './expose-gate.js';
|
|
20
20
|
import { getUserConfig } from '../user-config.js';
|
|
21
21
|
import { debug, redactSecretText } from '../debug/log.js';
|
|
22
|
+
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
22
23
|
import { buildDocumentGuardianIndex, formatDocumentGuardians } from './document-guardian-index.js';
|
|
23
24
|
import { buildImporterTestIndex, importerTestsNotInRunSet, isTestPath, type ImporterTestIndex } from './importer-test-index.js';
|
|
24
25
|
import { isCommentOnlySourceChange } from './comment-only-source.js';
|
|
@@ -38,6 +39,8 @@ import { defaultGateEnvKey, defaultRevResolver, resolveArtifactDir, writeGateArt
|
|
|
38
39
|
export interface SelfGateCliOptions {
|
|
39
40
|
base?: string;
|
|
40
41
|
pr?: string;
|
|
42
|
+
/** Bypass reuse of the last passing test radius; still write this run's receipt for the next invocation. */
|
|
43
|
+
noInherit?: boolean;
|
|
41
44
|
shards?: number;
|
|
42
45
|
/** Live shard bundle concurrency; default three, bounded to one through four. */
|
|
43
46
|
shardConcurrency?: number;
|
|
@@ -106,11 +109,11 @@ interface SelfGateCliDeps {
|
|
|
106
109
|
runTests?: (cwd: string, files: readonly string[]) => ProcessResult;
|
|
107
110
|
runBaseline?: (cwd: string, files: readonly string[], baseRef: string) => BaselineProcessResult;
|
|
108
111
|
runTimeoutRecheck?: (cwd: string, file: string, name: string, timeoutMs: number) => { observation?: TimeoutRerunObservation; elapsedMs: number; output: string };
|
|
112
|
+
runInterferenceRecheck?: (cwd: string, report: GateBaselineReport, baseRef: string, relatedTestFiles: readonly string[]) => GateBaselineReport;
|
|
109
113
|
runShards?: typeof runShardedGateTests;
|
|
110
114
|
runShardsAsync?: typeof runShardedGateTestsAsync;
|
|
111
115
|
/** Test seam for the live progress line. */
|
|
112
116
|
writeProgressStderr?: (line: string) => void;
|
|
113
|
-
now?: () => number;
|
|
114
117
|
runIsolationGate?: (out: GateOutput) => number;
|
|
115
118
|
runMockModuleRestoreGate?: (out: GateOutput) => number;
|
|
116
119
|
/** 모델 이름 하드코딩 래칫(🅕 #20521) — `pr land` 만 물고 하니스 무인 병합은 안 물면 위반이 main 에 들어가 남의 착지를 막는다(🅣 2026-09-25). */
|
|
@@ -128,12 +131,19 @@ interface SelfGateCliDeps {
|
|
|
128
131
|
/** `--artifact-dir` 전용 심 — 커밋 sha 해석(실패 = null) · 환경 키. */
|
|
129
132
|
resolveRev?: RevResolver;
|
|
130
133
|
envKey?: () => string;
|
|
134
|
+
/** Receipt-store seam for tests; production stores under ~/.elanous/gate-receipts. */
|
|
135
|
+
gateReceiptDir?: () => string;
|
|
136
|
+
now?: () => number;
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
/** `--artifact-dir` 가 쓸 재료 — 판정 경로가 «채우기만» 하고 읽지 않는다. */
|
|
134
140
|
interface GateArtifactCapture {
|
|
135
141
|
baseRef?: string;
|
|
136
142
|
testFiles?: readonly string[];
|
|
143
|
+
fullTestFiles?: readonly string[];
|
|
144
|
+
failedTestFiles?: readonly string[];
|
|
145
|
+
testReceiptMeasured?: boolean;
|
|
146
|
+
receiptDecision?: GateReceiptDecision;
|
|
137
147
|
sharded?: ReturnType<typeof runShardedGateTests>;
|
|
138
148
|
verdict?: string;
|
|
139
149
|
verdictLine?: string;
|
|
@@ -144,6 +154,7 @@ interface GateArtifactCapture {
|
|
|
144
154
|
unrunImporters?: number | null;
|
|
145
155
|
importerLookupFailed?: string;
|
|
146
156
|
timeoutRechecks?: readonly TimeoutRecheckRecord[];
|
|
157
|
+
interferenceRechecks?: readonly InterferenceRecheckRecord[];
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
/** SIDE-VERIFY ③ — summary 정수 칸: 게이트가 이미 낸 `result.baseline` ⊕ `unrunImporterTotal` 을 «옮기기만» 한다.
|
|
@@ -799,6 +810,7 @@ export function selectGateTestFiles(cwd: string, options: GateSelectionOptions =
|
|
|
799
810
|
export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): SelfGateCliResult {
|
|
800
811
|
const capture: GateArtifactCapture = {};
|
|
801
812
|
const result = runSelfGateCliCore(cwd, options, deps, capture, false) as SelfGateCliResult;
|
|
813
|
+
persistGateReceipt(cwd, capture, deps);
|
|
802
814
|
if (options.artifactDir !== undefined) emitGateArtifacts(cwd, options.artifactDir, result, capture, deps);
|
|
803
815
|
return result;
|
|
804
816
|
}
|
|
@@ -807,6 +819,7 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
|
|
|
807
819
|
export async function runSelfGateCliAsync(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): Promise<SelfGateCliResult> {
|
|
808
820
|
const capture: GateArtifactCapture = {};
|
|
809
821
|
const result = await runSelfGateCliCore(cwd, options, deps, capture, true);
|
|
822
|
+
persistGateReceipt(cwd, capture, deps);
|
|
810
823
|
if (options.artifactDir !== undefined) emitGateArtifacts(cwd, options.artifactDir, result, capture, deps);
|
|
811
824
|
return result;
|
|
812
825
|
}
|
|
@@ -830,6 +843,7 @@ function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCli
|
|
|
830
843
|
verdict: capture.verdict ?? null,
|
|
831
844
|
...(capture.verdictLine !== undefined ? { verdictLine: capture.verdictLine } : {}),
|
|
832
845
|
...(capture.timeoutRechecks ? { timeoutRechecks: capture.timeoutRechecks } : {}),
|
|
846
|
+
...(capture.interferenceRechecks ? { interferenceRechecks: capture.interferenceRechecks } : {}),
|
|
833
847
|
exitCode: result.exitCode,
|
|
834
848
|
counts: counts.counts,
|
|
835
849
|
...(counts.reason !== undefined ? { countsUnavailableReason: counts.reason } : {}),
|
|
@@ -844,6 +858,246 @@ function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCli
|
|
|
844
858
|
}
|
|
845
859
|
}
|
|
846
860
|
|
|
861
|
+
const GATE_RECEIPT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
862
|
+
const GATE_RECEIPT_SCHEMA = 1;
|
|
863
|
+
|
|
864
|
+
interface GateReceipt {
|
|
865
|
+
schema: 1;
|
|
866
|
+
createdAt: number;
|
|
867
|
+
repositoryHash: string;
|
|
868
|
+
branch: string;
|
|
869
|
+
baseSha: string;
|
|
870
|
+
headSha: string;
|
|
871
|
+
runtime: string;
|
|
872
|
+
environmentKey: string;
|
|
873
|
+
lockfileHash: string;
|
|
874
|
+
fullTestFiles: string[];
|
|
875
|
+
failedTestFiles: string[];
|
|
876
|
+
measured: boolean;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
interface GateReceiptIdentity extends Omit<GateReceipt, 'createdAt' | 'fullTestFiles' | 'failedTestFiles' | 'measured'> {
|
|
880
|
+
receiptPath: string;
|
|
881
|
+
receiptDir: string;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
interface GateReceiptDecision {
|
|
885
|
+
mode: 'full' | 'inherit';
|
|
886
|
+
reason: string;
|
|
887
|
+
identity?: GateReceiptIdentity;
|
|
888
|
+
sourceHead?: string;
|
|
889
|
+
runTestFiles?: readonly string[];
|
|
890
|
+
inheritedTestFiles?: readonly string[];
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function sha256(value: string | Buffer): string {
|
|
894
|
+
return createHash('sha256').update(value).digest('hex');
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
function normalizedRepositoryUrl(value: string): string | undefined {
|
|
898
|
+
const raw = value.trim();
|
|
899
|
+
if (!raw) return undefined;
|
|
900
|
+
if (!raw.includes('://')) {
|
|
901
|
+
const scp = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(raw);
|
|
902
|
+
if (scp) return `${scp[1].toLowerCase()}/${scp[2]}`.replace(/\.git$/i, '');
|
|
903
|
+
}
|
|
904
|
+
try {
|
|
905
|
+
const url = new URL(raw);
|
|
906
|
+
url.username = '';
|
|
907
|
+
url.password = '';
|
|
908
|
+
url.search = '';
|
|
909
|
+
url.hash = '';
|
|
910
|
+
return `${url.protocol.toLowerCase()}//${url.host.toLowerCase()}${url.pathname}`.replace(/\.git$/i, '').replace(/\/$/, '');
|
|
911
|
+
} catch { return undefined; }
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
function gateReceiptIdentity(
|
|
915
|
+
cwd: string,
|
|
916
|
+
selection: ChangedFileSelection,
|
|
917
|
+
deps: SelfGateCliDeps,
|
|
918
|
+
): { identity?: GateReceiptIdentity; reason?: string } {
|
|
919
|
+
const run = deps.runCommand ?? defaultRunCommand;
|
|
920
|
+
const command = (args: string[]) => {
|
|
921
|
+
try { return run('git', args, cwd); }
|
|
922
|
+
catch (error) { return { status: null, stderr: error instanceof Error ? error.message : String(error) }; }
|
|
923
|
+
};
|
|
924
|
+
const worktree = command(['status', '--porcelain=v1', '-z', '--untracked-files=all']);
|
|
925
|
+
if (worktree.status !== 0 || worktree.error || worktree.stdout === undefined) {
|
|
926
|
+
return { reason: 'worktree-status-unavailable' };
|
|
927
|
+
}
|
|
928
|
+
if (worktree.stdout.length > 0) return { reason: 'worktree-dirty' };
|
|
929
|
+
const remote = command(['config', '--get', 'remote.origin.url']);
|
|
930
|
+
const repositoryUrl = remote.status === 0 ? normalizedRepositoryUrl(remote.stdout ?? '') : undefined;
|
|
931
|
+
if (!repositoryUrl) return { reason: 'repository-origin-unavailable' };
|
|
932
|
+
const branch = selection.prHeadRefName?.trim() || (() => {
|
|
933
|
+
const result = command(['branch', '--show-current']);
|
|
934
|
+
return result.status === 0 ? (result.stdout ?? '').trim() : '';
|
|
935
|
+
})();
|
|
936
|
+
if (!branch) return { reason: 'branch-unavailable' };
|
|
937
|
+
if (selection.baseRef === 'HEAD') return { reason: 'uncommitted-or-no-stable-base' };
|
|
938
|
+
const resolveRev = deps.resolveRev ?? defaultRevResolver(cwd);
|
|
939
|
+
const baseSha = resolveRev(selection.baseRef);
|
|
940
|
+
const headSha = resolveRev('HEAD');
|
|
941
|
+
if (!baseSha || !headSha || !/^[0-9a-f]{40}$/.test(baseSha) || !/^[0-9a-f]{40}$/.test(headSha)) {
|
|
942
|
+
return { reason: 'base-or-head-sha-unavailable' };
|
|
943
|
+
}
|
|
944
|
+
const lockfile = ['bun.lock', 'bun.lockb'].map((name) => join(cwd, name)).find((path) => existsSync(path));
|
|
945
|
+
if (!lockfile) return { reason: 'lockfile-unavailable' };
|
|
946
|
+
let lockfileHash: string;
|
|
947
|
+
try { lockfileHash = sha256(readFileSync(lockfile)); }
|
|
948
|
+
catch { return { reason: 'lockfile-unreadable' }; }
|
|
949
|
+
const runtime = process.versions.bun ?? (globalThis as { Bun?: { version?: string } }).Bun?.version;
|
|
950
|
+
if (!runtime) return { reason: 'bun-runtime-unavailable' };
|
|
951
|
+
let environmentKey: string;
|
|
952
|
+
try { environmentKey = (deps.envKey ?? defaultGateEnvKey)(); }
|
|
953
|
+
catch { return { reason: 'environment-key-unavailable' }; }
|
|
954
|
+
const repositoryHash = sha256(repositoryUrl);
|
|
955
|
+
const receiptDir = deps.gateReceiptDir?.() ?? join(getElanousConfigDir(), 'gate-receipts');
|
|
956
|
+
const key = sha256(`${repositoryUrl}\0${branch}\0${baseSha}`);
|
|
957
|
+
return {
|
|
958
|
+
identity: {
|
|
959
|
+
schema: GATE_RECEIPT_SCHEMA, repositoryHash, branch, baseSha, headSha, runtime,
|
|
960
|
+
environmentKey, lockfileHash, receiptDir, receiptPath: join(receiptDir, `${key}.json`),
|
|
961
|
+
},
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function pruneExpiredGateReceipts(receiptDir: string, now: number): void {
|
|
966
|
+
try {
|
|
967
|
+
for (const name of readdirSync(receiptDir)) {
|
|
968
|
+
if (!/^[a-f0-9]{64}\.json$/.test(name)) continue;
|
|
969
|
+
const path = join(receiptDir, name);
|
|
970
|
+
try {
|
|
971
|
+
const stat = lstatSync(path);
|
|
972
|
+
if (stat.isFile() && !stat.isSymbolicLink() && now - stat.mtimeMs > GATE_RECEIPT_TTL_MS) rmSync(path, { force: true });
|
|
973
|
+
} catch { /* a stale receipt disappearing concurrently is harmless */ }
|
|
974
|
+
}
|
|
975
|
+
} catch { /* the first receipt has no directory to prune */ }
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
function isGateReceipt(value: unknown): value is GateReceipt {
|
|
979
|
+
if (!value || typeof value !== 'object') return false;
|
|
980
|
+
const item = value as Partial<GateReceipt>;
|
|
981
|
+
return item.schema === GATE_RECEIPT_SCHEMA && typeof item.createdAt === 'number'
|
|
982
|
+
&& typeof item.repositoryHash === 'string' && typeof item.branch === 'string'
|
|
983
|
+
&& typeof item.baseSha === 'string' && /^[0-9a-f]{40}$/.test(item.baseSha)
|
|
984
|
+
&& typeof item.headSha === 'string' && /^[0-9a-f]{40}$/.test(item.headSha)
|
|
985
|
+
&& typeof item.runtime === 'string' && typeof item.environmentKey === 'string'
|
|
986
|
+
&& typeof item.lockfileHash === 'string' && /^[0-9a-f]{64}$/.test(item.lockfileHash)
|
|
987
|
+
&& Array.isArray(item.fullTestFiles) && item.fullTestFiles.every((path) => typeof path === 'string' && isGateTestFile(path))
|
|
988
|
+
&& Array.isArray(item.failedTestFiles) && item.failedTestFiles.every((path) => typeof path === 'string' && isGateTestFile(path))
|
|
989
|
+
&& typeof item.measured === 'boolean';
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
function rejectGateReceipt(cwd: string, reason: string, details: Record<string, unknown> = {}): GateReceiptDecision {
|
|
993
|
+
try { debug.log('self-implement', 'gate.receipt-inheritance-rejected', { reason, ...details }); } catch { /* telemetry must not alter the gate */ }
|
|
994
|
+
return { mode: 'full', reason };
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function decideGateReceiptInheritance(
|
|
998
|
+
cwd: string,
|
|
999
|
+
options: SelfGateCliOptions,
|
|
1000
|
+
selection: ChangedFileSelection,
|
|
1001
|
+
fullTestFiles: readonly string[],
|
|
1002
|
+
deps: SelfGateCliDeps,
|
|
1003
|
+
): GateReceiptDecision {
|
|
1004
|
+
// Existing injected-command fixtures stay isolated unless a test explicitly supplies a receipt directory.
|
|
1005
|
+
if (deps.runCommand && !deps.gateReceiptDir) return { mode: 'full', reason: 'injected-command-no-receipt-store' };
|
|
1006
|
+
const resolved = gateReceiptIdentity(cwd, selection, deps);
|
|
1007
|
+
if (!resolved.identity) return rejectGateReceipt(cwd, resolved.reason ?? 'receipt-identity-unavailable');
|
|
1008
|
+
const identity = resolved.identity;
|
|
1009
|
+
if (options.noInherit) {
|
|
1010
|
+
try { debug.log('self-implement', 'gate.receipt-inheritance-rejected', { reason: 'forced-full', baseSha: identity.baseSha, headSha: identity.headSha }); } catch { /* observation only */ }
|
|
1011
|
+
return { mode: 'full', reason: 'forced-full', identity };
|
|
1012
|
+
}
|
|
1013
|
+
const now = deps.now?.() ?? Date.now();
|
|
1014
|
+
pruneExpiredGateReceipts(identity.receiptDir, now);
|
|
1015
|
+
let prior: unknown;
|
|
1016
|
+
try {
|
|
1017
|
+
const stat = lstatSync(identity.receiptPath);
|
|
1018
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return rejectGateReceipt(cwd, 'receipt-not-regular-file', { baseSha: identity.baseSha });
|
|
1019
|
+
prior = JSON.parse(readFileSync(identity.receiptPath, 'utf8'));
|
|
1020
|
+
} catch (error) {
|
|
1021
|
+
const code = (error as NodeJS.ErrnoException)?.code;
|
|
1022
|
+
return rejectGateReceipt(cwd, code === 'ENOENT' ? 'no-prior-receipt' : 'receipt-read-failed', { baseSha: identity.baseSha });
|
|
1023
|
+
}
|
|
1024
|
+
if (!isGateReceipt(prior)) return rejectGateReceipt(cwd, 'receipt-schema-invalid', { baseSha: identity.baseSha });
|
|
1025
|
+
if (now - prior.createdAt > GATE_RECEIPT_TTL_MS) {
|
|
1026
|
+
try { rmSync(identity.receiptPath, { force: true }); } catch { /* stale file can remain without affecting the full gate */ }
|
|
1027
|
+
return rejectGateReceipt(cwd, 'receipt-expired', { previousHead: prior.headSha });
|
|
1028
|
+
}
|
|
1029
|
+
if (prior.repositoryHash !== identity.repositoryHash || prior.branch !== identity.branch) return rejectGateReceipt(cwd, 'repository-or-branch-mismatch');
|
|
1030
|
+
if (prior.baseSha !== identity.baseSha) return rejectGateReceipt(cwd, 'base-sha-mismatch', { previousBase: prior.baseSha, currentBase: identity.baseSha });
|
|
1031
|
+
if (prior.runtime !== identity.runtime || prior.environmentKey !== identity.environmentKey) return rejectGateReceipt(cwd, 'runtime-mismatch', { previousRuntime: prior.runtime, currentRuntime: identity.runtime });
|
|
1032
|
+
if (prior.lockfileHash !== identity.lockfileHash) return rejectGateReceipt(cwd, 'lockfile-hash-mismatch');
|
|
1033
|
+
if (!prior.measured) return rejectGateReceipt(cwd, 'previous-test-run-unmeasured', { previousHead: prior.headSha });
|
|
1034
|
+
const ancestor = (deps.runCommand ?? defaultRunCommand)('git', ['merge-base', '--is-ancestor', prior.headSha, identity.headSha], cwd);
|
|
1035
|
+
if (ancestor.status !== 0 || ancestor.error) return rejectGateReceipt(cwd, 'previous-head-not-ancestor', { previousHead: prior.headSha, currentHead: identity.headSha });
|
|
1036
|
+
|
|
1037
|
+
const diff = (deps.runCommand ?? defaultRunCommand)('git', ['diff', '--name-only', `${prior.headSha}..${identity.headSha}`], cwd);
|
|
1038
|
+
if (diff.status !== 0 || diff.error || diff.stdout === undefined) return rejectGateReceipt(cwd, 'head-delta-unavailable', { previousHead: prior.headSha });
|
|
1039
|
+
const changedFiles = [...new Set(diff.stdout.split('\n').map((path) => normalizeGatePath(path.trim())).filter(Boolean))].sort();
|
|
1040
|
+
try {
|
|
1041
|
+
const deltaSelection = { files: changedFiles, baseRef: prior.headSha };
|
|
1042
|
+
const deltaOptions: GateSelectionOptions = { ...options, base: prior.headSha, pr: undefined };
|
|
1043
|
+
const deltaDeps: GateSelectionDeps = { ...deps, changedFiles: () => deltaSelection };
|
|
1044
|
+
const deltaPrepared = prepareGateTestSelection(cwd, deltaOptions, deltaDeps);
|
|
1045
|
+
if (deltaPrepared.lookupFailed || deltaPrepared.routeIndex?.lookupFailures.length) {
|
|
1046
|
+
return rejectGateReceipt(cwd, 'head-delta-test-radius-unmeasured', { previousHead: prior.headSha });
|
|
1047
|
+
}
|
|
1048
|
+
const deltaTests = finishGateTestSelection(deltaPrepared, deltaOptions, cwd, deltaDeps).testFiles;
|
|
1049
|
+
const current = new Set(fullTestFiles);
|
|
1050
|
+
const previous = new Set(prior.fullTestFiles);
|
|
1051
|
+
const previousFailures = new Set(prior.failedTestFiles);
|
|
1052
|
+
const changed = new Set(deltaTests);
|
|
1053
|
+
const runTestFiles = fullTestFiles.filter((path) => changed.has(path) || previousFailures.has(path) || !previous.has(path));
|
|
1054
|
+
const run = new Set(runTestFiles);
|
|
1055
|
+
const inheritedTestFiles = fullTestFiles.filter((path) => previous.has(path) && !previousFailures.has(path) && !run.has(path));
|
|
1056
|
+
// A current scope path not accounted for by the receipt is run, never silently inherited.
|
|
1057
|
+
for (const path of fullTestFiles) if (!previous.has(path) && !run.has(path)) return rejectGateReceipt(cwd, 'new-test-not-selected', { path });
|
|
1058
|
+
if (current.size !== fullTestFiles.length) return rejectGateReceipt(cwd, 'current-test-scope-duplicate');
|
|
1059
|
+
try {
|
|
1060
|
+
debug.log('self-implement', 'gate.receipt-inheritance-accepted', {
|
|
1061
|
+
previousHead: prior.headSha, currentHead: identity.headSha, baseSha: identity.baseSha,
|
|
1062
|
+
changedFiles, rerunTestFiles: runTestFiles, inheritedTestFiles,
|
|
1063
|
+
});
|
|
1064
|
+
} catch { /* observation only */ }
|
|
1065
|
+
return { mode: 'inherit', reason: 'matching-prior-receipt', identity, sourceHead: prior.headSha,
|
|
1066
|
+
runTestFiles, inheritedTestFiles };
|
|
1067
|
+
} catch (error) {
|
|
1068
|
+
return rejectGateReceipt(cwd, 'head-delta-test-radius-failed', { message: error instanceof Error ? error.message : String(error) });
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
function persistGateReceipt(cwd: string, capture: GateArtifactCapture, deps: SelfGateCliDeps): void {
|
|
1073
|
+
const decision = capture.receiptDecision;
|
|
1074
|
+
const identity = decision?.identity;
|
|
1075
|
+
if (!identity) return;
|
|
1076
|
+
if (deps.runCommand && !deps.gateReceiptDir) return;
|
|
1077
|
+
if (capture.testReceiptMeasured !== true || !capture.fullTestFiles || !capture.failedTestFiles) {
|
|
1078
|
+
try { debug.log('self-implement', 'gate.receipt-write-rejected', { reason: 'test-outcome-unmeasured', headSha: identity.headSha }); } catch { /* observation only */ }
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
const failed = [...new Set(capture.failedTestFiles)].filter((path) => capture.fullTestFiles!.includes(path)).sort();
|
|
1082
|
+
const receipt: GateReceipt = {
|
|
1083
|
+
schema: GATE_RECEIPT_SCHEMA, createdAt: deps.now?.() ?? Date.now(), repositoryHash: identity.repositoryHash,
|
|
1084
|
+
branch: identity.branch, baseSha: identity.baseSha, headSha: identity.headSha, runtime: identity.runtime,
|
|
1085
|
+
environmentKey: identity.environmentKey, lockfileHash: identity.lockfileHash,
|
|
1086
|
+
fullTestFiles: [...new Set(capture.fullTestFiles)].sort(), failedTestFiles: failed, measured: true,
|
|
1087
|
+
};
|
|
1088
|
+
const temporary = join(identity.receiptDir, `.${basename(identity.receiptPath)}.${process.pid}.${randomUUID()}.tmp`);
|
|
1089
|
+
try {
|
|
1090
|
+
mkdirSync(identity.receiptDir, { recursive: true, mode: 0o700 });
|
|
1091
|
+
pruneExpiredGateReceipts(identity.receiptDir, receipt.createdAt);
|
|
1092
|
+
writeFileSync(temporary, `${JSON.stringify(receipt, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
|
|
1093
|
+
renameSync(temporary, identity.receiptPath);
|
|
1094
|
+
try { debug.log('self-implement', 'gate.receipt-written', { headSha: identity.headSha, baseSha: identity.baseSha, testFiles: receipt.fullTestFiles.length, failedTestFiles: failed.length }); } catch { /* observation only */ }
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
try { rmSync(temporary, { force: true }); } catch { /* best effort */ }
|
|
1097
|
+
try { debug.log('self-implement', 'gate.receipt-write-rejected', { reason: 'receipt-write-failed', message: error instanceof Error ? error.message : String(error) }); } catch { /* observation only */ }
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
847
1101
|
/** A completed bundle is observed immediately, before the synchronous runner returns. Each sink is best effort. */
|
|
848
1102
|
function shardProgressObserver(cwd: string, options: SelfGateCliOptions, deps: SelfGateCliDeps): (progress: ShardRunProgress) => void {
|
|
849
1103
|
const now = deps.now ?? Date.now;
|
|
@@ -879,8 +1133,17 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
879
1133
|
const expose = publicExposureFiles(selection.files).length > 0
|
|
880
1134
|
? runExposeGate(cwd, selection.files, getUserConfig().harness?.exposeGate === 'strict' ? 'strict' : 'warn', deps.runCommand)
|
|
881
1135
|
: { passed: true, log: '' };
|
|
882
|
-
const { alwaysInclude, alwaysIncludeMissing, alwaysIncludeExtra, importerTestsAdded, commentOnlySources, scenarioTests, testFiles,
|
|
1136
|
+
const { alwaysInclude, alwaysIncludeMissing, alwaysIncludeExtra, importerTestsAdded, commentOnlySources, scenarioTests, testFiles: fullTestFiles,
|
|
883
1137
|
skipTestStep, importerTestsNotRun, unrunImporterTotal, callerTestsOverflow, importerLookupFailed } = finishGateTestSelection(prepared, options, cwd, deps);
|
|
1138
|
+
const receiptDecision = options.base || options.pr || options.noInherit
|
|
1139
|
+
? decideGateReceiptInheritance(cwd, options, selection, fullTestFiles, deps) : undefined;
|
|
1140
|
+
if (receiptDecision && !receiptDecision.identity && (!deps.runCommand || deps.gateReceiptDir)) {
|
|
1141
|
+
receiptDecision.identity = gateReceiptIdentity(cwd, selection, deps).identity;
|
|
1142
|
+
}
|
|
1143
|
+
const testFiles = receiptDecision?.mode === 'inherit' ? [...(receiptDecision.runTestFiles ?? fullTestFiles)] : [...fullTestFiles];
|
|
1144
|
+
capture.fullTestFiles = [...fullTestFiles];
|
|
1145
|
+
capture.receiptDecision = receiptDecision;
|
|
1146
|
+
const relatedTestFiles = [...new Set([...selection.files.filter(isTestPath), ...(scope.testArgs ?? []), ...importerTestsAdded])];
|
|
884
1147
|
const lines = [
|
|
885
1148
|
// ⛔⭐ 「changed=0」을 «초록»으로 읽는 사고가 났다(2026-09-02 · 🅕 보고 · 🅣 재현).
|
|
886
1149
|
// 커밋 «전»에 돌리면 작업 트리 변경은 «안 세므로» changed=0 이 나오는데,
|
|
@@ -889,7 +1152,10 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
889
1152
|
+ (selection.files.length === 0 && (selection.ignoredDirtyPaths?.length ?? 0) > 0
|
|
890
1153
|
? ` ⚠️ 센 것이 0인데 «커밋 안 된» 변경 ${selection.ignoredDirtyPaths!.length}개가 있다 — 「통과」가 아니라 「안 쟀다」다(커밋 뒤 다시 돌려라)`
|
|
891
1154
|
: ''),
|
|
892
|
-
`scope: ${scope.testArgs?.join(', ') ?? '(test step skipped)'}`,
|
|
1155
|
+
`scope: ${receiptDecision?.mode === 'inherit' ? testFiles.join(', ') || '(all tests inherited)' : scope.testArgs?.join(', ') ?? '(test step skipped)'}`,
|
|
1156
|
+
...(receiptDecision ? [receiptDecision.mode === 'inherit'
|
|
1157
|
+
? `gate receipt: inherited ${receiptDecision.inheritedTestFiles?.length ?? 0} · rerun ${testFiles.length} · source head ${receiptDecision.sourceHead?.slice(0, 12) ?? '(unknown)'}`
|
|
1158
|
+
: `gate receipt: full radius (${receiptDecision.reason})`] : []),
|
|
893
1159
|
`ignored unrelated worktree changes: ${selection.ignoredDirtyPaths === undefined ? '(not checked)' : selection.ignoredDirtyPaths.join(', ') || '(none)'}`,
|
|
894
1160
|
`unverified: ${scope.unverified.length} (${scope.unverified.join(', ') || '(none)'})`,
|
|
895
1161
|
`elanous runtime artifacts: ${scope.elanousRuntimeArtifacts.length} (${scope.elanousRuntimeArtifacts.join(', ') || '(none)'})`,
|
|
@@ -958,8 +1224,29 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
958
1224
|
lines.push(`next-tui-entry-budget: UNMEASURED ${error instanceof Error ? error.message : String(error)}`);
|
|
959
1225
|
}
|
|
960
1226
|
|
|
1227
|
+
if (receiptDecision?.mode === 'inherit' && testFiles.length === 0 && fullTestFiles.length > 0) {
|
|
1228
|
+
capture.testReceiptMeasured = true;
|
|
1229
|
+
capture.failedTestFiles = [];
|
|
1230
|
+
capture.verdict = 'passed';
|
|
1231
|
+
const testLine = formatPartialObservationNote(unrunImporterTotal ?? 0,
|
|
1232
|
+
`tests: pass (${receiptDecision.inheritedTestFiles?.length ?? 0} files inherited from ${receiptDecision.sourceHead?.slice(0, 12) ?? 'prior receipt'})`);
|
|
1233
|
+
lines.push(testLine);
|
|
1234
|
+
capture.verdictLine = testLine;
|
|
1235
|
+
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
1236
|
+
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
1237
|
+
return {
|
|
1238
|
+
exitCode: policyPassed && androidPassed && iosPassed && pwaPassed && entryBudgetPassed && expose.passed ? 0 : 1,
|
|
1239
|
+
lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
|
|
1240
|
+
documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
|
|
1241
|
+
alwaysIncludeMissing, importerTestsAdded,
|
|
1242
|
+
baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 },
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
|
|
961
1246
|
if (skipTestStep) {
|
|
962
1247
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
1248
|
+
capture.testReceiptMeasured = false;
|
|
1249
|
+
capture.failedTestFiles = [];
|
|
963
1250
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
964
1251
|
Object.assign(capture, { verdict: 'skipped', artifactsUnavailable: 'no-tests' } satisfies GateArtifactCapture);
|
|
965
1252
|
return { exitCode: androidPassed && iosPassed && pwaPassed && entryBudgetPassed && policyPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, importerTestsAdded, baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 } };
|
|
@@ -1006,6 +1293,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
1006
1293
|
let shardBaseline: SelfGateCliResult['baseline'];
|
|
1007
1294
|
let unmeasuredReason: string | undefined;
|
|
1008
1295
|
if (aggregate.status === 'unmeasured') {
|
|
1296
|
+
capture.testReceiptMeasured = false;
|
|
1297
|
+
capture.failedTestFiles = [];
|
|
1009
1298
|
unmeasuredReason = sharded.reason
|
|
1010
1299
|
? redactSecretText(sharded.reason).replace(/[\r\n\t\x00-\x1f\x7f]+/g, ' ').slice(0, 500)
|
|
1011
1300
|
: aggregate.retryShardIds.join(', ') || 'no complete JUnit';
|
|
@@ -1017,8 +1306,12 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
1017
1306
|
capture.unmeasuredReason = unmeasuredReason;
|
|
1018
1307
|
}
|
|
1019
1308
|
else if (aggregate.report) {
|
|
1020
|
-
const
|
|
1309
|
+
const timeoutReport = recheckTimeoutOnlyIntroducedFailures(cwd, aggregate.report, deps.runTimeoutRecheck);
|
|
1310
|
+
const report = deps.runShards || deps.runShardsAsync
|
|
1311
|
+
? deps.runInterferenceRecheck?.(cwd, timeoutReport, selection.baseRef, relatedTestFiles) ?? timeoutReport
|
|
1312
|
+
: (deps.runInterferenceRecheck ?? recheckOutsideScopeFailures)(cwd, timeoutReport, selection.baseRef, relatedTestFiles);
|
|
1021
1313
|
capture.timeoutRechecks = report.timeoutRechecks;
|
|
1314
|
+
capture.interferenceRechecks = report.interferenceRechecks;
|
|
1022
1315
|
const timeoutRecheckResolvedFailure = aggregate.status === 'failed'
|
|
1023
1316
|
&& (report.loadTimeout ?? 0) > 0
|
|
1024
1317
|
&& report.introduced === 0 && report.unknown === 0 && report.preconditionUnmet === 0
|
|
@@ -1026,6 +1319,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
1026
1319
|
&& report.baselineStatus !== 'unknown';
|
|
1027
1320
|
const effectiveStatus = timeoutRecheckResolvedFailure ? 'passed' : aggregate.status;
|
|
1028
1321
|
capture.verdict = effectiveStatus;
|
|
1322
|
+
capture.testReceiptMeasured = report.unknown === 0 && report.preconditionUnmet === 0 && report.worktreeFailuresParsed;
|
|
1323
|
+
capture.failedTestFiles = [...new Set(report.failures.map((failure) => failure.file).filter((file): file is string => typeof file === 'string'))];
|
|
1029
1324
|
logGateCliBaseline(cwd, {
|
|
1030
1325
|
introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown,
|
|
1031
1326
|
preconditionUnmet: report.preconditionUnmet, timedOut: report.timedOut,
|
|
@@ -1035,6 +1330,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
1035
1330
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
|
|
1036
1331
|
shardBaseline = { introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown, preconditionUnmet: report.preconditionUnmet };
|
|
1037
1332
|
} else {
|
|
1333
|
+
capture.testReceiptMeasured = true;
|
|
1334
|
+
capture.failedTestFiles = [];
|
|
1038
1335
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
|
|
1039
1336
|
logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
|
|
1040
1337
|
shardBaseline = { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 };
|
|
@@ -1056,6 +1353,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
1056
1353
|
const worktreeLog = formatProcessOutput(test);
|
|
1057
1354
|
Object.assign(capture, { unshardedRc: test.status, artifactsUnavailable: 'unsharded' } satisfies GateArtifactCapture);
|
|
1058
1355
|
if (test.status === 0 && !test.error) {
|
|
1356
|
+
capture.testReceiptMeasured = true;
|
|
1357
|
+
capture.failedTestFiles = [];
|
|
1059
1358
|
lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
|
|
1060
1359
|
Object.assign(capture, { verdict: 'passed', verdictLine: lines[lines.length - 1] } satisfies GateArtifactCapture);
|
|
1061
1360
|
const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
|
|
@@ -1065,8 +1364,17 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
|
|
|
1065
1364
|
|
|
1066
1365
|
if (worktreeLog.includes('deterministic environment setup failed')) lines.push(worktreeLog);
|
|
1067
1366
|
const baseline = (deps.runBaseline ?? runGateBaseline)(cwd, testFiles, selection.baseRef);
|
|
1068
|
-
|
|
1367
|
+
// An injected runner can represent a virtual checkout; only the real runner may use this host's file tree.
|
|
1368
|
+
const currentFileExists = deps.runTests ? undefined : (file: string) => existsSync(resolve(cwd, file));
|
|
1369
|
+
const timeoutReport = recheckTimeoutOnlyIntroducedFailures(cwd,
|
|
1370
|
+
buildGateBaselineReport(worktreeLog, baseline, undefined, 0, currentFileExists), deps.runTimeoutRecheck);
|
|
1371
|
+
const report = deps.runTests
|
|
1372
|
+
? deps.runInterferenceRecheck?.(cwd, timeoutReport, selection.baseRef, relatedTestFiles) ?? timeoutReport
|
|
1373
|
+
: (deps.runInterferenceRecheck ?? recheckOutsideScopeFailures)(cwd, timeoutReport, selection.baseRef, relatedTestFiles);
|
|
1069
1374
|
capture.timeoutRechecks = report.timeoutRechecks;
|
|
1375
|
+
capture.interferenceRechecks = report.interferenceRechecks;
|
|
1376
|
+
capture.testReceiptMeasured = report.unknown === 0 && report.preconditionUnmet === 0 && report.worktreeFailuresParsed;
|
|
1377
|
+
capture.failedTestFiles = [...new Set(report.failures.map((failure) => failure.file).filter((file): file is string => typeof file === 'string'))];
|
|
1070
1378
|
logGateCliBaseline(cwd, {
|
|
1071
1379
|
introduced: report.introduced,
|
|
1072
1380
|
preexisting: report.preexisting,
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GATE-ONCE-PER-HEAD (0.2.40 첫 조각 · OP 10-27 23:0x 지시) — host-regate 통과 영수증의 지속 등록부.
|
|
3
|
+
*
|
|
4
|
+
* S: 같은 PR head 의 자식 gate 뒤 host-regate 와 착지 게이트가 같은 시험을 다시 실행해 Pod 와 호스트 자원을 소모한다.
|
|
5
|
+
* C: 통과 사실이 어디에도 남지 않아 매 호출이 전 검사를 다시 돌릴 수밖에 없다.
|
|
6
|
+
* Q: 정확히 같은 통합 입력과 측정 범위에 대해 이미 통과한 게이트만 승계할 수 있는가?
|
|
7
|
+
* A: 통과 영수증을 이 등록부에 원자적으로 기록하고, runHostRegate 가 재검증·통합 후보 구성 뒤 현재 key 와
|
|
8
|
+
* 일치하는 통과 영수증만 승계한다. 불일치·결손·불완전·실패/측정불가 영수증은 원래 검사를 실행한다.
|
|
9
|
+
*
|
|
10
|
+
* 원본 영수증 없이 통과 판정 금지: 승계는 저장된 영수증 행 하나를 통해서만 일어나고, 그 행의 key 는
|
|
11
|
+
* 행 스스로의 필드에서 다시 계산되어야 한다(gateReceiptSelfKey). key 가 필드와 맞지 않는 행은 저장도
|
|
12
|
+
* 승계도 거절한다.
|
|
13
|
+
*
|
|
14
|
+
* 원자성: saveGateReceipts 는 임시 파일에 온전히 쓴 뒤 rename(2) 로 바꾼다 — 부분 쓰기는 관측될 수 없다.
|
|
15
|
+
* 프로세스끼리의 동시 저장은 각자 온전한 등록부를 남긴다(늦은 쪽이 이긴다). 잃은 영수증은 다음 호출을
|
|
16
|
+
* 원래 검사로 되돌릴 뿐, 잘못된 통과를 만들지 않는다 — 실패 방향으로 열린다.
|
|
17
|
+
*/
|
|
18
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
19
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
20
|
+
import { basename, dirname, join } from 'node:path';
|
|
21
|
+
import { gateTestBaseline } from '../../scripts/lib/gate-test-env.js';
|
|
22
|
+
|
|
23
|
+
export const GATE_RECEIPT_SCHEMA = 1;
|
|
24
|
+
export type GateReceiptVerdict = 'passed' | 'failed' | 'unmeasured';
|
|
25
|
+
|
|
26
|
+
const SHA40 = /^[0-9a-f]{40}$/i;
|
|
27
|
+
const SHA256 = /^[0-9a-f]{64}$/i;
|
|
28
|
+
|
|
29
|
+
/** 한 번의 host-regate 측정을 정체 짓는 입력. 판정(verdict)은 identity 가 아니라 key 계산에 들어간다. */
|
|
30
|
+
export interface GateReceiptIdentity {
|
|
31
|
+
/** 40자 PR head SHA */
|
|
32
|
+
headCommit: string;
|
|
33
|
+
/** 40자 실제 측정 base SHA — PR 에 기록된 baseRefOid 가 아니라 얹어 잰 끝 */
|
|
34
|
+
baseCommit: string;
|
|
35
|
+
/** 검사를 실행한 Bun 식별값(bun --version) */
|
|
36
|
+
bunVersion: string;
|
|
37
|
+
/** 검사가 설치·실행한 lockfile 의 SHA-256(bun.lock/bun.lockb 바이트) — 없으면 'absent' */
|
|
38
|
+
lockfileHash: string;
|
|
39
|
+
/** 정규화된 radius 파일 집합(병합 후보 기준 변경 파일 — 중복 제거·정렬) */
|
|
40
|
+
radiusFiles: readonly string[];
|
|
41
|
+
/** 이 영수증이 통과한 검사 토큰(종류 ⊕ 측정 범위 — 중복 제거·정렬) */
|
|
42
|
+
checks: readonly string[];
|
|
43
|
+
/** 실행 환경 지문(gateEnvFingerprint) */
|
|
44
|
+
envFingerprint: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface GateReceipt extends GateReceiptIdentity {
|
|
48
|
+
schema: typeof GATE_RECEIPT_SCHEMA;
|
|
49
|
+
key: string;
|
|
50
|
+
verdict: GateReceiptVerdict;
|
|
51
|
+
savedAt: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type GateReceiptRegistry = Record<string, GateReceipt>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 검사 종류·판정·환경까지 포함한 정준 직렬화의 SHA-256. 같은 측정·같은 판정만 같은 key 를 받는다.
|
|
58
|
+
* head/base 는 40자 hex 여야 한다 — 그보다 못한 입력으로 영수증을 만들 수 없게 문을 닫는다.
|
|
59
|
+
*/
|
|
60
|
+
export function computeReceiptKey(identity: GateReceiptIdentity, verdict: GateReceiptVerdict): string {
|
|
61
|
+
if (!SHA40.test(identity.headCommit)) throw new Error('gate receipt head SHA is not 40 hex characters');
|
|
62
|
+
if (!SHA40.test(identity.baseCommit)) throw new Error('gate receipt base SHA is not 40 hex characters');
|
|
63
|
+
const canonical = JSON.stringify({
|
|
64
|
+
schema: GATE_RECEIPT_SCHEMA,
|
|
65
|
+
head: identity.headCommit.toLowerCase(),
|
|
66
|
+
base: identity.baseCommit.toLowerCase(),
|
|
67
|
+
bun: identity.bunVersion,
|
|
68
|
+
lockfile: identity.lockfileHash,
|
|
69
|
+
radius: [...new Set(identity.radiusFiles)].sort(),
|
|
70
|
+
checks: [...new Set(identity.checks)].sort(),
|
|
71
|
+
env: identity.envFingerprint,
|
|
72
|
+
verdict,
|
|
73
|
+
});
|
|
74
|
+
return createHash('sha256').update(canonical).digest('hex');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 행의 key 를 행 스스로의 필드에서 다시 계산한다 — 위조·불일치 행은 저장된 key 와 어긋난다. */
|
|
78
|
+
export function gateReceiptSelfKey(receipt: GateReceipt): string {
|
|
79
|
+
return computeReceiptKey(receipt, receipt.verdict);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isGateReceipt(value: unknown): value is GateReceipt {
|
|
83
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
84
|
+
const row = value as Partial<GateReceipt>;
|
|
85
|
+
return row.schema === GATE_RECEIPT_SCHEMA && typeof row.key === 'string' && SHA256.test(row.key)
|
|
86
|
+
&& (row.verdict === 'passed' || row.verdict === 'failed' || row.verdict === 'unmeasured')
|
|
87
|
+
&& SHA40.test(row.headCommit ?? '') && SHA40.test(row.baseCommit ?? '')
|
|
88
|
+
&& typeof row.bunVersion === 'string' && typeof row.lockfileHash === 'string'
|
|
89
|
+
&& Array.isArray(row.radiusFiles) && row.radiusFiles.every((file) => typeof file === 'string')
|
|
90
|
+
&& Array.isArray(row.checks) && row.checks.every((check) => typeof check === 'string')
|
|
91
|
+
&& typeof row.envFingerprint === 'string' && typeof row.savedAt === 'string';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 결손·손상 파일은 빈 등록부로 복구한다 — 못 읽은 영수증은 «없다» 로 취급해 원래 검사를 실행한다.
|
|
96
|
+
* 모양이 어긋나거나 행의 key 가 맵 키와 다른 행은 버린다.
|
|
97
|
+
*/
|
|
98
|
+
export function loadGateReceipts(path: string): GateReceiptRegistry {
|
|
99
|
+
let raw: string;
|
|
100
|
+
try { raw = readFileSync(path, 'utf8'); }
|
|
101
|
+
catch { return {}; }
|
|
102
|
+
let parsed: unknown;
|
|
103
|
+
try { parsed = JSON.parse(raw); }
|
|
104
|
+
catch { return {}; }
|
|
105
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
|
|
106
|
+
const registry: GateReceiptRegistry = {};
|
|
107
|
+
for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
|
|
108
|
+
if (!isGateReceipt(value) || value.key !== key) continue;
|
|
109
|
+
registry[key] = value;
|
|
110
|
+
}
|
|
111
|
+
return registry;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** write-then-rename 원자적 기록 — 부분 쓰기 노출 금지. 임시 파일은 같은 디렉터리에 무작위 이름으로 둔다. */
|
|
115
|
+
export function saveGateReceipts(path: string, registry: GateReceiptRegistry): void {
|
|
116
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
117
|
+
const tmp = join(dirname(path), `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`);
|
|
118
|
+
writeFileSync(tmp, `${JSON.stringify(registry, null, 2)}\n`);
|
|
119
|
+
try { renameSync(tmp, path); }
|
|
120
|
+
catch (error) {
|
|
121
|
+
try { unlinkSync(tmp); } catch { /* 최선의 정리 — 원래 오류를 지운다 */ }
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 통과 영수증을 지속 등록부에 원자적으로 병합 기록한다. key 가 필드와 맞지 않는 행은 쓰기 단계에서 거절한다. */
|
|
127
|
+
export function saveGateReceipt(path: string, receipt: GateReceipt): void {
|
|
128
|
+
if (gateReceiptSelfKey(receipt) !== receipt.key) throw new Error('gate receipt key does not match its own fields');
|
|
129
|
+
const registry = loadGateReceipts(path);
|
|
130
|
+
registry[receipt.key] = receipt;
|
|
131
|
+
saveGateReceipts(path, registry);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 승계 거절 사유. 불일치(head/base/env/Bun·lockfile/radius)·결손·불완전(현재 측정 범위 미커버)·
|
|
136
|
+
* 실패/측정불가 판정을 가려 한 줄로 남긴다 — debug.log 의 decline 이유가 된다.
|
|
137
|
+
*/
|
|
138
|
+
export function describeGateReceiptDecline(probe: GateReceiptIdentity, registry: GateReceiptRegistry): string {
|
|
139
|
+
const receipts = Object.values(registry);
|
|
140
|
+
if (!receipts.length) return 'gate receipt registry empty';
|
|
141
|
+
const sameHeadBase = receipts.filter((receipt) => receipt.headCommit.toLowerCase() === probe.headCommit.toLowerCase()
|
|
142
|
+
&& receipt.baseCommit.toLowerCase() === probe.baseCommit.toLowerCase());
|
|
143
|
+
if (!sameHeadBase.length) return `no receipt for head ${probe.headCommit.slice(0, 12)} base ${probe.baseCommit.slice(0, 12)}`;
|
|
144
|
+
for (const receipt of sameHeadBase) {
|
|
145
|
+
const differs: string[] = [];
|
|
146
|
+
if (receipt.verdict !== 'passed') differs.push(`verdict=${receipt.verdict}`);
|
|
147
|
+
if (receipt.envFingerprint !== probe.envFingerprint) differs.push('env fingerprint differs');
|
|
148
|
+
if (receipt.bunVersion !== probe.bunVersion || receipt.lockfileHash !== probe.lockfileHash) differs.push('bun/lockfile differs');
|
|
149
|
+
if ([...new Set(receipt.radiusFiles)].sort().join('\n') !== [...new Set(probe.radiusFiles)].sort().join('\n')) differs.push('changed-file radius differs');
|
|
150
|
+
const current = [...new Set(probe.checks)].sort();
|
|
151
|
+
const stored = [...new Set(receipt.checks)].sort();
|
|
152
|
+
if (stored.join('\n') !== current.join('\n')) {
|
|
153
|
+
const missing = current.filter((check) => !stored.includes(check));
|
|
154
|
+
differs.push(missing.length && stored.every((check) => current.includes(check))
|
|
155
|
+
? `receipt does not cover: ${missing.join(',')}`
|
|
156
|
+
: `receipt checks differ (stored ${stored.join(',')})`);
|
|
157
|
+
}
|
|
158
|
+
if (differs.length) return `receipt ${receipt.key.slice(0, 12)} ${differs.join(' · ')}`;
|
|
159
|
+
}
|
|
160
|
+
return 'no stored receipt matches this measurement key';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** 실행 환경 지문: 플랫폼 ⊕ 게이트 시험 baseline(TZ·locale·fake-LLM 스위치)의 정준 직렬화 SHA-256. */
|
|
164
|
+
export function gateEnvFingerprint(env: NodeJS.ProcessEnv): string {
|
|
165
|
+
const baseline = gateTestBaseline(env);
|
|
166
|
+
const canonical = JSON.stringify({
|
|
167
|
+
platform: process.platform,
|
|
168
|
+
env: Object.fromEntries(Object.entries(baseline).sort(([a], [b]) => a.localeCompare(b))),
|
|
169
|
+
});
|
|
170
|
+
return createHash('sha256').update(canonical).digest('hex');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** 후보 워크트리가 실제로 설치·실행한 lockfile 의 SHA-256. 둘 다 없으면 'absent'. */
|
|
174
|
+
export function gateLockfileHash(worktree: string): string {
|
|
175
|
+
for (const name of ['bun.lock', 'bun.lockb']) {
|
|
176
|
+
if (!existsSync(join(worktree, name))) continue;
|
|
177
|
+
return createHash('sha256').update(readFileSync(join(worktree, name))).digest('hex');
|
|
178
|
+
}
|
|
179
|
+
return 'absent';
|
|
180
|
+
}
|