elanous 0.2.28 → 0.2.29
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/{y1ltt7oCZxVpC6zVPhZ2O → cIpv5nU9AycwYWZI9H589}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.js → 058a98ba.7eb28d5e6dc03565.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4565-67e4c620597965c8.js → 1015-9cba22a5a4554797.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.js → 1142.65d002789ab3af7d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1516.dfaceff3fd2d0e0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +286 -0
- package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1782-59db1b5aa06df38a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1743.563d3168e95825ef.js → 1852.7f7b53991fcb99ef.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +36 -0
- package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +64 -0
- package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{65ebff95.081daeff622d238e.js → 285adb1a.5654e605dddf86d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +115 -0
- package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3160-95c96f4d2a21dd26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +90 -0
- package/apps/pwa/out/_next/static/chunks/328bb3ab-6628a1114fe3fb3b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 3396-97b97928c49190c9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 3403.7199205e65124486.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +1 -0
- package/apps/pwa/out/_next/static/chunks/419.736c0d6f426249a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6def8a8e.c81f9ca41028eccf.js → 425cfc4d.fb91158e3971c39f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 46bd8bea.2f4b4099172fcdb7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5081.a240b63fad28663a.js → 4759.1f76713aefb87db5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +62 -0
- package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +27 -0
- package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{9974.e77b4ff4884557b3.js → 5591.a35e7a217734a8b9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +93 -0
- package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5492-e05e26a033ba80d2.js → 6013-2f769370d8b4c2c6.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +2 -0
- package/apps/pwa/out/_next/static/chunks/{5408.377c8c543635b81f.js → 6534.1ab00f370db7b105.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +148 -0
- package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +149 -0
- package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +79 -0
- package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8578.dff22d988cc2b106.js → 6767.1fcfc9b8be83975f.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/6776.06ff1e3b464cc607.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.js → 6853.cc5174a9dee59593.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +287 -0
- package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 7375.050ea0d72968e49f.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +77 -0
- package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +74 -0
- package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7725-4f83d5541fbdb81b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8332.6f0f49df772e163b.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{7483.ba01c6c209b81bba.js → 8398.73a19b39715eda04.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.js → 8471.8d2a8c74f09c36ff.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{5785-ea8d2c633b6688e3.js → 8767-2f6a634f5abeaa01.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +32 -0
- package/apps/pwa/out/_next/static/chunks/8795.32573a185af18c7b.js +41 -0
- package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.js → 9143.ff14585db1d275ff.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.js → 9907.49be0fcadaf214b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{973cbf1b.3bbcf2b41548eca7.js → a435ad95.577add051b4facb2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-fa46d4588e8442c2.js → page-a5635eba0d73b84e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/{page-66ad46ed0279feb9.js → page-86feb08080261a2f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/{page-646b50f63b6fe732.js → page-8aaa6dedc4c10dfb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-6f131b51193a36f9.js → page-33bf667a5fb297bf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-29900ed0011b2c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f4dfbfc0.a69fb12f854882aa.js → bc324b7c.02a09dd93f6a399b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +122 -0
- package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.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/release/release-loop.yaml +6 -2
- package/package.json +1 -1
- package/plugins/agent-team/agents/research.md +1 -0
- package/scripts/ci-typecheck-changed.ts +3 -2
- package/scripts/coord-channel-watch.sh +26 -6
- package/scripts/coord-role-pack.ts +143 -0
- package/scripts/lib/morning-report-options.ts +41 -0
- package/scripts/pr-land-extra-remote-gates.ts +49 -0
- package/scripts/release-loop/gate-batch-safe.ts +23 -0
- package/scripts/release-loop/gate-history.ts +422 -0
- package/scripts/release-loop/gate-node.ts +310 -46
- package/scripts/release-loop/gate-triage-node.ts +190 -0
- package/scripts/release-loop/spawn-lane.ts +68 -0
- package/scripts/release-loop/tui-node-checks.ts +23 -0
- package/scripts/release-loop/version-node.ts +62 -4
- package/scripts/test-deterministic.ts +41 -12
- package/scripts/usage-rollup.ts +11 -3
- package/src/acp/core-turn-bridge.ts +98 -22
- package/src/acp/elanous-extensions.ts +2 -0
- package/src/acp/server.ts +2 -0
- package/src/agent/ref-grounding.ts +18 -0
- package/src/agent-substrate/pr-reviewer.ts +29 -21
- package/src/budget/pty-usage-reemit.ts +7 -0
- package/src/budget/run-usage-rollup.ts +9 -0
- package/src/budget/usage-daily-store.ts +98 -0
- package/src/capture/tui-self-report.ts +22 -4
- package/src/chat/index.ts +31 -10
- package/src/chat/pickers/modal-runtime.ts +1 -0
- package/src/chat/pickers/modals.ts +3 -1
- package/src/chat/turn-typeahead.ts +123 -16
- package/src/cli/dashboard-name-flag.ts +48 -0
- package/src/cli/doctor-cli.ts +80 -0
- package/src/cli/log-event-names.ts +12 -0
- package/src/cli/msg-cli.ts +45 -2
- package/src/cli/pr-cli.ts +382 -105
- package/src/cli/pr-land-heavy-remote.ts +233 -0
- package/src/cli/pr-land-overlap-evidence.ts +104 -5
- package/src/cli/pty-takeover-cli.ts +125 -16
- package/src/cli/release-cli.ts +44 -2
- package/src/cli/remote-resolve.ts +2 -1
- package/src/cli/seat-cli.ts +26 -16
- package/src/cli/tasks-cli.ts +8 -2
- package/src/cli/usage-cli.ts +146 -12
- package/src/cli/usage-daily-cli.ts +84 -0
- package/src/context-bus/context-now.ts +82 -5
- package/src/core-turn/auth-rejected-notice.ts +41 -0
- package/src/core-turn/run-core-turn.ts +13 -2
- package/src/core-turn/run-goal-loop.ts +17 -1
- package/src/core-turn/short-question.ts +45 -12
- package/src/core-turn/types.ts +7 -0
- package/src/dashboard/acp-active-model.ts +40 -0
- package/src/dashboard/auto-compact-runtime.ts +2 -0
- package/src/dashboard/boot-banner.ts +80 -0
- package/src/dashboard/dashboard-status-lines.ts +11 -0
- package/src/dashboard/detail-viewer-runtime.ts +15 -2
- package/src/dashboard/event-loop-stall-monitor.ts +4 -0
- package/src/dashboard/goal-loop-thinking.ts +16 -0
- package/src/dashboard/hitl-boot.ts +9 -4
- package/src/dashboard/index.ts +228 -387
- package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
- package/src/dashboard/input/chat-main-log-actions.ts +4 -0
- package/src/dashboard/input/chat-main-log-command.ts +12 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +172 -3
- package/src/dashboard/input/chat-main-session.ts +6 -2
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/chat-main-turn.ts +2 -1
- package/src/dashboard/input/compact-prepass-recovery.ts +97 -0
- package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
- package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
- package/src/dashboard/input/external-input-host.ts +45 -0
- package/src/dashboard/input/log-fold-binding.ts +18 -0
- package/src/dashboard/input/mouse-wiring.ts +17 -4
- package/src/dashboard/input/turn-steer-bridge.ts +94 -0
- package/src/dashboard/log-click-runtime.ts +5 -3
- package/src/dashboard/running-build-status.ts +74 -0
- package/src/dashboard/seat-boot-preamble.ts +113 -0
- package/src/dashboard/seat-local-instructions.ts +305 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +100 -28
- package/src/dashboard/slash-runtime/model-choices.ts +35 -0
- package/src/dashboard/term-slash-runtime.ts +15 -0
- package/src/dashboard/turn-preamble.ts +30 -2
- package/src/dashboard/turn-session-layers.ts +176 -0
- package/src/dashboard/turn-stream-formatter.ts +14 -6
- package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
- package/src/domains/release-tool.ts +8 -9
- package/src/domains/surface-events.ts +4 -1
- package/src/domains/watch-default-scheduler.ts +8 -9
- package/src/fold-stack.ts +24 -1
- package/src/git-fs/dirty.ts +32 -4
- package/src/git-fs/index.ts +43 -1
- package/src/graph-runner/runner.ts +1 -0
- package/src/harness/harness-gc.ts +32 -5
- package/src/index.ts +14 -1
- package/src/input/external-input-queue.ts +219 -0
- package/src/interactive-terminal-modal.ts +13 -0
- package/src/llm/route-decision.ts +25 -0
- package/src/llm-stream-retry-display.ts +59 -0
- package/src/llm.ts +253 -55
- package/src/log-entry.ts +3 -3
- package/src/log-pane/search.ts +29 -4
- package/src/loops/agent-reply.ts +256 -0
- package/src/loops/budget.ts +37 -7
- package/src/loops/loop-cli.ts +3 -2
- package/src/loops/msg-address.ts +57 -0
- package/src/loops/msg-wake.ts +282 -0
- package/src/loops/orchestrator/inbox.ts +60 -3
- package/src/loops/orchestrator/tick.ts +24 -4
- package/src/loops/registry.ts +42 -4
- package/src/memory.ts +20 -5
- package/src/native-tool-catalog.ts +125 -0
- package/src/nexus/api/http-server.ts +5 -0
- package/src/nexus/api/ops-api.ts +2 -0
- package/src/nexus/api/project-autopsy.ts +127 -0
- package/src/nexus/api/terminals.ts +3 -0
- package/src/nexus/api/workflow-approvals.ts +2 -0
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
- package/src/oauth/codex-account-store.ts +15 -3
- package/src/oauth/codex-billing-route.ts +31 -0
- package/src/ops/overview-collect.ts +19 -2
- package/src/panes/log-pane.ts +67 -8
- package/src/persona/presets.ts +44 -0
- package/src/plugins/maker/wizard-generate.ts +6 -4
- package/src/preview/terminal.ts +14 -1
- package/src/prompt-cache/types.ts +2 -0
- package/src/prompt-enhance/enhance.ts +24 -8
- package/src/prompt-library/universal-preamble.ts +273 -56
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/pty-manifest.ts +77 -5
- package/src/pty-shell/registry.ts +19 -2
- package/src/pty-shell/tui-run-state.ts +253 -0
- package/src/release-loop/light-rc.ts +28 -3
- package/src/release-loop/rehearsal.ts +1 -1
- package/src/render.ts +5 -1
- package/src/seat-loop/seat-report.ts +42 -2
- package/src/self-dev/run-supervisor.ts +71 -5
- package/src/self-dev/shard-aggregate.ts +2 -0
- package/src/self-dev/shard-run.ts +23 -2
- package/src/self-health/signatures.ts +132 -0
- package/src/self-implement/doctor-visit.ts +118 -0
- package/src/self-implement/gate-cli.ts +11 -2
- package/src/self-implement/goal-author-decompose.ts +80 -16
- package/src/self-implement/goal-author.ts +114 -72
- package/src/self-implement/goal-authoring-grounding.ts +1 -1
- package/src/self-implement/goal-file-name.ts +65 -0
- package/src/self-implement/ground-goal.ts +2 -1
- package/src/self-implement/host-regate.ts +14 -0
- package/src/self-implement/review-mustfix-class.ts +115 -0
- package/src/self-implement/run-ledger.ts +111 -7
- package/src/self-implement/running-runs.ts +10 -6
- package/src/self-implement/self-implement-runtime.ts +32 -0
- package/src/session/pending-input.ts +62 -11
- package/src/session-runtime/index.ts +7 -1
- package/src/skills/tools/ops-ledger.ts +707 -0
- package/src/skills/tools/persistent-grounding.ts +47 -7
- package/src/skills/tools/shell.ts +117 -1
- package/src/status/bar.ts +32 -2
- package/src/status/status-provider-info.ts +58 -0
- package/src/task-agent/rejudge-on-head.ts +4 -1
- package/src/task-agent/remote-rejudge-bind.ts +34 -5
- package/src/task-agent/repair-cycle.ts +13 -0
- package/src/task-orchestrator/surfaces/kubectl-transient-retry.ts +51 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +63 -7
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +6 -11
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +76 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +107 -33
- package/src/terminal/session-registry.ts +6 -0
- package/src/thinking-line.ts +12 -3
- package/src/tool-runtime/index.ts +4 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
- package/src/tool-runtime/ref-consult-runtime.ts +17 -2
- package/src/tool-runtime/run-shell-runtime.ts +4 -1
- package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
- package/src/tui.ts +5 -0
- package/src/user-config.ts +54 -6
- package/src/ux-sim/fake-llm.ts +29 -0
- package/src/ux-sim/in-process-cli.ts +175 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
- package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +0 -148
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1454-29d1d773d5996a49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +0 -34
- package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/599-56f2c0a5cc4a7295.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7752.5cbdd0b433c54af9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
- package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +0 -90
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +0 -79
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-256ffd365d32e100.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4c741eb760f2f77c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-e9ba98f5f1440a21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2f6f303fa114ec24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-ced0bcfc6542b3fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-bb1f05cd51c38944.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f736324afa2117c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-435f5e2faf02bc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-66a67eb19ebd976b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c71267e7681da982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-cb249e81ed339318.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-781cfc5114e097da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-478157214db6a023.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-86141f12cf090b7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-979d318a534e92da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-601fb77340e63c9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e117f801.e92bf10242653497.js +0 -1
- package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +0 -122
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
- package/src/dashboard/bench-slash-runtime.ts +0 -40
- package/src/dashboard/input/search-modal-router.ts +0 -9
- package/src/dashboard/modals/pane-key-router.ts +0 -27
- package/src/dashboard/view-slash-runtime.ts +0 -48
- /package/apps/pwa/out/_next/static/{y1ltt7oCZxVpC6zVPhZ2O → cIpv5nU9AycwYWZI9H589}/_ssgManifest.js +0 -0
|
@@ -11,20 +11,23 @@ import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/res
|
|
|
11
11
|
import { getElanousConfigDirOverride } from '../../src/elanous-config-dir.js';
|
|
12
12
|
import { diffFailures, junitFailures, parseFailures, parseTimedOutFailures } from './gate-diff';
|
|
13
13
|
import { loadEnvKnownFailures, splitKnownEnv } from './env-known-failures';
|
|
14
|
+
import { loadGateBatchSafe } from './gate-batch-safe';
|
|
14
15
|
import { baselineFromCutLogs } from './baseline-from-logs';
|
|
15
16
|
import { mergePartialFailures, readPartialPlan, testFileOfId } from './gate-partial';
|
|
16
|
-
import { logPlanWalltime, planDurations,
|
|
17
|
+
import { logPlanWalltime, planDurations, readFileMemory } from './shard-plan';
|
|
18
|
+
import { isGateSpawnLaneFile, planGateSpawnSeparatedShards } from './spawn-lane';
|
|
17
19
|
import { readJunitFileSeconds } from './gate-method';
|
|
18
20
|
import { deriveCdpTestPatterns } from '../test-deterministic';
|
|
19
21
|
import { emitNodeResult, readGraphContext } from './node-verdict.js';
|
|
20
22
|
import { isGateExecutor, type GateExecutor } from './gate-executor.js';
|
|
21
|
-
import { runPodCommand, parsePodCpu, resolvePodCpu, type RunPodCommandOptions, type PodCommandResult, type PodCpu } from '../../src/task-orchestrator/surfaces/pod-command-job.js';
|
|
23
|
+
import { runPodCommand, parsePodCpu, podCpuMillis, resolvePodCpu, type RunPodCommandOptions, type PodCommandResult, type PodCpu } from '../../src/task-orchestrator/surfaces/pod-command-job.js';
|
|
22
24
|
import { POD_BUN_CACHE_HOST_PATH, parseInstallSeconds, podBunCacheVolume } from '../../src/task-orchestrator/surfaces/pod-bun-cache.js';
|
|
23
25
|
import { PodPoolScheduler, parsePodPool, checkPodPool, defaultRemoteRun, type PodPoolMember } from '../../src/task-orchestrator/surfaces/pod-pool.js';
|
|
24
26
|
import { POD_INSTALL_SLOTS_DEFAULT, POD_INSTALL_SLOTS_HOST_PATH, installSlotScript } from '../../src/task-orchestrator/surfaces/pod-install-slots.js';
|
|
25
27
|
import { gateDepsInstallScript, parseGateDeps } from '../../src/task-orchestrator/surfaces/pod-gate-deps.js';
|
|
26
28
|
import { gateShardsPath, recordGateShardsVerdict, writeGateShards, type GateShard } from '../../src/release-loop/gate-shards.js';
|
|
27
29
|
import { defaultKubectl } from '../../src/task-orchestrator/surfaces/self-implement-pod.js';
|
|
30
|
+
import { executeTuiNodeCheck, type ExecutedTuiCheck } from './tui-node-checks.js';
|
|
28
31
|
|
|
29
32
|
interface CommandResult { rc: number; output: string; passedIds?: string[]; stalledEnv?: Array<{ file: string; reason: 'no-output' }>; timedOut?: boolean }
|
|
30
33
|
export interface GateRunner {
|
|
@@ -52,6 +55,8 @@ export interface GateOptions {
|
|
|
52
55
|
instanceRoot?: string;
|
|
53
56
|
ledgerRoot?: string;
|
|
54
57
|
repo?: string;
|
|
58
|
+
/** Rehearsal's opt-in screen measurement; normal release gates keep their existing defaults. */
|
|
59
|
+
rehearsalTui?: boolean;
|
|
55
60
|
/** freshShards — GATE-SHARD-RESUME off: every shard starts a Pod even when this logDir already holds its result. */
|
|
56
61
|
pod?: { pool: string; shards?: number; shardTimeoutSeconds?: number; durationSource?: string; bunCache?: string; freshShards?: boolean;
|
|
57
62
|
/** GATE-SKIP-KNOWN-RETRY — failure ids the previous release already had (and env-known ones): a shard that fails only
|
|
@@ -96,6 +101,8 @@ export interface GateResult {
|
|
|
96
101
|
knownEnvCleared: string[];
|
|
97
102
|
stalledEnv: Array<{ file: string; reason: 'no-output' | 'isolated-timeout'; local: 'passed' | 'failed' | 'timeout' }>;
|
|
98
103
|
rcNonzeroNoFailures: Array<{ file: string; rc: number; pass: number; baseline: 'same' | 'clean' | 'missing' }>;
|
|
104
|
+
/** GATE-HOST-RECHECK-CAP — files left unmeasured when the final serial host recheck reaches its bound. */
|
|
105
|
+
unmeasuredRecheckFiles?: string[];
|
|
99
106
|
baselineSource?: 'ledger' | 'instance' | 'cut-logs' | 'swept';
|
|
100
107
|
/** GATE-BASELINE-CACHE — isolated baseline files answered from the ledger (hits) or run now (misses). */
|
|
101
108
|
baselineCache?: { hits: number; misses: number };
|
|
@@ -112,6 +119,7 @@ export interface GateResult {
|
|
|
112
119
|
/** GATE-INTRO-RECHECK — new failures that were only the «timed out» shape and passed one isolated re-run with a
|
|
113
120
|
* {@link GATE_TIMEOUT_RECHECK_MS} per-test limit: a warning (flaky under load), not an introduced regression. */
|
|
114
121
|
loadFlaky?: string[];
|
|
122
|
+
rehearsalTui?: ExecutedTuiCheck;
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
const sha = /^[0-9a-f]{7,40}$/i;
|
|
@@ -274,20 +282,70 @@ export function shardParts(paths: readonly string[], seconds: (file: string) =>
|
|
|
274
282
|
if (current.length) parts.push(current);
|
|
275
283
|
return parts;
|
|
276
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* GATE-ENV-BASELINE (W5 · 10-15) — the gate shard Pod's deterministic test env, exported before anything runs.
|
|
287
|
+
* 0.2.29 gate failures were the Pod's «environment», not the code: no LLM provider · `man` stubbed · CLI spawn timeouts.
|
|
288
|
+
* - `TZ=UTC` — the value `bun test` already uses when TZ is unset; pinned so a later image (or a shell profile) cannot move it.
|
|
289
|
+
* - `LANG`/`LC_ALL=C.UTF-8` — the image sets no locale (POSIX); C.UTF-8 ships with glibc, so no image rebuild.
|
|
290
|
+
* - `ELANOUS_TEST_FAKE_LLM=1` — the shared switch for the fake LLM provider. Its reader (UX device #27790) is not on main
|
|
291
|
+
* yet; until it lands the switch changes nothing. The reader yields to an explicit provider/endpoint, so a spawned CLI
|
|
292
|
+
* test that injects its own stub keeps it.
|
|
293
|
+
* Retries, splits and file isolation all re-enter `runShard`, which builds every Pod shell here — they carry it too.
|
|
294
|
+
* Provider keys are not set here on purpose: `test:deterministic` strips every credential-shaped key
|
|
295
|
+
* (`scripts/lib/deterministic-env.ts` `isCredentialKey`), so a test never reaches a real provider from the Pod.
|
|
296
|
+
* Binaries the image lacks (`man` pages — `git <sub> --help`) are not fixed here; see MANUAL-gate-regression-response-recipe §2a.
|
|
297
|
+
*/
|
|
298
|
+
export const GATE_POD_ENV_BASELINE: Readonly<Record<string, string>> = Object.freeze({
|
|
299
|
+
TZ: 'UTC',
|
|
300
|
+
LANG: 'C.UTF-8',
|
|
301
|
+
LC_ALL: 'C.UTF-8',
|
|
302
|
+
ELANOUS_TEST_FAKE_LLM: '1',
|
|
303
|
+
});
|
|
304
|
+
export function gateEnvBaselineLine(env: Readonly<Record<string, string>> = GATE_POD_ENV_BASELINE): string {
|
|
305
|
+
return `export ${Object.entries(env).map(([key, value]) => `${key}=${quote(value)}`).join(' ')}`;
|
|
306
|
+
}
|
|
277
307
|
/**
|
|
278
308
|
* The shard's Pod shell. Install once (behind the node's install slots), then run each part under the soft deadline,
|
|
279
309
|
* leaving `install.log`/`install.rc`, `part-<i>.log`/`.rc`/`.junit.xml`, and `shard.timeout` (the part index) when the
|
|
280
|
-
* deadline cut the shard.
|
|
310
|
+
* deadline cut the shard. Real child/PTY parts have an additional 120 s test limit; a cap hit also writes
|
|
311
|
+
* `shard.timeout` so the artifact reader does not mistake an unfinished child for a test verdict.
|
|
312
|
+
* A part without `.rc` did not finish. The shell itself always exits 0 (as before).
|
|
281
313
|
*/
|
|
282
|
-
export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPatterns: readonly string[]; softSeconds: number; cachePrefix: string; installSlots: number; depsDir?: string; beatSeconds?: number }): string {
|
|
283
|
-
|
|
314
|
+
export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPatterns: readonly string[]; softSeconds: number; cachePrefix: string; installSlots: number; depsDir?: string; beatSeconds?: number; parallelParts?: number }): string {
|
|
315
|
+
// The planner keeps spawn files in their own shards; reject a mixed part rather than silently lose its limit.
|
|
316
|
+
for (const part of o.parts) {
|
|
317
|
+
if (part.some(isGateSpawnLaneFile) && !part.every(isGateSpawnLaneFile)) throw new Error('gate spawn lane part mixed with regular tests');
|
|
318
|
+
}
|
|
319
|
+
const spawnParts = o.parts.flatMap((part, index) => part.length && part.every(isGateSpawnLaneFile) ? [index] : []);
|
|
320
|
+
const commands = o.parts.map((part, index) => {
|
|
284
321
|
const ignores = o.cdpPatterns.filter((pattern) => part.includes(pattern)).flatMap((pattern) => ['--path-ignore-patterns', pattern]);
|
|
285
|
-
return `run_part ${index} ${['bun', 'run', 'test:deterministic', ...ignores, ...part.map(asPath)].map(quote).join(' ')}`;
|
|
286
|
-
})
|
|
322
|
+
return `run_part ${index} ${['bun', 'run', 'test:deterministic', ...(spawnParts.includes(index) ? ['--timeout=120000'] : []), ...ignores, ...part.map(asPath)].map(quote).join(' ')}`;
|
|
323
|
+
});
|
|
324
|
+
// Only file-isolation batches use this path. A bounded group shares one clone/install, but every test process gets
|
|
325
|
+
// its own HOME, state and tmp directory; part logs/JUnit remain separate and the existing artifact reader judges them.
|
|
326
|
+
const width = Math.max(1, Math.floor(o.parallelParts ?? 1));
|
|
327
|
+
const isolateParts = o.parallelParts !== undefined;
|
|
328
|
+
const run = width === 1 ? commands.join(' && ') : Array.from({ length: Math.ceil(commands.length / width) }, (_, group) => [
|
|
329
|
+
...commands.slice(group * width, (group + 1) * width).map((line) => `(${line}) & pids+=("$!")`),
|
|
330
|
+
'for pid in "${pids[@]}"; do wait "$pid" || true; done; pids=()',
|
|
331
|
+
].join('; ')).join('; ');
|
|
287
332
|
return [
|
|
288
333
|
'mkdir -p "$HOME/outbox"; O="$HOME/outbox"',
|
|
334
|
+
'stage_at() { printf "%s\\t%s\\n" "$1" "$2" >> "$O/stages.tsv"; }',
|
|
335
|
+
'stage() { stage_at "$(date +%s)" "$1"; }',
|
|
336
|
+
// This shell's first moment, captured before anything else runs so clone-end/shell-start keep their meaning.
|
|
337
|
+
'shell_t=$(date +%s)',
|
|
338
|
+
// Boot stages only: the container's age at shell entry. gate_end below keeps reading pod_age at its own spot.
|
|
339
|
+
`boot_age=$(awk -v t="$(cut -d' ' -f22 /proc/1/stat 2>/dev/null)" -v hz="$(getconf CLK_TCK 2>/dev/null)" '{ if (t > 0 && hz > 0) print int($1 - t / hz); else print 0 }' /proc/uptime 2>/dev/null)`,
|
|
340
|
+
'case "$boot_age" in ""|*[!0-9]*) boot_age=0;; esac',
|
|
341
|
+
// GATE-WARM-BOOT-STAGES: boot on the Pod's own clock — prep start = the child container's PID 1 (none when the age is
|
|
342
|
+
// unknown, never a guess), clone end = this shell's first line (the source checkout runs right before it).
|
|
343
|
+
'if [ "$boot_age" -gt 0 ]; then stage_at "$(( shell_t - boot_age ))" prep-start; fi',
|
|
344
|
+
'stage_at "$shell_t" clone-end',
|
|
345
|
+
'stage_at "$shell_t" shell-start',
|
|
289
346
|
...(o.beatSeconds ? gateBeatScript(o.beatSeconds, o.installSlots > 0) : []),
|
|
290
347
|
...(o.cachePrefix ? [o.cachePrefix] : []),
|
|
348
|
+
gateEnvBaselineLine(),
|
|
291
349
|
// Seconds since this container's PID 1 started (the clone ran before this shell) — 0 when /proc cannot tell.
|
|
292
350
|
`pod_age=$(awk -v t="$(cut -d' ' -f22 /proc/1/stat 2>/dev/null)" -v hz="$(getconf CLK_TCK 2>/dev/null)" '{ if (t > 0 && hz > 0) print int($1 - t / hz); else print 0 }' /proc/uptime 2>/dev/null)`,
|
|
293
351
|
'case "$pod_age" in ""|*[!0-9]*) pod_age=0;; esac',
|
|
@@ -295,19 +353,45 @@ export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPa
|
|
|
295
353
|
...(o.installSlots > 0 ? [installSlotScript({ slots: o.installSlots })] : []),
|
|
296
354
|
'run_part() {',
|
|
297
355
|
' local i=$1; shift',
|
|
356
|
+
...(spawnParts.length ? [' local spawn_part=0', ` case "$i" in ${spawnParts.join('|')}) spawn_part=1;; esac`] : []),
|
|
357
|
+
' stage "part-$i-start"',
|
|
358
|
+
...(isolateParts ? [
|
|
359
|
+
' local isolated; isolated=$(mktemp -d /tmp/gate-isolate.XXXXXX) || return 1',
|
|
360
|
+
' mkdir -p "$isolated/home" "$isolated/tmp" "$isolated/state" "$isolated/config" "$isolated/cache" "$isolated/data" "$isolated/xdg-state"',
|
|
361
|
+
' local source_repo="$PWD"',
|
|
362
|
+
' local -a run_env=(env HOME="$isolated/home" TMPDIR="$isolated/tmp" ELANOUS_STATE_DIR="$isolated/state" XDG_CONFIG_HOME="$isolated/config" XDG_CACHE_HOME="$isolated/cache" XDG_DATA_HOME="$isolated/data" XDG_STATE_HOME="$isolated/xdg-state")',
|
|
363
|
+
' stage "part-$i-setup-start"',
|
|
364
|
+
' local source_sha; source_sha=$(git rev-parse HEAD) || return 1',
|
|
365
|
+
' if ! "${run_env[@]}" git clone --shared --quiet --no-checkout "$source_repo" "$isolated/repo" > "$O/part-$i.setup.log" 2>&1 || ! "${run_env[@]}" git -C "$isolated/repo" checkout --detach --quiet "$source_sha" >> "$O/part-$i.setup.log" 2>&1; then cat "$O/part-$i.setup.log" > "$O/part-$i.log"; rm -rf "$isolated"; return 1; fi',
|
|
366
|
+
' ln -s "$source_repo/node_modules" "$isolated/repo/node_modules"',
|
|
367
|
+
' if [ -d "$source_repo/apps/pwa/node_modules" ]; then ln -s "$source_repo/apps/pwa/node_modules" "$isolated/repo/apps/pwa/node_modules"; fi',
|
|
368
|
+
' cd "$isolated/repo" || return 1',
|
|
369
|
+
' stage "part-$i-setup-end"',
|
|
370
|
+
] : [' local -a run_env=()']),
|
|
298
371
|
' local left=$(( gate_end - $(date +%s) ))',
|
|
299
372
|
' if [ "$left" -le 0 ]; then echo "$i" > "$O/shard.timeout"; return 1; fi',
|
|
300
|
-
'
|
|
373
|
+
...(spawnParts.length ? [' if [ "$spawn_part" -eq 1 ] && [ "$left" -gt 120 ]; then left=120; fi'] : []),
|
|
374
|
+
' stage "part-$i-test-start"',
|
|
375
|
+
...(spawnParts.length ? [' local test_start; test_start=$(date +%s)'] : []),
|
|
376
|
+
' "${run_env[@]}" timeout -k 10 "$left" "$@" --reporter=junit --reporter-outfile="$O/part-$i.junit.xml" > "$O/part-$i.log" 2>&1',
|
|
301
377
|
' local prc=$?',
|
|
378
|
+
...(spawnParts.length ? [' local test_end; test_end=$(date +%s)'] : []),
|
|
379
|
+
' stage "part-$i-test-end"',
|
|
380
|
+
...(isolateParts ? [' stage "part-$i-cleanup-start"', ' cd "$source_repo"', ' rm -rf "$isolated"', ' stage "part-$i-cleanup-end"'] : []),
|
|
381
|
+
' stage "part-$i-end"',
|
|
382
|
+
...(spawnParts.length ? [' if [ "$spawn_part" -eq 1 ] && { [ "$prc" -eq 124 ] || { [ "$test_end" -ge "$(( test_start + left ))" ] && { [ "$prc" -eq 137 ] || [ "$prc" -eq 143 ]; }; }; }; then echo "$i" > "$O/shard.timeout"; return 1; fi'] : []),
|
|
302
383
|
' if [ "$(date +%s)" -ge "$gate_end" ] && { [ "$prc" -eq 124 ] || [ "$prc" -eq 137 ] || [ "$prc" -eq 143 ]; }; then echo "$i" > "$O/shard.timeout"; return 1; fi',
|
|
303
384
|
' echo "$prc" > "$O/part-$i.rc"',
|
|
304
385
|
'}',
|
|
305
386
|
'if cd .. && cd repo; then',
|
|
387
|
+
' stage deps-start',
|
|
306
388
|
// GATE-IMAGE-DEPS: link the image's baked node_modules when the lockfiles match; only a miss installs (behind a slot).
|
|
307
389
|
...gateDepsInstallScript({ log: '"$O/install.log"', installSlots: o.installSlots, ...(o.depsDir ? { depsDir: o.depsDir } : {}) }).split('\n').map((line) => ` ${line}`),
|
|
308
390
|
' echo "$irc" > "$O/install.rc"',
|
|
309
|
-
|
|
391
|
+
' stage deps-end',
|
|
392
|
+
` if [ "$irc" -eq 0 ]; then stage test-start; ${width > 1 ? 'pids=(); ' : ''}${run || 'true'}; stage test-end; fi`,
|
|
310
393
|
'else echo 5 > "$O/install.rc"; fi',
|
|
394
|
+
'stage shell-end',
|
|
311
395
|
'true',
|
|
312
396
|
].join('\n');
|
|
313
397
|
}
|
|
@@ -355,6 +439,50 @@ export function readShardLiveLog(text: string): ShardLiveLog {
|
|
|
355
439
|
}
|
|
356
440
|
return { checkout, ...(beat ? { beat } : {}) };
|
|
357
441
|
}
|
|
442
|
+
|
|
443
|
+
/** Kubernetes clock boundaries for scheduling and init. Child start → shell-start includes source checkout and setup. */
|
|
444
|
+
export function readGatePodLifecycle(text: string): Record<string, string> {
|
|
445
|
+
try {
|
|
446
|
+
const pod = (JSON.parse(text) as { items?: Array<{ metadata?: { creationTimestamp?: string }; status?: {
|
|
447
|
+
conditions?: Array<{ type?: string; lastTransitionTime?: string }>;
|
|
448
|
+
initContainerStatuses?: Array<{ name?: string; state?: { terminated?: { startedAt?: string; finishedAt?: string } } }>;
|
|
449
|
+
containerStatuses?: Array<{ name?: string; state?: { terminated?: { startedAt?: string; finishedAt?: string } } }>;
|
|
450
|
+
} }> }).items?.[0];
|
|
451
|
+
if (!pod) return {};
|
|
452
|
+
const out: Record<string, string> = {};
|
|
453
|
+
const put = (key: string, value?: string) => { if (value && Number.isFinite(Date.parse(value))) out[key] = value; };
|
|
454
|
+
put('podCreated', pod.metadata?.creationTimestamp);
|
|
455
|
+
put('podScheduled', pod.status?.conditions?.find((item) => item.type === 'PodScheduled')?.lastTransitionTime);
|
|
456
|
+
for (const item of pod.status?.initContainerStatuses ?? []) {
|
|
457
|
+
if (!item.name || !/^[a-z0-9-]+$/.test(item.name)) continue;
|
|
458
|
+
put(`init-${item.name}-start`, item.state?.terminated?.startedAt);
|
|
459
|
+
put(`init-${item.name}-end`, item.state?.terminated?.finishedAt);
|
|
460
|
+
}
|
|
461
|
+
const child = pod.status?.containerStatuses?.find((item) => item.name === 'child');
|
|
462
|
+
put('childStart', child?.state?.terminated?.startedAt);
|
|
463
|
+
put('childEnd', child?.state?.terminated?.finishedAt);
|
|
464
|
+
return out;
|
|
465
|
+
} catch { return {}; }
|
|
466
|
+
}
|
|
467
|
+
/** Seconds with at least one isolated test process running; setup gaps between parallel groups remain overhead. */
|
|
468
|
+
export function gateBatchTestWallSeconds(stages: Record<string, number> | undefined, partCount: number): number | undefined {
|
|
469
|
+
if (!stages || partCount < 1) return undefined;
|
|
470
|
+
const spans: Array<[number, number]> = [];
|
|
471
|
+
for (let index = 0; index < partCount; index++) {
|
|
472
|
+
const start = stages[`part-${index}-test-start`];
|
|
473
|
+
const end = stages[`part-${index}-test-end`];
|
|
474
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end! < start!) return undefined;
|
|
475
|
+
spans.push([start!, end!]);
|
|
476
|
+
}
|
|
477
|
+
spans.sort((a, b) => a[0] - b[0]);
|
|
478
|
+
let covered = 0;
|
|
479
|
+
let [from, to] = spans[0]!;
|
|
480
|
+
for (const [start, end] of spans.slice(1)) {
|
|
481
|
+
if (start <= to) to = Math.max(to, end);
|
|
482
|
+
else { covered += to - from; from = start; to = end; }
|
|
483
|
+
}
|
|
484
|
+
return covered + to - from;
|
|
485
|
+
}
|
|
358
486
|
/**
|
|
359
487
|
* GATE-POD-STALL-FAILFAST — watches one running shard Job. Armed once the source checkout line is seen; disarmed for good
|
|
360
488
|
* the moment any test output exists (that shard then behaves exactly as before). Stalled = `stallSeconds` since the
|
|
@@ -645,6 +773,8 @@ class StalledPodShards extends Error {
|
|
|
645
773
|
|
|
646
774
|
/** Isolated re-runs (host stall re-run · cut and baseline re-checks) are time-limited; sweeps and installs keep their full time. */
|
|
647
775
|
export const GATE_ISOLATED_TIMEOUT_MS = 300_000;
|
|
776
|
+
/** Bound the final serial host phase until isolated checks can run safely in parallel on separate worktrees. */
|
|
777
|
+
export const GATE_HOST_RECHECK_FILE_LIMIT = 32;
|
|
648
778
|
/** GATE-INTRO-RECHECK (0.2.19) — the per-test limit of the one re-run given to a «timed out after 5000ms» new failure.
|
|
649
779
|
* 0.2.18: both first-gate introductions were 5 s limits missed at 6.04/6.06 s, and they alone cost an 84-minute re-gate. */
|
|
650
780
|
export const GATE_TIMEOUT_RECHECK_MS = 60_000;
|
|
@@ -807,11 +937,12 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
807
937
|
// The TD1 measurements predate the fixture-only gate; do not isolate those five files at their old 2–13 GB peaks.
|
|
808
938
|
const fixtureOnly = new Set([...GATE_NIGHTLY_AUDITS, 'test/guardian/dispatch-surface-contract.test.ts', 'test/user-config-mcp.test.ts']);
|
|
809
939
|
const heavy = new Set(assignable.filter((file) => !fixtureOnly.has(file) && (memory.get(file) ?? 0) >= POD_HEAVY_FILE_MB));
|
|
810
|
-
const
|
|
940
|
+
const { shards: lightShards, spawnFiles: spawnLane, spawnShardCount } = planGateSpawnSeparatedShards(assignable.filter((file) => !heavy.has(file)), durations, shardCount);
|
|
811
941
|
const shards = [
|
|
812
|
-
...
|
|
942
|
+
...lightShards,
|
|
813
943
|
...[...heavy].map((file) => ({ files: [file], plannedSeconds: durations.get(file) ?? 0 })),
|
|
814
944
|
];
|
|
945
|
+
if (spawnLane.length) debug.log('release-loop.gate', 'pod-spawn-lane', { files: spawnLane, shards: spawnShardCount });
|
|
815
946
|
logPlanWalltime(planWall, shards);
|
|
816
947
|
if (heavy.size) debug.log('release-loop.gate', 'pod-heavy-alone', { files: [...heavy], thresholdMb: POD_HEAVY_FILE_MB, memoryLimit: POD_ISOLATION_MEMORY_LIMIT });
|
|
817
948
|
const known = assignable.filter((file) => durations.has(file)).length;
|
|
@@ -822,7 +953,10 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
822
953
|
});
|
|
823
954
|
// GATE-SPEED A3①: shard Pod CPU (`release.loop.gatePodCpu` · default request 1 / limit 4) — shards × request must fit the pool.
|
|
824
955
|
const cpu = resolvePodCpu(pod.cpu);
|
|
956
|
+
// Only evidence-backed opt-in files reach this batch; every other file retains its own Pod below.
|
|
957
|
+
const batchWidth = Math.max(1, Math.min(4, Math.floor(podCpuMillis(cpu.limit)! / 1000)));
|
|
825
958
|
debug.log('release-loop.gate', 'shard-resources', { shards: shards.length, cpuRequest: cpu.request, cpuLimit: cpu.limit, cpuSource: pod.cpu ? 'config' : 'default' });
|
|
959
|
+
debug.log('release-loop.gate', 'isolation-batch-width', { batchWidth, cpuLimit: cpu.limit });
|
|
826
960
|
const ready = poolOverride ? undefined : checkPodPool(parsePodPool(pod.pool), defaultKubectl);
|
|
827
961
|
if (ready && !ready.ok) throw new Error('pod command: 풀의 노드가 하나도 준비되지 않았다');
|
|
828
962
|
const poolScheduler = poolOverride ?? new PodPoolScheduler(ready!.ready);
|
|
@@ -895,6 +1029,8 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
895
1029
|
// 깊이 끝 OOM 조각은 «조각 전체»를 파일 하나씩 격리한다 — 상한 40 이면 나머지가 못 잰 채 남았다(09-30 ① 7번 조각 110 파일).
|
|
896
1030
|
const isolationRemaining = shards.map((item) => item.files.length);
|
|
897
1031
|
const knownFailures = new Set(pod.knownFailures ?? []);
|
|
1032
|
+
const batchSafe = loadGateBatchSafe(repo);
|
|
1033
|
+
debug.log('release-loop.gate', 'batch-safe-opt-in', { files: batchSafe.size });
|
|
898
1034
|
const estimated = (paths: string[]) => paths.reduce((sum, file) => {
|
|
899
1035
|
const value = durations.get(file);
|
|
900
1036
|
return sum + (value !== undefined && Number.isFinite(value) && value >= 0 ? value : unknownSeconds);
|
|
@@ -935,13 +1071,13 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
935
1071
|
},
|
|
936
1072
|
release: (member: Parameters<PodPoolScheduler['release']>[0]) => poolScheduler.release(member),
|
|
937
1073
|
}) as unknown as PodPoolScheduler;
|
|
938
|
-
const runShard = async (paths: string[], shard: number, depth = 0, branch = '', retriedNoOutput = false, fresh = pod.freshShards === true, parentAttempt?: string, hostRetries = 0): Promise<{ runs: ShardRun[]; stalled: NonNullable<GateResult['stalledShards']> }> => {
|
|
1074
|
+
const runShard = async (paths: string[], shard: number, depth = 0, branch = '', retriedNoOutput = false, fresh = pod.freshShards === true, parentAttempt?: string, hostRetries = 0, batchIsolation = false): Promise<{ runs: ShardRun[]; stalled: NonNullable<GateResult['stalledShards']> }> => {
|
|
939
1075
|
// 파일별 소요는 junit 으로 남긴다 — 콘솔 요약(판정 원천)은 그대로이고, 느린 시험 목록(K10 D4)·계층 분리(D2)의 자가 된다.
|
|
940
1076
|
// GATE-TIMEOUT-HEAL: parts (each with its own junit) under a soft deadline inside this shard's own Job deadline.
|
|
941
|
-
const shardDeadline = shardDeadlineSeconds(estimated(paths), deadlineSeconds);
|
|
942
|
-
const parts = shardParts(paths, (file) => estimated([file]));
|
|
943
|
-
const memoryLimit = paths.length === 1 && (depth >= 1 || heavy.has(paths[0]!)) ? POD_ISOLATION_MEMORY_LIMIT : undefined;
|
|
944
|
-
const shellOptions = { parts, cdpPatterns, softSeconds: softDeadlineSeconds(shardDeadline), cachePrefix, installSlots };
|
|
1077
|
+
const shardDeadline = shardDeadlineSeconds(batchIsolation ? Math.max(...paths.map((file) => estimated([file]))) * Math.ceil(paths.length / batchWidth) : estimated(paths), deadlineSeconds);
|
|
1078
|
+
const parts = batchIsolation ? paths.map((file) => [file]) : shardParts(paths, (file) => estimated([file]));
|
|
1079
|
+
const memoryLimit = batchIsolation || paths.length === 1 && (depth >= 1 || heavy.has(paths[0]!)) ? POD_ISOLATION_MEMORY_LIMIT : undefined;
|
|
1080
|
+
const shellOptions = { parts, cdpPatterns, softSeconds: softDeadlineSeconds(shardDeadline), cachePrefix, installSlots, ...(batchIsolation ? { parallelParts: batchWidth } : {}) };
|
|
945
1081
|
const keyShell = gateShardShell(shellOptions);
|
|
946
1082
|
// The stall beat only reports; runKey keeps hashing the shell without it, so earlier results stay reusable.
|
|
947
1083
|
const podShell = stallWatch ? gateShardShell({ ...shellOptions, beatSeconds: gateStallBeatSeconds(stallSeconds) }) : keyShell;
|
|
@@ -949,9 +1085,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
949
1085
|
let start = Date.now();
|
|
950
1086
|
let admitted: GateAdmissionResult | undefined;
|
|
951
1087
|
let output: string | undefined;
|
|
1088
|
+
const phaseTimes: Record<string, string> = {};
|
|
1089
|
+
const stamp = (phase: string) => { phaseTimes[phase] = new Date().toISOString(); };
|
|
1090
|
+
let podStages: Record<string, number> | undefined;
|
|
1091
|
+
let podLifecycle: Record<string, string> | undefined;
|
|
1092
|
+
let batchArtifactsComplete = true;
|
|
952
1093
|
let junit: string | undefined;
|
|
953
1094
|
let rc: number | undefined;
|
|
954
1095
|
let jobExitCode: number | undefined;
|
|
1096
|
+
let batchArtifactDir: string | undefined;
|
|
955
1097
|
let lastFile: string | undefined;
|
|
956
1098
|
let jobFailed = false;
|
|
957
1099
|
let jobError = '';
|
|
@@ -967,7 +1109,8 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
967
1109
|
// cap chunks for a big root shard · halves otherwise · none for one file).
|
|
968
1110
|
// Isolation follows only while this shard's isolation budget still covers every file (review r7) — the budget is the
|
|
969
1111
|
// shard's file count and isolations take disjoint files, so this holds unless the plan changed; if not, run the Pod.
|
|
970
|
-
const splitChild = depth === 2 && paths.length > 1 ? (isolationRemaining[shard]! >= paths.length
|
|
1112
|
+
const splitChild = depth === 2 && paths.length > 1 ? (isolationRemaining[shard]! >= paths.length
|
|
1113
|
+
? batchIsolation || !paths.every((file) => batchSafe.has(file)) ? '-file-0' : '-batch' : undefined)
|
|
971
1114
|
: depth < 2 && paths.length > 1 ? (depth === 0 && paths.length > POD_SHARD_FILE_CAP ? '-c0' : '-0') : undefined;
|
|
972
1115
|
const found = !fresh && logDir ? previousShardDescent(logDir, `pod-${shard}${branch}`, commit, paths, runKey, parentAttempt, splitChild) : undefined;
|
|
973
1116
|
const descent = found?.way;
|
|
@@ -977,7 +1120,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
977
1120
|
if (descent === 'retry') {
|
|
978
1121
|
// «descend» is only the way down; «resumed» comes from each leaf whose log reads cleanly (review r4).
|
|
979
1122
|
debug.log('release-loop.gate', 'pod-shard-descend', { shard, branch, files: paths.length, via: 'retry' });
|
|
980
|
-
return runShard(paths, shard, depth, `${branch}-retry`, true, undefined, attemptId);
|
|
1123
|
+
return runShard(paths, shard, depth, `${branch}-retry`, true, undefined, attemptId, hostRetries, batchIsolation);
|
|
981
1124
|
}
|
|
982
1125
|
if (descent === 'split') {
|
|
983
1126
|
output = undefined;
|
|
@@ -989,7 +1132,9 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
989
1132
|
jobExitCode = 0;
|
|
990
1133
|
lastFile = lastStartedTestFile(output, paths);
|
|
991
1134
|
} else try {
|
|
1135
|
+
stamp('admissionStart');
|
|
992
1136
|
admitted = await admitGateShard(gateAdmission, { waitMs: admissionWaitSeconds * 1000, onWait: (reason) => markShard(shard, { waitReason: reason }) });
|
|
1137
|
+
stamp('admissionEnd');
|
|
993
1138
|
if (admitted.outcome !== 'off') debug.log('release-loop.gate', 'shard-admission', { shard, branch, outcome: admitted.outcome, waitedMs: admitted.waitedMs, ...(admitted.reason ? { reason: admitted.reason } : {}) },
|
|
994
1139
|
admitted.outcome === 'granted' ? undefined : { level: 'warn' });
|
|
995
1140
|
// The admission wait is not the shard's run time: deadline/timeout judgment and the measured duration start here.
|
|
@@ -1007,7 +1152,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1007
1152
|
} }) : undefined;
|
|
1008
1153
|
const placed = admitted.release;
|
|
1009
1154
|
const job = await podCommand({
|
|
1010
|
-
pool: pod.pool, poolScheduler: trackedPool(shard, depth > 0 || branch !== '', (member) => { jobContext = member.context; placedOn = member.context; placed(); }), clone: true, source: { kind: 'commit', sha: commit }, deadlineSeconds: shardDeadline,
|
|
1155
|
+
pool: pod.pool, poolScheduler: trackedPool(shard, depth > 0 || branch !== '', (member) => { stamp('poolPlaced'); jobContext = member.context; placedOn = member.context; placed(); }), clone: true, source: { kind: 'commit', sha: commit }, deadlineSeconds: shardDeadline,
|
|
1011
1156
|
...(multiHost ? { statusUnreadableMs: memberUnreadableSeconds * 1000 } : {}),
|
|
1012
1157
|
...(bunCache ? { bunCache } : {}),
|
|
1013
1158
|
...(installSlots > 0 ? { installSlots: POD_INSTALL_SLOTS_HOST_PATH } : {}),
|
|
@@ -1017,8 +1162,30 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1017
1162
|
name: jobName,
|
|
1018
1163
|
command: ['bash', '-lc', podShell],
|
|
1019
1164
|
}).finally(() => watch?.stop());
|
|
1165
|
+
stamp('jobReturned');
|
|
1166
|
+
if (!poolOverride && placedOn) {
|
|
1167
|
+
try {
|
|
1168
|
+
const got = defaultKubectl(['--context', placedOn, '-n', 'elanous-test', 'get', 'pods', '-l', `job-name=${job.job}`, '-o', 'json']);
|
|
1169
|
+
if (got.status === 0) podLifecycle = readGatePodLifecycle(got.stdout);
|
|
1170
|
+
} catch { /* timings never change the verdict */ }
|
|
1171
|
+
}
|
|
1020
1172
|
jobExitCode = job.exitCode;
|
|
1173
|
+
batchArtifactDir = job.artifactsDir;
|
|
1021
1174
|
const read = readShardArtifacts(job.artifactsDir, parts);
|
|
1175
|
+
batchArtifactsComplete = !batchIsolation || parts.every((_, index) =>
|
|
1176
|
+
['rc', 'log', 'junit.xml'].every((suffix) => existsSync(join(job.artifactsDir, `part-${index}.${suffix}`))));
|
|
1177
|
+
const stagesPath = join(job.artifactsDir, 'stages.tsv');
|
|
1178
|
+
if (existsSync(stagesPath)) {
|
|
1179
|
+
try {
|
|
1180
|
+
podStages = Object.fromEntries(readFileSync(stagesPath, 'utf8').split(/\r?\n/).flatMap((line) => {
|
|
1181
|
+
const match = /^(\d+)\t([a-z0-9-]+)$/.exec(line);
|
|
1182
|
+
return match ? [[match[2]!, Number(match[1])]] : [];
|
|
1183
|
+
}));
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
debug.log('release-loop.gate', 'pod-stages-unreadable', { shard, branch, error: String(error) }, { level: 'warn' });
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
stamp('artifactsRead');
|
|
1022
1189
|
({ output, junit, rc, timedOut, finished, unfinishedLog, exitCodeOnly } = read);
|
|
1023
1190
|
// A stall counts only when the Job also left no verdict (a failed stop can let a late shard finish after all).
|
|
1024
1191
|
const stalledAt = watch?.stalled();
|
|
@@ -1039,7 +1206,12 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1039
1206
|
const durationMs = Date.now() - start;
|
|
1040
1207
|
const fileSeconds = junit === undefined ? undefined : Object.fromEntries(readJunitFileSeconds(junit));
|
|
1041
1208
|
const testSeconds = fileSeconds === undefined ? undefined : Object.values(fileSeconds).reduce((sum, seconds) => sum + seconds, 0);
|
|
1042
|
-
const
|
|
1209
|
+
const testWallSeconds = batchIsolation
|
|
1210
|
+
? gateBatchTestWallSeconds(podStages, parts.length)
|
|
1211
|
+
: podStages?.['test-start'] !== undefined && podStages?.['test-end'] !== undefined
|
|
1212
|
+
? Math.max(0, podStages['test-end'] - podStages['test-start']) : undefined;
|
|
1213
|
+
const podOverheadSeconds = testWallSeconds !== undefined || (!batchIsolation && testSeconds !== undefined)
|
|
1214
|
+
? Math.max(0, durationMs / 1000 - (testWallSeconds ?? testSeconds!)) : undefined;
|
|
1043
1215
|
// A reused shard keeps its files as they are — rewriting would replace the measured durationMs the next release plans by.
|
|
1044
1216
|
if (logDir && !reused && !descent) {
|
|
1045
1217
|
mkdirSync(logDir, { recursive: true });
|
|
@@ -1057,7 +1229,10 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1057
1229
|
else rmSync(unfinishedDestination, { force: true });
|
|
1058
1230
|
writeFileSync(join(logDir, `pod-${shard}${branch}.json`), JSON.stringify({ durationMs, rc: rc ?? null,
|
|
1059
1231
|
...(stall ? { reason: 'stall', finishedFiles: 0, stallSeconds: stall.seconds, sinceCheckoutMs: stall.sinceCheckoutMs } : timedOut ? { reason: 'timeout', finishedFiles: finished.length } : {}), files: paths, plannedSeconds: estimated(paths), deadlineSeconds: shardDeadline, shardCount: shards.length, commit, runKey, attemptId, ...(parentAttempt ? { parentAttempt } : {}), jobExitCode: jobExitCode ?? null, jobFailed, ...(placedOn ? { host: placedOn } : {}),
|
|
1060
|
-
...(
|
|
1232
|
+
...(Object.keys(phaseTimes).length ? { phaseTimes } : {}), ...(podStages ? { podStages } : {}),
|
|
1233
|
+
...(podLifecycle && Object.keys(podLifecycle).length ? { podLifecycle } : {}),
|
|
1234
|
+
...(fileSeconds !== undefined ? { fileSeconds, testSeconds } : {}), ...(testWallSeconds !== undefined ? { testWallSeconds } : {}),
|
|
1235
|
+
...(podOverheadSeconds !== undefined ? { podOverheadSeconds } : {}),
|
|
1061
1236
|
...(admitted && admitted.outcome !== 'off' ? { admission: admitted.outcome, admissionWaitMs: admitted.waitedMs } : {}) }) + '\n', { mode: 0o600 });
|
|
1062
1237
|
}
|
|
1063
1238
|
const installSeconds = parseInstallSeconds(output ?? '');
|
|
@@ -1078,6 +1253,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1078
1253
|
// GATE-POD-STALL-FAILFAST: stopped with no test output — the existing «no output» reason (one fresh retry).
|
|
1079
1254
|
else if (stall) reason = 'no-output';
|
|
1080
1255
|
else if (timedOut) reason = 'timeout';
|
|
1256
|
+
else if (batchIsolation && !batchArtifactsComplete) reason = 'incomplete';
|
|
1081
1257
|
// GATE-POD-STALL-FAILFAST (OP): a complete summary with 0 fail · 0 error but an exit other than 0/1 is an exit-code
|
|
1082
1258
|
// anomaly (0.2.23: a test left process.exitCode set → «0 fail · rc 3» read as a stalled shard). Same split/isolation
|
|
1083
1259
|
// path as job-failed — only the label differs, so the verdict names the file instead of saying «stalled».
|
|
@@ -1116,14 +1292,14 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1116
1292
|
// A reused result that the current tool cannot read cleanly is not a verdict: run that shard for real.
|
|
1117
1293
|
if (reused && reason) {
|
|
1118
1294
|
debug.log('release-loop.gate', 'pod-shard-resume-miss', { shard, branch, reason });
|
|
1119
|
-
return runShard(paths, shard, depth, branch, retriedNoOutput, true, parentAttempt);
|
|
1295
|
+
return runShard(paths, shard, depth, branch, retriedNoOutput, true, parentAttempt, hostRetries, batchIsolation);
|
|
1120
1296
|
}
|
|
1121
1297
|
// GATE-MULTI-HOST: the Job failed because its member is gone (launch failed · status unreadable) — not the shard's
|
|
1122
1298
|
// fault, so no split: the same files run again on the members left. Bounded by the roster size.
|
|
1123
1299
|
if (jobFailed && placedOn && hostRetries < poolScheduler.members.length && memberLost(placedOn, shard, jobError)
|
|
1124
1300
|
&& poolScheduler.members.some((m) => !downMembers.has(m.context))) {
|
|
1125
1301
|
debug.log('release-loop.gate', 'pod-shard-host-retry', { shard, branch, files: paths.length, lostMember: placedOn, attempt: hostRetries + 1 }, { level: 'warn' });
|
|
1126
|
-
return runShard(paths, shard, depth, `${branch}-h${hostRetries}`, retriedNoOutput, undefined, attemptId, hostRetries + 1);
|
|
1302
|
+
return runShard(paths, shard, depth, `${branch}-h${hostRetries}`, retriedNoOutput, undefined, attemptId, hostRetries + 1, batchIsolation);
|
|
1127
1303
|
}
|
|
1128
1304
|
// GATE-TIMEOUT-HEAL ④: a Pod that died before any test ran (no outbox · jobExitCode≠0 — 0.2.19: isolated retries
|
|
1129
1305
|
// ending with exit 5, the source checkout) gets the same one fresh retry as «no output» instead of stalling the sweep.
|
|
@@ -1131,13 +1307,45 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1131
1307
|
const diedBeforeTests = reason === 'job-failed' && output === undefined && !jobFailed && jobExitCode !== undefined && jobExitCode !== 0
|
|
1132
1308
|
&& jobExitCode !== 137 && (paths.length === 1 || jobExitCode === 5);
|
|
1133
1309
|
if ((reason === 'no-output' || diedBeforeTests) && !retriedNoOutput) {
|
|
1134
|
-
const retry = await runShard(paths, shard, depth, `${branch}-retry`, true, undefined, attemptId);
|
|
1310
|
+
const retry = await runShard(paths, shard, depth, `${branch}-retry`, true, undefined, attemptId, hostRetries, batchIsolation);
|
|
1135
1311
|
debug.log('release-loop.gate', 'pod-shard-retry', { shard, files: paths, reason, outcome: retry.stalled[0]?.reason ?? 'ok' });
|
|
1136
1312
|
return retry;
|
|
1137
1313
|
}
|
|
1138
1314
|
// GATE-POD-STALL-FAILFAST: a stall after the fresh retry is unmeasured — no split, no isolation: smaller Pods on the
|
|
1139
1315
|
// same stalled node only re-measure the stall (10-10: retries and splits repeated it for 2h+).
|
|
1140
1316
|
if (stall && reason === 'no-output') return { runs: [], stalled: [{ shard, files: paths, reason, stall }] };
|
|
1317
|
+
// A shared Job may finish some file parts before another part loses its JUnit/log/rc. Keep every complete part's
|
|
1318
|
+
// original verdict, including a failure, and rerun only parts without the full artifact trio.
|
|
1319
|
+
if (batchIsolation && !batchArtifactsComplete && batchArtifactDir && reason) {
|
|
1320
|
+
const measured: ShardRun[] = [];
|
|
1321
|
+
const missing: string[] = [];
|
|
1322
|
+
parts.forEach((part, index) => {
|
|
1323
|
+
const file = part[0]!;
|
|
1324
|
+
try {
|
|
1325
|
+
const prefix = join(batchArtifactDir!, `part-${index}`);
|
|
1326
|
+
const partLog = readFileSync(`${prefix}.log`, 'utf8');
|
|
1327
|
+
const partJunit = readFileSync(`${prefix}.junit.xml`, 'utf8');
|
|
1328
|
+
const partRc = Number(readFileSync(`${prefix}.rc`, 'utf8').trim());
|
|
1329
|
+
const ranPart = lastMatch(partLog, /Ran (\d+) tests? across (\d+) files?/);
|
|
1330
|
+
const passPart = summaryCount(partLog, 'pass'), failPart = summaryCount(partLog, 'fail');
|
|
1331
|
+
const errorsPart = summaryCount(partLog, 'error');
|
|
1332
|
+
if ((partRc !== 0 && partRc !== 1) || !ranPart || Number(ranPart[2]) !== 1
|
|
1333
|
+
|| !Number.isFinite(passPart) || !Number.isFinite(failPart)) throw new Error('incomplete part');
|
|
1334
|
+
const attributed = failuresOf({ rc: partRc, output: partLog }, `pod-${shard} part-${index}`);
|
|
1335
|
+
if (attributed.failures.length !== failPart) throw new Error('unattributed part');
|
|
1336
|
+
measured.push({ output: partLog, rc: partRc, pass: passPart, fail: failPart,
|
|
1337
|
+
errors: Number.isFinite(errorsPart) ? errorsPart : 0, ran: Number(ranPart[1]), files: 1,
|
|
1338
|
+
passedIds: junitPassedIds(partJunit).map(podRelative) });
|
|
1339
|
+
} catch { missing.push(file); }
|
|
1340
|
+
});
|
|
1341
|
+
if (measured.length && missing.length) {
|
|
1342
|
+
debug.log('release-loop.gate', 'isolation-batch-partial', { shard, branch, measured: measured.length, missing });
|
|
1343
|
+
const children = await Promise.all(missing.map((file) => runShard([file], shard, depth + 1,
|
|
1344
|
+
`${branch}-file-${paths.indexOf(file)}`, false, undefined, attemptId)));
|
|
1345
|
+
return { runs: [...measured, ...children.flatMap((child) => child.runs)],
|
|
1346
|
+
stalled: children.flatMap((child) => child.stalled) };
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1141
1349
|
if (reason) {
|
|
1142
1350
|
// GATE-SKIP-KNOWN-RETRY — a shard whose summary is complete but whose failures could not be read back (unattributed)
|
|
1143
1351
|
// and whose every named failure is one the previous release already had is not re-run: re-running only re-measures
|
|
@@ -1162,7 +1370,8 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1162
1370
|
debug.log('release-loop.gate', 'retry-narrowed', { shard, before: paths.length, after: narrowed.length });
|
|
1163
1371
|
const kept = new Set(paths.filter((file) => !narrowed.includes(file)));
|
|
1164
1372
|
const passedIds = junitPassedIds(junit!).map(podRelative).filter((id) => { try { return kept.has(testFileOfId(id)); } catch { return false; } });
|
|
1165
|
-
const
|
|
1373
|
+
const directBatch = narrowed.length > 1 && narrowed.length <= POD_SHARD_FILE_CAP && narrowed.every((file) => batchSafe.has(file));
|
|
1374
|
+
const child = await runShard(narrowed, shard, directBatch ? 2 : depth, `${branch}-n`, false, undefined, attemptId, 0, directBatch);
|
|
1166
1375
|
return { runs: [{ output: '', rc: 0, pass: passedIds.length, fail: 0, errors: 0, ran: passedIds.length, files: kept.size, passedIds },
|
|
1167
1376
|
...child.runs], stalled: child.stalled };
|
|
1168
1377
|
}
|
|
@@ -1171,19 +1380,27 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1171
1380
|
if (depth === 2 && paths.length > 1) {
|
|
1172
1381
|
const count = Math.min(paths.length, isolationRemaining[shard]!);
|
|
1173
1382
|
isolationRemaining[shard]! -= count;
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1383
|
+
const batchPaths = paths.slice(0, count);
|
|
1384
|
+
// The common path already ran every file as an isolated part in this same Job. Only an incomplete batch
|
|
1385
|
+
// needs a fresh per-file Pod, preserving the earlier fail-closed behavior when the shared Job died.
|
|
1386
|
+
const canBatch = batchPaths.length > 1 && batchPaths.every((file) => batchSafe.has(file));
|
|
1387
|
+
const batch = batchIsolation || !canBatch ? undefined : await runShard(batchPaths, shard, depth + 1, `${branch}-batch`, false, undefined, attemptId, 0, true);
|
|
1388
|
+
const retryPaths = !batch ? batchPaths : batchPaths.filter((file) => batch.stalled.some((item) => item.files.includes(file)));
|
|
1389
|
+
const children = !batch || batch.stalled.length ? await Promise.all(retryPaths.map(async (file) => {
|
|
1390
|
+
const child = await runShard([file], shard, depth + 1, `${branch}-file-${batchPaths.indexOf(file)}`, false, undefined, attemptId);
|
|
1176
1391
|
debug.log('release-loop.gate', 'pod-shard-isolate', { shard, file, outcome: child.stalled[0]?.reason ?? 'ok' });
|
|
1177
1392
|
return child;
|
|
1178
|
-
}));
|
|
1179
|
-
|
|
1393
|
+
})) : [batch];
|
|
1394
|
+
debug.log('release-loop.gate', 'pod-shard-isolate-batch', { shard, files: batchPaths.length, fallback: !batch || batch.stalled.length > 0 });
|
|
1395
|
+
return { runs: [...(batch?.stalled.length ? batch.runs : []), ...children.flatMap((child) => child.runs)], stalled: [
|
|
1180
1396
|
...children.flatMap((child) => child.stalled),
|
|
1397
|
+
...(batch?.stalled.filter((item) => item.files.some((file) => !retryPaths.includes(file))) ?? []),
|
|
1181
1398
|
...(paths.length > count ? [{ shard, files: paths.slice(count), reason,
|
|
1182
1399
|
...(lastFile ? { lastFile } : {}),
|
|
1183
1400
|
}] : []),
|
|
1184
1401
|
] };
|
|
1185
1402
|
}
|
|
1186
|
-
if (depth
|
|
1403
|
+
if (depth >= 2 || paths.length === 1) return { runs: [], stalled: [{ shard, files: paths, reason,
|
|
1187
1404
|
...(lastFile ? { lastFile } : {}),
|
|
1188
1405
|
...(reason === 'unattributed' ? { summaryFailures: fails, namedFailures, ...(unattributedDetail ? { detail: unattributedDetail } : {}) } : {}),
|
|
1189
1406
|
}] };
|
|
@@ -1193,14 +1410,19 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1193
1410
|
if (depth === 0 && paths.length > POD_SHARD_FILE_CAP) {
|
|
1194
1411
|
const chunks = Array.from({ length: Math.ceil(paths.length / POD_SHARD_FILE_CAP) }, (_, i) => paths.slice(i * POD_SHARD_FILE_CAP, (i + 1) * POD_SHARD_FILE_CAP));
|
|
1195
1412
|
debug.log('release-loop.gate', 'pod-shard-cap-split', { shard, files: paths.length, chunks: chunks.length, cap: POD_SHARD_FILE_CAP, reason });
|
|
1196
|
-
|
|
1413
|
+
// Preserve the proven cap-chunk Job even with an empty opt-in list. Batch isolation is only for chunks whose
|
|
1414
|
+
// every file is explicitly safe; a regular cap chunk keeps the preexisting one-process Pod verdict.
|
|
1415
|
+
const children = await Promise.all(chunks.map((chunk, i) => runShard(chunk, shard, 2, `${branch}-c${i}`, false, undefined, attemptId, 0,
|
|
1416
|
+
chunk.length > 1 && chunk.every((file) => batchSafe.has(file)))));
|
|
1197
1417
|
return { runs: children.flatMap((child) => child.runs), stalled: children.flatMap((child) => child.stalled) };
|
|
1198
1418
|
}
|
|
1199
1419
|
debug.log('release-loop.gate', 'pod-shard-split', { shard, depth, files: paths, reason });
|
|
1200
1420
|
const middle = Math.ceil(paths.length / 2);
|
|
1201
1421
|
const children = await Promise.all([
|
|
1202
|
-
runShard(paths.slice(0, middle), shard, depth + 1, `${branch}-0`, false, undefined, attemptId
|
|
1203
|
-
|
|
1422
|
+
runShard(paths.slice(0, middle), shard, depth + 1, `${branch}-0`, false, undefined, attemptId, 0,
|
|
1423
|
+
depth + 1 === 2 && middle > 1 && paths.slice(0, middle).every((file) => batchSafe.has(file))),
|
|
1424
|
+
runShard(paths.slice(middle), shard, depth + 1, `${branch}-1`, false, undefined, attemptId, 0,
|
|
1425
|
+
depth + 1 === 2 && paths.length - middle > 1 && paths.slice(middle).every((file) => batchSafe.has(file))),
|
|
1204
1426
|
]);
|
|
1205
1427
|
return { runs: children.flatMap((child) => child.runs), stalled: children.flatMap((child) => child.stalled) };
|
|
1206
1428
|
}
|
|
@@ -1625,7 +1847,15 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1625
1847
|
try { saveBaselineFileCache(ledger, row.commit, [row]); }
|
|
1626
1848
|
catch (error) { debug.log('release.gate', 'baseline-cache-write-failed', { commit: row.commit, file: row.file, error: String(error) }); }
|
|
1627
1849
|
};
|
|
1628
|
-
|
|
1850
|
+
const recheckFiles = [...newFailureFiles].sort();
|
|
1851
|
+
const unmeasuredRecheckFiles = recheckFiles.slice(GATE_HOST_RECHECK_FILE_LIMIT);
|
|
1852
|
+
if (unmeasuredRecheckFiles.length) debug.log('release-loop.gate', 'isolated-recheck-capped',
|
|
1853
|
+
{ limit: GATE_HOST_RECHECK_FILE_LIMIT, total: recheckFiles.length, unmeasured: unmeasuredRecheckFiles });
|
|
1854
|
+
const recheckStartedAt = Date.now();
|
|
1855
|
+
const selectedRechecks = recheckFiles.slice(0, GATE_HOST_RECHECK_FILE_LIMIT);
|
|
1856
|
+
for (const [index, file] of selectedRechecks.entries()) {
|
|
1857
|
+
debug.log('release-loop.gate', 'isolated-recheck-progress',
|
|
1858
|
+
{ index: index + 1, total: selectedRechecks.length, file, elapsedSec: Math.round((Date.now() - recheckStartedAt) / 1000) });
|
|
1629
1859
|
// 0.2.15: the cut re-check of a new-failure file (InsidePage.test.tsx · headless Chrome) hung for good — limit it like the host re-run.
|
|
1630
1860
|
const cutCheck = cutHostFailed.has(file) ? undefined : await runner.command('bun', ['run', 'test:deterministic', asPath(file)], cutTree, GATE_ISOLATED_TIMEOUT_MS);
|
|
1631
1861
|
if (cutCheck?.timedOut) {
|
|
@@ -1716,7 +1946,18 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1716
1946
|
result.preexisting = preexistingIds.length;
|
|
1717
1947
|
result.baselineCache = cacheStats;
|
|
1718
1948
|
debug.log('release.gate', 'baseline-cache', { hits: cacheStats.hits, misses: cacheStats.misses, commit: baseSha });
|
|
1719
|
-
|
|
1949
|
+
if (unmeasuredRecheckFiles.length) {
|
|
1950
|
+
result.unmeasuredRecheckFiles = unmeasuredRecheckFiles;
|
|
1951
|
+
result.outcome = 'error';
|
|
1952
|
+
result.error = `isolated recheck unmeasured: ${unmeasuredRecheckFiles.length} files exceed limit ${GATE_HOST_RECHECK_FILE_LIMIT}: ${unmeasuredRecheckFiles.join(', ')}`;
|
|
1953
|
+
} else result.outcome = result.introduced.length ? 'regression' : 'ok';
|
|
1954
|
+
if (opts.rehearsalTui) {
|
|
1955
|
+
result.rehearsalTui = await executeTuiNodeCheck(opts.commit, repo, runner.localCommand);
|
|
1956
|
+
if (result.rehearsalTui.outcome !== 'ok') {
|
|
1957
|
+
result.outcome = 'error';
|
|
1958
|
+
result.error = result.rehearsalTui.detail;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1720
1961
|
} catch (error) {
|
|
1721
1962
|
result.error = error instanceof Error ? error.message : String(error);
|
|
1722
1963
|
if (error instanceof StalledPodShards) {
|
|
@@ -1758,31 +1999,51 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1758
1999
|
result.error = `baseline persistence: ${String(error)}`;
|
|
1759
2000
|
}
|
|
1760
2001
|
}
|
|
1761
|
-
|
|
2002
|
+
{
|
|
1762
2003
|
const ids = {
|
|
1763
2004
|
introduced: [...result.introduced].sort(),
|
|
1764
2005
|
knownEnv: [...knownEnvIds].sort(),
|
|
1765
2006
|
preexisting: [...preexistingIds].sort(),
|
|
1766
2007
|
loadFlaky: [...(result.loadFlaky ?? [])].sort(),
|
|
2008
|
+
...(result.unmeasuredRecheckFiles?.length ? { unmeasuredRecheckFiles: [...result.unmeasuredRecheckFiles].sort() } : {}),
|
|
1767
2009
|
};
|
|
1768
2010
|
try {
|
|
1769
|
-
const
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
2011
|
+
for (const location of roots) {
|
|
2012
|
+
const path = verdictFile(location, opts.version);
|
|
2013
|
+
if (existsSync(path)) readFileSync(path, 'utf8');
|
|
2014
|
+
}
|
|
2015
|
+
for (const location of roots) {
|
|
2016
|
+
const path = verdictFile(location, opts.version);
|
|
2017
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
2018
|
+
const temp = join(dirname(path), `.gate-verdict-${process.pid}-${randomUUID()}.tmp`);
|
|
2019
|
+
try {
|
|
2020
|
+
writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit, outcome: result.outcome, ...ids }, null, 2) + '\n', { mode: 0o600 });
|
|
2021
|
+
chmodSync(temp, 0o600);
|
|
2022
|
+
renameSync(temp, path);
|
|
2023
|
+
} finally { if (existsSync(temp)) rmSync(temp); }
|
|
2024
|
+
}
|
|
1777
2025
|
} catch (error) {
|
|
1778
2026
|
result.outcome = 'error';
|
|
1779
2027
|
result.error = `verdict persistence: ${String(error)}`;
|
|
2028
|
+
const path = verdictFile(ledger, opts.version);
|
|
2029
|
+
try {
|
|
2030
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
2031
|
+
const temp = join(dirname(path), `.gate-verdict-${process.pid}-${randomUUID()}.tmp`);
|
|
2032
|
+
try {
|
|
2033
|
+
writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit, outcome: result.outcome, ...ids }, null, 2) + '\n', { mode: 0o600 });
|
|
2034
|
+
chmodSync(temp, 0o600);
|
|
2035
|
+
renameSync(temp, path);
|
|
2036
|
+
} finally { if (existsSync(temp)) rmSync(temp); }
|
|
2037
|
+
} catch (persistenceError) {
|
|
2038
|
+
result.error += `; error verdict persistence: ${String(persistenceError)}`;
|
|
2039
|
+
}
|
|
1780
2040
|
}
|
|
1781
|
-
|
|
1782
|
-
version: opts.version, commit: opts.commit,
|
|
2041
|
+
debug.log('release-loop.gate', 'judged', {
|
|
2042
|
+
version: opts.version, commit: opts.commit, outcome: result.outcome,
|
|
1783
2043
|
introduced: result.introduced.length, preexisting: result.preexisting,
|
|
1784
2044
|
knownEnv: result.knownEnv, loadFlaky: ids.loadFlaky.length,
|
|
1785
2045
|
introducedIds: ids.introduced, knownEnvIds: ids.knownEnv, preexistingIds: ids.preexisting, loadFlakyIds: ids.loadFlaky,
|
|
2046
|
+
...(result.outcome === 'error' ? { error: result.error } : {}),
|
|
1786
2047
|
});
|
|
1787
2048
|
}
|
|
1788
2049
|
// GATE-LIVE-OBS-RC-WORDING ⓒ — the shards board says «판정 전» until this lands; then «새 실패 N» only (UX · gate-shards.ts).
|
|
@@ -1843,6 +2104,7 @@ export function parseOptions(args: string[], env: NodeJS.ProcessEnv): GateOption
|
|
|
1843
2104
|
// GATE-HOST-EXECUTOR: a host gate never reads the pod settings (a bad pod value must not block the fallback executor).
|
|
1844
2105
|
const hostExecutor = fromGraph.gateExecutor === 'host';
|
|
1845
2106
|
const opts: GateOptions = {
|
|
2107
|
+
rehearsalTui: fromGraph.rehearsalTui === true,
|
|
1846
2108
|
commit: typeof fromGraph.commit === 'string' ? fromGraph.commit : '',
|
|
1847
2109
|
version: typeof fromGraph.version === 'string' ? fromGraph.version : '',
|
|
1848
2110
|
baselineVersion: typeof fromGraph.previousVersion === 'string' ? fromGraph.previousVersion : undefined,
|
|
@@ -1870,6 +2132,7 @@ export function parseOptions(args: string[], env: NodeJS.ProcessEnv): GateOption
|
|
|
1870
2132
|
if (arg === '--json') continue;
|
|
1871
2133
|
// Applied after the loop and only to a Pod gate — on its own it must not turn a local gate into a Pod one (review r5).
|
|
1872
2134
|
if (arg === '--fresh-shards') { freshShards = true; continue; }
|
|
2135
|
+
if (arg === '--rehearsal-tui') { opts.rehearsalTui = true; continue; }
|
|
1873
2136
|
if (arg === '--executor') {
|
|
1874
2137
|
const value = args[++i];
|
|
1875
2138
|
if (!isGateExecutor(value)) throw new Error(`--executor must be pod or host: ${value ?? ''}`);
|
|
@@ -1920,6 +2183,7 @@ export async function runGateNode(argv: string[], env: NodeJS.ProcessEnv, runner
|
|
|
1920
2183
|
return 0;
|
|
1921
2184
|
}
|
|
1922
2185
|
version = opts.version;
|
|
2186
|
+
// The graph's existing gate-node execution path delegates verdict classification and persistence here.
|
|
1923
2187
|
result = await (runner ? judgeGate(opts, runner) : judgeGate(opts));
|
|
1924
2188
|
} catch (error) {
|
|
1925
2189
|
result = { outcome: 'error', commit: '', introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: Date.now() - start, error: String(error) };
|