elanous 0.2.34 → 0.2.35
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/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → 0368f25d-ad84af92fefee68f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1165.bad13fc9151a7288.js +1 -0
- package/apps/pwa/out/_next/static/chunks/13.02a07436dec15f89.js +32 -0
- package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 1530.0e612369b6fd7ea0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1540.af38731fa7c4a3e0.js +41 -0
- package/apps/pwa/out/_next/static/chunks/1674.2a65fd5668e1cc5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1850.f2b470ba5a471da0.js +24 -0
- package/apps/pwa/out/_next/static/chunks/193.62da94cd0b88323b.js +74 -0
- package/apps/pwa/out/_next/static/chunks/1975.260f6d249fac5f7c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1982-67cd8dfe8682325f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1993-c0007b7ad0c0ef41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1999-bb415351c8a2846c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1c735de4.f993a30bbd3c57c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1dc5a567.9b092bfae3d7099b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 2018.a741297bce759490.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2085.8f950b4bda1cbbc7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2159-6179a961376956b9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216.b5c2a421aa1d28a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2251.49fbe369f74c372c.js +148 -0
- package/apps/pwa/out/_next/static/chunks/2286-2939577360d3dcc0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2625.5d870aa999f33db1.js +34 -0
- package/apps/pwa/out/_next/static/chunks/2668.34d21539e62bf111.js +77 -0
- package/apps/pwa/out/_next/static/chunks/2833-0fe47af99ed13c29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2930.d0edb4f108787ef7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2973.77318e7d85f59477.js +62 -0
- package/apps/pwa/out/_next/static/chunks/3103.0df8da390948bb84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3123.2bee9ba15d320bd2.js +90 -0
- package/apps/pwa/out/_next/static/chunks/3162-6cf652bf7124d8cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 3408.21d1570602f4b6c0.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3577-7340009f7007a795.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 3589.5444a06bcf6e775c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/359-2250789a2d3499e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3618.f514792d6c59d7fd.js +36 -0
- package/apps/pwa/out/_next/static/chunks/3669.343f9119aa276001.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3677-4215f826f6aa68e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3736.c2efad489604cc3b.js +79 -0
- package/apps/pwa/out/_next/static/chunks/3817.f9aeab2bb6675d73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3f7c4ee5.3dde54f01a816613.js +122 -0
- package/apps/pwa/out/_next/static/chunks/4182-0b9b1251c29cc0cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4346.8601952e73bf5803.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6053-d893974de92e6198.js → 4441-875b97f5821ed58a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4582.bd68683c076649e3.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4605-6e623f55aec77422.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4607.5cc27468628eb4bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4627.f07508b3936fd6c0.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 4705-194e64e47ca0fbdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 4718-17d2af636796a330.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/4747-c22262c093e46807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4775-178215aed0daba61.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4815-6ffb8c3c991cc45d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4834-beca8b47ad29a898.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5023-fb4802b6d2492b02.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 5101.e32282718f99ed6f.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5154.a118f3957ed14e36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5210-a2e0015e3d4d5d9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5356.84ac712cc15928bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5401.22352141b6fd336e.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{2987-30cf9c2eb7b8bdd5.js → 5483-dd5d7697f6bdb106.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5637.281e5dec4ea6ecf1.js +94 -0
- package/apps/pwa/out/_next/static/chunks/5662.02eaa029af05ad46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/56d372f2.681ab4ec4c998fae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5760.22456f433c6f42c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7386.5d8e7e42e818dfb6.js → 5852.db1f7449f4f74612.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5891-0f11a7d7362a9072.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5943.264d14a44ca32513.js +1 -0
- package/apps/pwa/out/_next/static/chunks/604-1b3c39df083c02aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6121-5f97072330738caf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6193.07d8ca5af4b09086.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6203-b3fea3a60d69ff14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 6236.e18cced2d5ba6afb.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6286.d638fb5953e2e757.js +8 -0
- package/apps/pwa/out/_next/static/chunks/630.fe5a46428d63b013.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6301.ae0245f507e4395e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6673.fbbe5699f6ea5991.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6777-f6d301efb5de828d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6786.423f24c88de034c7.js +93 -0
- package/apps/pwa/out/_next/static/chunks/6854-cef64a948c5e122d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6866-79aa5b4e47cac6aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6b89c8bd.24df687a820500b3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7037-fe27f001db30d323.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7080.2d826860534fd88e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7118.8731be28c3ebb14b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7196.44241bc1df3e26fe.js +149 -0
- package/apps/pwa/out/_next/static/chunks/7235.c7c4e6cb5c693c2d.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 7385.50a308a477bdfc21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 7644.17e37ba6f1d4226e.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/7706-58bfb1546637f217.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7839.5b91455338c9fd3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7857-31f13ee96f4011aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/81.f74cb60312fe4001.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8219.baa715d1deee80e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8256.e3ac8421a71f82f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8310-444a6a895c402f12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8423.f7dda8aca4fcaae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7193-cf355cca5ba6c5d5.js → 8437-8d5492094b166cfa.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 8444.4c26b379ca2b9596.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/8496.75649af8652c74f4.js +226 -0
- package/apps/pwa/out/_next/static/chunks/8557-e7898769499cd56f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8576.65bb654b524f3614.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8609.558ce2f8f9aea2be.js +64 -0
- package/apps/pwa/out/_next/static/chunks/8614.caec96cfb91f4ae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 8637.47f5b35afcae5e6b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8714.ff0b7ce3ec3e3ae2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8732.367f44a916202353.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9141-7fd1f73a5400bdc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/921.c4267d0d69a65404.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 9214.63a510d39178e997.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9261.3962c3321b047691.js +115 -0
- package/apps/pwa/out/_next/static/chunks/936-26efd1a0efdd44d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 938.66ad1ef0e5abae1c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 9512.5a76207a730e0491.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9627-4b9efe616b27e2e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/967-2aa39b2d04b4c690.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9734.40eb1e558c29ccea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9908.3aa54f7a586a73dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 9952.5daf5f94063a2b3e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9954-ca8d29752bdbb45a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9974-507fa67cb94066dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fa59d6d17daa3389.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-53f68bbe7bd4b774.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-1c500fbb9f4a7a04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-99d72673aa5c307c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d2d5adc1e9484c88.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c607c5aae637f1cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fa8c23596d555c0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-bdab8c5e855c8416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-406b47745b53f269.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-a4276386b7051f50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-8a26bab9ad375f25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-775f48aa1dc7a2d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-1c4dd5f959d0c558.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c48938a8377c9f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c6e7905859425aa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c280f4252452e830.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-cf8c57498f20970a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-ca3a17caf409fc83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/{page-d7bff0f0905a662c.js → page-26e6c18a1a750cf6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-3abc872cc6aeee39.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7481b7b2174fe3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1ae7ef8077680337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-47c5d4db587266bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-415f1e243c7ccb13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-73f380f17b76f95c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-2991073ad66ee2d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1f5a60f70cb4dd0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fbad60d1e358fb2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-bac7dee94e5eae4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-398047d6949e8ca5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-2d33a2231540ca89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5bf1e6bf70bcb96c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-ba59c19376a0917d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-111f187139add30f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-acaae197d5be5779.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0df20b0f546a0d7d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-ce9e00f7fb45506a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-27e1202d24b8fe35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-bda78c50a78363e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-da592691293d9c9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f832994317a2e9f0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-df3445b207ceceab.js → page-dc0a532f5b9196ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-cfccbbeae0473404.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-527e2073af84c81b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bac86e9112671357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6d59dff410e9d76a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-53a61f8be09f02d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-db8f559e763c17f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c02aa4cc66455093.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → b2f6ba4d.fb56fdbbf798df33.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/b6705a4f-b9a9047de9eecfd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → cbe38a15.5a032598e39970c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{abb4b98b.163e0f56e84ae35d.js → d06f9160.a3d9062f95de8ad7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → da5176c6.6773b6c5994e1d99.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-50e6acebc630849b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-7a1ae342d5ed75e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-7ad7d505ba1f92b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-02edba75232cb235.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d6ebae3e8eee4a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-e986adaa429163e8.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/bin/elanous.mjs +3 -2
- package/catalog/providers/opengateway.yaml +25 -0
- package/docs/goal-context/01-goal-authoring-checks.md +8 -0
- package/docs/goal-context/03-verification-menu.md +24 -0
- package/docs/goal-context/04-mock-scenarios.md +100 -0
- package/docs/goal-context/README.md +4 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/default-loop.yaml +57 -3
- package/graphs/document-loop.yaml +51 -3
- package/graphs/implement-loop.yaml +53 -4
- package/graphs/journey/ta-journey.yaml +11 -1
- package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
- package/graphs/journey/units/author-dialogue/observe.ts +96 -0
- package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
- package/graphs/operate-loop.yaml +51 -3
- package/graphs/research-loop.yaml +137 -3
- package/graphs/test-diet/test-diet.yaml +3 -0
- package/package.json +1 -1
- package/scripts/coord-role-pack.ts +19 -6
- package/scripts/hq/standby-snapshot.ts +17 -12
- package/scripts/release-loop/docs-land-node.ts +21 -5
- package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
- package/scripts/release-loop/gate-node.ts +181 -22
- package/scripts/release-loop/gate-partial.ts +65 -11
- package/scripts/release-loop/gate-radius-live.ts +177 -0
- package/scripts/release-loop/gate-radius-shadow.ts +1 -1
- package/scripts/release-loop/node-verdict.ts +12 -1
- package/scripts/release-loop/npm-publish-node.ts +66 -12
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
- package/scripts/release-loop/pwa-remote.ts +166 -0
- package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
- package/scripts/release-loop/resume-release.ts +41 -4
- package/scripts/release-loop/unattended-release.ts +2 -0
- package/scripts/test-diet/lib.ts +6 -1
- package/scripts/test-diet/node.ts +194 -13
- package/scripts/ux-sim.ts +39 -0
- package/src/agent/self-ambient-cache.ts +8 -0
- package/src/agent-substrate/acp-reviewer.ts +39 -4
- package/src/agent-substrate/pr-reviewer.ts +17 -0
- package/src/agent-substrate/self-review-cli.ts +62 -13
- package/src/autopilot/pr-manager.ts +215 -36
- package/src/budget/run-usage-rollup.ts +1 -0
- package/src/chat/index.ts +0 -2
- package/src/chat/pickers/modal-runtime.ts +10 -27
- package/src/cli/agent-cli.ts +13 -2
- package/src/cli/doctor-cli.ts +4 -1
- package/src/cli/light-entry-route.ts +46 -6
- package/src/cli/pod-cli.ts +77 -3
- package/src/cli/pr-cli.ts +5 -2
- package/src/cli/pr-land-pod-shadow-job.ts +3 -0
- package/src/cli/release-checklist-read-cli.ts +79 -0
- package/src/cli/release-cli.ts +72 -102
- package/src/cli/remote-resolve.ts +1 -1
- package/src/cli/root-tui-entry.ts +48 -0
- package/src/cli/sim-cli.ts +22 -0
- package/src/cli/tasks-cli.ts +540 -31
- package/src/cli/usage-cli.ts +13 -11
- package/src/clipboard/history.ts +179 -13
- package/src/config.ts +8 -1
- package/src/dashboard/chat/acp-chat.ts +8 -0
- package/src/dashboard/index.ts +78 -10
- package/src/dashboard/render/theme-resolver.ts +33 -4
- package/src/domains/schedule-registry.ts +16 -2
- package/src/git-fs/idle-refresh.ts +76 -0
- package/src/git-fs/index.ts +18 -7
- package/src/git-fs/worktree.ts +42 -4
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/runner.ts +153 -10
- package/src/grok/credential.ts +10 -3
- package/src/harness/harness-cli-command.ts +112 -28
- package/src/harness/harness-incidents.ts +33 -0
- package/src/harness/launch-utterance-ledger.ts +208 -0
- package/src/impl-discipline/detector.ts +16 -4
- package/src/impl-discipline/system-prompt.ts +11 -0
- package/src/impl-discipline/types.ts +2 -2
- package/src/index.ts +496 -143
- package/src/intake-plane/already-built-hint.ts +4 -2
- package/src/intake-plane/requirement-funnel.ts +29 -1
- package/src/light-cli.ts +27 -11
- package/src/llm/opengateway-models.ts +11 -0
- package/src/llm/provider-credentials.ts +14 -0
- package/src/llm/provider-detect.ts +8 -1
- package/src/llm/runtime-model-family.ts +2 -1
- package/src/llm.ts +213 -56
- package/src/model-tier/llm-tier-map.ts +15 -1
- package/src/native-tool-catalog.ts +15 -1
- package/src/nexus/api/loop-resources.ts +13 -1
- package/src/oauth/codex.ts +7 -0
- package/src/ops/overview-collect.ts +18 -3
- package/src/ops/overview.ts +20 -7
- package/src/pr-tool/census.ts +261 -27
- package/src/pty-shell/pty-manifest.ts +7 -0
- package/src/release-loop/checklist.ts +24 -0
- package/src/release-loop/landed-but-yellow.ts +129 -5
- package/src/release-loop/light-rc.ts +1 -0
- package/src/release-loop/rehearsal.ts +2 -2
- package/src/repl/index.ts +174 -17
- package/src/repl/ops-msg-bridge.ts +32 -0
- package/src/self-dev/ask-launch-flow.ts +44 -5
- package/src/self-dev/cli-help-text.ts +17 -0
- package/src/self-dev/dev-cli.ts +11 -9
- package/src/self-dev/draft-residue.ts +37 -1
- package/src/self-dev/draft-sweep.ts +137 -11
- package/src/self-dev/draft-triage-rules.ts +107 -0
- package/src/self-dev/fleet-reduce.ts +3 -2
- package/src/self-dev/graph-front-nodes.ts +112 -0
- package/src/self-dev/graph-journey-nodes.ts +1 -0
- package/src/self-dev/harness-run-cli.ts +3 -15
- package/src/self-dev/orchestrate-cli-text.ts +10 -0
- package/src/self-dev/review-provider-fallback.ts +35 -1
- package/src/self-dev/self-orchestrate-runtime.ts +1 -11
- package/src/self-dev/shard-aggregate.ts +42 -5
- package/src/self-dev/shard-run.ts +8 -1
- package/src/self-implement/blocked-draft-policy.ts +20 -0
- package/src/self-implement/classify-shadow.ts +3 -7
- package/src/self-implement/doctor-visit.ts +18 -1
- package/src/self-implement/gate-baseline.ts +56 -17
- package/src/self-implement/gate-cli.ts +1 -0
- package/src/self-implement/gate-remote.ts +31 -20
- package/src/self-implement/goal-author-decompose.ts +275 -47
- package/src/self-implement/goal-author.ts +250 -0
- package/src/self-implement/goal-elaborate.ts +295 -0
- package/src/self-implement/goal-refine.ts +270 -0
- package/src/self-implement/graph-overlay-yaml.ts +14 -3
- package/src/self-implement/orchestrator.ts +152 -45
- package/src/self-implement/rework-budget-judgment.ts +5 -8
- package/src/self-implement/run-stop.ts +10 -1
- package/src/self-implement/running-runs.ts +29 -1
- package/src/self-implement/scope-adjacency.ts +113 -0
- package/src/self-implement/seams.ts +127 -24
- package/src/self-implement/stop-autoheal.ts +87 -1
- package/src/session-runtime/index.ts +1 -1
- package/src/setup/llm-env-detect.ts +5 -0
- package/src/skills/tools/agent.ts +140 -14
- package/src/skills/tools/msg-ask.ts +100 -0
- package/src/skills/tools/ops-ledger.ts +2 -1
- package/src/steward/hold-hygiene.ts +24 -6
- package/src/steward/triage-budget.ts +194 -0
- package/src/steward/triage.ts +20 -3
- package/src/task-agent/actions.ts +69 -1
- package/src/task-agent/green-sweep.ts +4 -0
- package/src/task-agent/live-moves.ts +160 -4
- package/src/task-agent/parent-host.ts +123 -3
- package/src/task-agent/shadow.ts +7 -1
- package/src/task-agent/task-hand.ts +54 -41
- package/src/task-agent/tier-split.ts +127 -0
- package/src/task-agent/work-order-build.ts +2 -0
- package/src/task-agent/work-order.ts +3 -2
- package/src/task-orchestrator/generator-prompt.ts +60 -11
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +33 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-command-job.ts +45 -7
- package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
- package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
- package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +8 -2
- package/src/task-orchestrator/surfaces/pod-provenance.ts +76 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
- package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +3 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +37 -5
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +368 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +23 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
- package/src/tui/README.md +2 -0
- package/src/tui/chat/background-job-status.ts +54 -0
- package/src/tui/chat/log-view.ts +80 -0
- package/src/tui/entry.ts +406 -0
- package/src/tui/input/composer.ts +144 -0
- package/src/tui/seat-mail-boot.ts +59 -0
- package/src/tui/slash/compact.ts +100 -0
- package/src/tui/slash/new-session.ts +35 -0
- package/src/tui-client/local-chat-turn.ts +239 -0
- package/src/tui-client/local-harness-command.ts +63 -0
- package/src/tui-client/local-provider-command.ts +184 -0
- package/src/user-config.ts +4 -2
- package/src/ux-sim/event-monkey.ts +378 -0
- package/src/ux-sim/fake-bin.ts +42 -7
- package/src/ux-sim/fault-nextmove-dispatch.ts +266 -0
- package/src/ux-sim/fault-pod-codex-503.ts +211 -0
- package/src/ux-sim/fault-scope-escape-lift.ts +189 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
- package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
- package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
- package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
- package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +0 -34
- package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3498.cf2a15a8a9e5b926.js +0 -226
- package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +0 -32
- package/apps/pwa/out/_next/static/chunks/3837.722e053fb9f321ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
- package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
- package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
- package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
- package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5446.edf141cff9ef647d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
- package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
- package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +0 -41
- package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
- package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
- package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
- package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
- package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ffdc3a04.b9c23c1b28dd4a96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
- /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → T1mBQqmkwKDLGtyisDCOd}/_ssgManifest.js +0 -0
|
@@ -4,7 +4,7 @@ import { appendFileSync, chmodSync, copyFileSync, existsSync, mkdirSync, mkdtemp
|
|
|
4
4
|
import { hostname, tmpdir } from 'node:os';
|
|
5
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
6
6
|
import { dirname, join, resolve } from 'node:path';
|
|
7
|
-
import { debug } from '../../src/debug/log.js';
|
|
7
|
+
import { debug, redactSecretText } from '../../src/debug/log.js';
|
|
8
8
|
import { registerStandaloneLogSink } from '../../src/domains/standalone-log-sink.js';
|
|
9
9
|
import { landingFreezeMessage, readLandingFreeze } from '../../src/release-loop/landing-freeze.js';
|
|
10
10
|
import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
|
|
@@ -13,8 +13,12 @@ import { diffFailures, junitFailures, parseFailures, parseTimedOutFailures } fro
|
|
|
13
13
|
import { loadEnvKnownFailures, splitKnownEnv } from './env-known-failures';
|
|
14
14
|
import { loadGateBatchSafe } from './gate-batch-safe';
|
|
15
15
|
import { baselineFromCutLogs } from './baseline-from-logs';
|
|
16
|
-
import { mergePartialFailures,
|
|
16
|
+
import { mergePartialFailures, readPartialPlanResult, testFileOfId, verifyDocsOnlyCarry } from './gate-partial';
|
|
17
17
|
import { planGateRadiusShadow, shadowActual, writeGateRadiusShadow, type GateRadiusShadowPlan } from './gate-radius-shadow';
|
|
18
|
+
import { planHardRehearsalRadius, partialGateImagesMatch, preflightGateImageDigest } from './gate-radius-live';
|
|
19
|
+
import { actualGatePodImageDigest, gateBaselineReceipt, gateEnvFingerprint, gateGraphPins, gateSourcePins,
|
|
20
|
+
POD_SWEEP_INTEGRATION_ONLY } from './gate-baseline-receipt';
|
|
21
|
+
export { POD_SWEEP_INTEGRATION_ONLY } from './gate-baseline-receipt';
|
|
18
22
|
import { logPlanWalltime, planDurations, readFileMemory } from './shard-plan';
|
|
19
23
|
import { defaultGateHostMirrorReaders, resolveGateHostMirror, type GateHostMirror, type GateHostMirrorReaders } from './gate-host-mirror';
|
|
20
24
|
import { isGateSpawnLaneFile, planGateSpawnSeparatedShards } from './spawn-lane';
|
|
@@ -67,6 +71,8 @@ export function warmCommandMatchesRequest(command: WarmWorkerCommand, request: O
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
interface CommandResult { rc: number; output: string; passedIds?: string[]; stalledEnv?: Array<{ file: string; reason: 'no-output' }>; timedOut?: boolean;
|
|
74
|
+
/** Identity and complete selected inventory of this Pod sweep; only the producer may issue it. */
|
|
75
|
+
podSweep?: { id: string; shards: number; files: string[] };
|
|
70
76
|
/** Complete, source-bound one-file Job result for shadow comparison; absent means unmeasured. */
|
|
71
77
|
warmReference?: WarmWorkerFileResult | null;
|
|
72
78
|
warmAttemptId?: string;
|
|
@@ -75,6 +81,13 @@ interface CommandResult { rc: number; output: string; passedIds?: string[]; stal
|
|
|
75
81
|
abortedShards?: number;
|
|
76
82
|
/** Each contributing Pod leaf already passed failuresOf; repeated printed ids cannot add new failures. */
|
|
77
83
|
validatedShards?: boolean }
|
|
84
|
+
function redactedGateLogTail(input: string): string {
|
|
85
|
+
// Redact before trimming: a truncated token might no longer match the redaction rule.
|
|
86
|
+
const bytes = Buffer.from(redactSecretText(input), 'utf8');
|
|
87
|
+
let start = Math.max(0, bytes.length - 16_384);
|
|
88
|
+
while (start < bytes.length && (bytes[start]! & 0xc0) === 0x80) start++;
|
|
89
|
+
return bytes.subarray(start).toString('utf8');
|
|
90
|
+
}
|
|
78
91
|
export interface GateRunner {
|
|
79
92
|
command(cmd: string, args: string[], cwd: string, limitMs?: number): Promise<CommandResult>;
|
|
80
93
|
localCommand(cmd: string, args: string[], cwd: string, limitMs?: number): Promise<CommandResult>;
|
|
@@ -93,6 +106,10 @@ export interface GateRunner {
|
|
|
93
106
|
}
|
|
94
107
|
export interface GateOptions {
|
|
95
108
|
commit: string;
|
|
109
|
+
/** The graph run that launched this gate; direct hard rehearsal instead pins source bytes explicitly. */
|
|
110
|
+
graphRunId?: string;
|
|
111
|
+
/** Only a direct hard rehearsal may pin graph bytes from its measured Git commit. */
|
|
112
|
+
rehearsalBaseline?: boolean;
|
|
96
113
|
forceFreeze?: boolean;
|
|
97
114
|
version: string;
|
|
98
115
|
baselineVersion?: string;
|
|
@@ -154,6 +171,9 @@ export interface GateOptions {
|
|
|
154
171
|
liveLog?: (job: { name: string; context?: string }) => string | null;
|
|
155
172
|
/** false = the stop did not take; the watch asks again every poll until it does (void = taken). */
|
|
156
173
|
stopJob?: (job: { name: string; context?: string }) => boolean | void;
|
|
174
|
+
/** Failure-only Pod status and log reader; injected tests never call the live cluster. */
|
|
175
|
+
failureEvidence?: (job: { name: string; context?: string }) => { podName?: string; termination?: { reason?: string; message?: string; exitCode?: number; finishedAt?: string }; logTail?: string; error?: string };
|
|
176
|
+
failureKubectl?: typeof defaultKubectl;
|
|
157
177
|
/** How often the stall watch reads the live log (ms); omitted = {@link GATE_POD_STALL_POLL_MS}. */
|
|
158
178
|
stallPollMs?: number;
|
|
159
179
|
/** GATE-POD-STALL-FAILFAST ① — seconds a shard may go without its part logs growing once test output began, before
|
|
@@ -218,6 +238,10 @@ export interface GateResult {
|
|
|
218
238
|
/** GATE-POD-STALL-FAILFAST — the shard (and its one fresh retry) printed no test output within the stall window: unmeasured. */
|
|
219
239
|
stall?: { seconds: number; sinceCheckoutMs: number } }>;
|
|
220
240
|
partialSummary?: { pass: number; fail: number; errors: number; ran: number; files: number };
|
|
241
|
+
/** Number of complete shards retained when an incomplete sweep is resumed. */
|
|
242
|
+
preservedShardCount?: number;
|
|
243
|
+
/** Completed shard measurements retained when another shard stalled, so same-commit resume can reuse them safely. */
|
|
244
|
+
partialFailures?: SweepFailures;
|
|
221
245
|
/** GATE-PARTIAL — this verdict re-ran only these files and carried the prior gate's results for the rest. */
|
|
222
246
|
partial?: { priorCommit: string; files: number };
|
|
223
247
|
/** GATE-INTRO-RECHECK — new failures that were only the «timed out» shape and passed one isolated re-run with a
|
|
@@ -971,7 +995,7 @@ export function readShardArtifacts(dir: string, parts: readonly (readonly string
|
|
|
971
995
|
export const gateUnfinishedHint = (relativePath: string, bytes: number) => `[gate] unfinished: ${relativePath} · ${bytes}B (진행 중 part 출력은 그 파일)`;
|
|
972
996
|
|
|
973
997
|
// review-model-ab: Pod 에서 출력 없이 멈춤 2/2(10-04 0.2.11 · 로컬 단독 4/0 · 1.7s) — GATE-STALL 수리 전까지 Pod 밖.
|
|
974
|
-
|
|
998
|
+
// The shared exclusion list lives in gate-baseline-receipt so radius verification uses the producer's rule.
|
|
975
999
|
/** Nightly-only whole-repository cases; gate runs the fixture cases in these same files. */
|
|
976
1000
|
export const GATE_NIGHTLY_AUDITS: readonly string[] = [
|
|
977
1001
|
// Replaces F12's real-repo bucket B apps/pwa scope check and its whole-repo export partition check.
|
|
@@ -1132,7 +1156,8 @@ export function readIsolatedRun(run: CommandResult, label: string, file: string)
|
|
|
1132
1156
|
}
|
|
1133
1157
|
|
|
1134
1158
|
class StalledPodShards extends Error {
|
|
1135
|
-
constructor(readonly stalledShards: NonNullable<GateResult['stalledShards']>, readonly partialSummary: NonNullable<GateResult['partialSummary']>,
|
|
1159
|
+
constructor(readonly stalledShards: NonNullable<GateResult['stalledShards']>, readonly partialSummary: NonNullable<GateResult['partialSummary']>,
|
|
1160
|
+
readonly partialFailures: SweepFailures, readonly preservedShardCount: number, readonly abortedShards = 0) {
|
|
1136
1161
|
const unmeasured = stalledShards.filter((item) => item.stall);
|
|
1137
1162
|
const exitCode = stalledShards.filter((item) => item.reason === 'exit-code');
|
|
1138
1163
|
super(`pod sweep incomplete: stalled shards ${stalledShards.map(({ shard }) => shard).join(', ')}`
|
|
@@ -1142,6 +1167,23 @@ class StalledPodShards extends Error {
|
|
|
1142
1167
|
}
|
|
1143
1168
|
}
|
|
1144
1169
|
|
|
1170
|
+
/** Read completed shard failures without letting one malformed shard hide the stalled-shard verdict. */
|
|
1171
|
+
export function partialFailuresOf(runs: readonly (CommandResult & { files: number })[]): SweepFailures {
|
|
1172
|
+
return runs.reduce<SweepFailures>((sum, run) => {
|
|
1173
|
+
try {
|
|
1174
|
+
const parsed = failuresOf({ rc: run.rc, output: run.output, validatedShards: true }, `pod partial shard ${run.files}`);
|
|
1175
|
+
sum.failures.push(...parsed.failures);
|
|
1176
|
+
sum.errors.push(...parsed.errors);
|
|
1177
|
+
} catch (error) {
|
|
1178
|
+
debug.log('release-loop.gate', 'pod-partial-failures-unreadable', {
|
|
1179
|
+
files: run.files,
|
|
1180
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
1181
|
+
}, { level: 'warn' });
|
|
1182
|
+
}
|
|
1183
|
+
return sum;
|
|
1184
|
+
}, { failures: [], errors: [] });
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1145
1187
|
class WarmRecheckIncomplete extends Error {
|
|
1146
1188
|
constructor(message: string, readonly file: string, readonly shadow: WarmShadowObservation) { super(message); }
|
|
1147
1189
|
}
|
|
@@ -1292,6 +1334,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1292
1334
|
}
|
|
1293
1335
|
: localCommand);
|
|
1294
1336
|
const podSweep = async (tree: string, logDir: string | undefined, pod: NonNullable<GateOptions['pod']>, only?: readonly string[]): Promise<CommandResult> => {
|
|
1337
|
+
const sweepId = randomUUID();
|
|
1295
1338
|
const shardCount = pod.shards ?? 24;
|
|
1296
1339
|
const isolationConcurrency = pod.isolationConcurrency ?? 4;
|
|
1297
1340
|
// GATE-TIMEOUT-HEAL ①: the configured value is the floor; each shard's own deadline is shardDeadlineSeconds(planned).
|
|
@@ -1434,6 +1477,33 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1434
1477
|
}
|
|
1435
1478
|
return '';
|
|
1436
1479
|
};
|
|
1480
|
+
const failureEvidence = pod.failureEvidence ?? ((job: { name: string; context?: string }) => {
|
|
1481
|
+
if (!job.context) return { error: '수거 실패 · Job 배치 context 없음' };
|
|
1482
|
+
const prefix = ['--context', job.context, '--request-timeout=5s', '-n', 'elanous-test'];
|
|
1483
|
+
const errors: string[] = [];
|
|
1484
|
+
let termination: { reason?: string; message?: string; exitCode?: number; finishedAt?: string } | undefined;
|
|
1485
|
+
let podName: string | undefined;
|
|
1486
|
+
let latestEndedAt = -Infinity;
|
|
1487
|
+
const status = (pod.failureKubectl ?? defaultKubectl)([...prefix, 'get', 'pods', '-l', `job-name=${job.name}`, '-o', 'json']);
|
|
1488
|
+
if (status.status !== 0) errors.push(`Pod 상태: ${status.stderr.trim() || `kubectl rc=${status.status}`}`);
|
|
1489
|
+
else try {
|
|
1490
|
+
const pods = JSON.parse(status.stdout) as { items?: Array<{ metadata?: { name?: string; creationTimestamp?: string }; status?: { containerStatuses?: Array<{ name?: string; state?: { terminated?: typeof termination } }> } }> };
|
|
1491
|
+
for (const item of pods.items ?? []) {
|
|
1492
|
+
const child = item.status?.containerStatuses?.find((container) => container.name === 'child');
|
|
1493
|
+
const ended = child?.state?.terminated;
|
|
1494
|
+
if (!ended || !item.metadata?.name) continue;
|
|
1495
|
+
const endedAt = Date.parse(ended.finishedAt ?? item.metadata.creationTimestamp ?? '');
|
|
1496
|
+
const rank = Number.isFinite(endedAt) ? endedAt : -Infinity;
|
|
1497
|
+
if (!termination || rank > latestEndedAt) { podName = item.metadata.name; termination = ended; latestEndedAt = rank; }
|
|
1498
|
+
}
|
|
1499
|
+
if (!termination) errors.push('Pod 상태: child 종료 사유 없음');
|
|
1500
|
+
} catch (error) { errors.push(`Pod 상태 JSON: ${String(error)}`); }
|
|
1501
|
+
const logs = podName ? (pod.failureKubectl ?? defaultKubectl)([...prefix, 'logs', `pod/${podName}`, '-c', 'child', '--tail=100']) : undefined;
|
|
1502
|
+
if (!logs) errors.push('로그: 종료된 Pod 이름 없음');
|
|
1503
|
+
else if (logs.status !== 0) errors.push(`로그: ${logs.stderr.trim() || `kubectl rc=${logs.status}`}`);
|
|
1504
|
+
return { ...(podName ? { podName } : {}), ...(termination ? { termination } : {}), ...(logs?.status === 0 ? { logTail: logs.stdout } : {}),
|
|
1505
|
+
...(errors.length ? { error: `수거 실패 · ${errors.join(' · ')}` } : {}) };
|
|
1506
|
+
});
|
|
1437
1507
|
type ShardRun = { output: string; rc: number; pass: number; fail: number; errors: number; ran: number; files: number; passedIds: string[] };
|
|
1438
1508
|
type ShardReason = NonNullable<GateResult['stalledShards']>[number]['reason'];
|
|
1439
1509
|
// 깊이 끝 OOM 조각은 «조각 전체»를 파일 하나씩 격리한다 — 상한 40 이면 나머지가 못 잰 채 남았다(09-30 ① 7번 조각 110 파일).
|
|
@@ -1513,6 +1583,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1513
1583
|
const stamp = (phase: string) => { phaseTimes[phase] = new Date().toISOString(); };
|
|
1514
1584
|
let podStages: Record<string, number> | undefined;
|
|
1515
1585
|
let podLifecycle: Record<string, string> | undefined;
|
|
1586
|
+
let imageDigest: string | null = null;
|
|
1516
1587
|
let podJobName: string | undefined;
|
|
1517
1588
|
let batchArtifactsComplete = true;
|
|
1518
1589
|
let junit: string | undefined;
|
|
@@ -1522,6 +1593,13 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1522
1593
|
let lastFile: string | undefined;
|
|
1523
1594
|
let jobFailed = false;
|
|
1524
1595
|
let jobError = '';
|
|
1596
|
+
let failureCapture: ReturnType<NonNullable<NonNullable<GateOptions['pod']>['failureEvidence']>> | undefined;
|
|
1597
|
+
let jobNameForCapture: string | undefined;
|
|
1598
|
+
let jobContextForCapture: string | undefined;
|
|
1599
|
+
const captureFailure = () => {
|
|
1600
|
+
try { failureCapture = failureEvidence({ name: jobNameForCapture ?? 'unplaced', context: jobContextForCapture }); }
|
|
1601
|
+
catch (error) { failureCapture = { error: `수거 실패 · ${String(error)}` }; }
|
|
1602
|
+
};
|
|
1525
1603
|
/** GATE-MULTI-HOST — the member this shard's Job was placed on (recorded in the shard json / log / board). */
|
|
1526
1604
|
let placedOn: string | undefined;
|
|
1527
1605
|
let timedOut = false;
|
|
@@ -1572,6 +1650,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1572
1650
|
// The admission wait is not the shard's run time: deadline/timeout judgment and the measured duration start here.
|
|
1573
1651
|
start = Date.now();
|
|
1574
1652
|
const jobName = `gate-${randomUUID()}`;
|
|
1653
|
+
jobNameForCapture = jobName;
|
|
1575
1654
|
// The member's context is known once the Job is placed; the live log is read (and the Job stopped) there.
|
|
1576
1655
|
let jobContext: string | undefined;
|
|
1577
1656
|
const liveJob = () => ({ name: jobName, ...(jobContext ? { context: jobContext } : {}) });
|
|
@@ -1593,8 +1672,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1593
1672
|
} : {}) }) : undefined;
|
|
1594
1673
|
const placed = admitted.release;
|
|
1595
1674
|
const job = await podCommand({
|
|
1675
|
+
provenanceGate: true,
|
|
1676
|
+
provenance: { actorKind: process.env.ELANOUS_SEAT ? 'seat' : 'loop', actor: process.env.ELANOUS_SEAT || 'release-loop',
|
|
1677
|
+
character: 'gate-shard-runner', launchHost: hostname(), entrance: process.env.ELANOUS_RELEASE_ENTRANCE?.trim() || 'release-run',
|
|
1678
|
+
kind: 'gate-shard', run: process.env.ELANOUS_RUN_ID || sweepId, phase: 'release-gate', requestedAt: new Date().toISOString(),
|
|
1679
|
+
graphNode: 'gate', version: pod.shardsFile?.version, commit, shard: `${shard + 1}-of-${shards.length}`,
|
|
1680
|
+
reason: `release gate shard ${shard + 1}/${shards.length}`, pool: pod.pool, cpuReq: cpu.request,
|
|
1681
|
+
memReq: memoryLimit ?? POD_ISOLATION_MEMORY_LIMIT, warmReused: false },
|
|
1596
1682
|
pool: pod.pool, poolScheduler: trackedPool(shard, depth > 0 || branch !== '', (member) => {
|
|
1597
|
-
stamp('poolPlaced'); jobContext = member.context; placedOn = member.context; placed();
|
|
1683
|
+
stamp('poolPlaced'); jobContext = member.context; jobContextForCapture = member.context; placedOn = member.context; placed();
|
|
1598
1684
|
if (branch === '-tail') tailPlacedHost = member.context;
|
|
1599
1685
|
}, skipMembers), clone: true, source: { kind: 'commit', sha: commit }, deadlineSeconds: shardDeadline,
|
|
1600
1686
|
...gateHostMirror(pod),
|
|
@@ -1609,13 +1695,20 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1609
1695
|
}).finally(() => watch?.stop());
|
|
1610
1696
|
stamp('jobReturned');
|
|
1611
1697
|
podJobName = job.job;
|
|
1698
|
+
// poolOverride is the injected scheduler used by isolated tests; it has no authenticated kubectl
|
|
1699
|
+
// context. Those sweeps intentionally cannot mint a valid baseline receipt (missing observed digest).
|
|
1700
|
+
// Production pool sweeps always use this Kubernetes lookup; lookup failure is receipt-invalid only.
|
|
1612
1701
|
if (!poolOverride && placedOn) {
|
|
1613
1702
|
try {
|
|
1614
1703
|
const got = defaultKubectl(['--context', placedOn, '-n', 'elanous-test', 'get', 'pods', '-l', `job-name=${job.job}`, '-o', 'json']);
|
|
1615
|
-
if (got.status === 0)
|
|
1704
|
+
if (got.status === 0) {
|
|
1705
|
+
podLifecycle = readGatePodLifecycle(got.stdout);
|
|
1706
|
+
imageDigest = actualGatePodImageDigest(got.stdout);
|
|
1707
|
+
}
|
|
1616
1708
|
} catch { /* timings never change the verdict */ }
|
|
1617
1709
|
}
|
|
1618
1710
|
jobExitCode = job.exitCode;
|
|
1711
|
+
if (job.exitCode !== 0) captureFailure();
|
|
1619
1712
|
batchArtifactDir = job.artifactsDir;
|
|
1620
1713
|
const read = readShardArtifacts(job.artifactsDir, parts);
|
|
1621
1714
|
batchArtifactsComplete = !batchIsolation || parts.every((_, index) =>
|
|
@@ -1649,6 +1742,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1649
1742
|
} catch (error) {
|
|
1650
1743
|
jobFailed = true;
|
|
1651
1744
|
jobError = error instanceof Error ? error.message : String(error);
|
|
1745
|
+
if (!failureCapture) captureFailure();
|
|
1652
1746
|
}
|
|
1653
1747
|
// A launch that failed before placement still gives its admission back (release is idempotent).
|
|
1654
1748
|
admitted?.release();
|
|
@@ -1683,9 +1777,20 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1683
1777
|
if (unfinishedLog !== undefined) writeFileSync(unfinishedDestination, unfinishedLog, { mode: 0o600 });
|
|
1684
1778
|
else rmSync(unfinishedDestination, { force: true });
|
|
1685
1779
|
writeFileSync(join(logDir, `pod-${shard}${branch}.json`), JSON.stringify({ durationMs, rc: rc ?? null,
|
|
1686
|
-
...(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 } : {}),
|
|
1780
|
+
...(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, sweepId, commit, runKey, attemptId, ...(parentAttempt ? { parentAttempt } : {}), jobExitCode: jobExitCode ?? null, jobFailed, ...(placedOn ? { host: placedOn } : {}),
|
|
1687
1781
|
...(Object.keys(phaseTimes).length ? { phaseTimes } : {}), ...(podStages ? { podStages } : {}),
|
|
1688
1782
|
...(podLifecycle && Object.keys(podLifecycle).length ? { podLifecycle } : {}),
|
|
1783
|
+
...(failureCapture ? { failureCapture: {
|
|
1784
|
+
...(failureCapture.podName ? { podName: failureCapture.podName } : {}),
|
|
1785
|
+
...(failureCapture.termination ? { termination: {
|
|
1786
|
+
...failureCapture.termination,
|
|
1787
|
+
...(failureCapture.termination.reason ? { reason: redactSecretText(failureCapture.termination.reason) } : {}),
|
|
1788
|
+
...(failureCapture.termination.message ? { message: redactSecretText(failureCapture.termination.message) } : {}),
|
|
1789
|
+
} } : {}),
|
|
1790
|
+
...(failureCapture.logTail !== undefined ? { logTail: redactedGateLogTail(failureCapture.logTail) } : {}),
|
|
1791
|
+
...(failureCapture.error ? { error: redactSecretText(failureCapture.error) } : {}),
|
|
1792
|
+
} } : {}),
|
|
1793
|
+
...(imageDigest ? { imageDigest } : {}),
|
|
1689
1794
|
...(fileSeconds !== undefined ? { fileSeconds, testSeconds } : {}), ...(testWallSeconds !== undefined ? { testWallSeconds } : {}),
|
|
1690
1795
|
...(podOverheadSeconds !== undefined ? { podOverheadSeconds } : {}),
|
|
1691
1796
|
...(unfinishedLogBytes !== undefined ? { unfinishedLogBytes } : {}),
|
|
@@ -1963,10 +2068,15 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1963
2068
|
stallSeconds, measuredFiles: total.files }, { level: 'warn' });
|
|
1964
2069
|
// An unmeasured (stalled) shard is never handed to the host re-run as an environment stall: the gate fails now.
|
|
1965
2070
|
if (abortedShards) debug.log('release-loop.gate', 'pod-sweep-aborted', { shards: abortedShards, midRunStallSeconds }, { level: 'warn' });
|
|
1966
|
-
if (stalledShards.some((item) => item.reason !== 'no-output' || item.files.length !== 1 || item.stall))
|
|
2071
|
+
if (stalledShards.some((item) => item.reason !== 'no-output' || item.files.length !== 1 || item.stall)) {
|
|
2072
|
+
const measuredFailures = partialFailuresOf(measured);
|
|
2073
|
+
throw new StalledPodShards(stalledShards, total, measuredFailures,
|
|
2074
|
+
results.filter((item) => item.stalled.length === 0).length, abortedShards);
|
|
2075
|
+
}
|
|
1967
2076
|
if (total.ran === 0 && total.errors === 0 && !stalledShards.length) throw new Error('sweep incomplete: no tests ran');
|
|
1968
2077
|
const outputs = measured.map((run) => run.output.replace(/(?:^|\n)\s*\d+ (?:pass|fail|errors?)\s*(?=\n|$)/g, '\n').replace(/Ran \d+ tests? across \d+ files?\.?/g, ''));
|
|
1969
2078
|
return { rc: total.fail + total.errors ? 1 : 0, output: outputs.join('\n') + `\n${total.pass} pass\n${total.fail} fail\n${total.errors} errors\nRan ${total.ran} tests across ${total.files} files.\n`, validatedShards: true,
|
|
2079
|
+
podSweep: { id: sweepId, shards: shards.length, files: assignable },
|
|
1970
2080
|
passedIds: [...new Set(measured.flatMap((run) => run.passedIds))].sort(),
|
|
1971
2081
|
stalledEnv: stalledShards.flatMap((item) => item.files.map((file) => ({ file, reason: 'no-output' as const }))),
|
|
1972
2082
|
...(abortedShards ? { abortedShards } : {}) };
|
|
@@ -2002,6 +2112,12 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
2002
2112
|
cachePrefix: bunCache ? podBunCacheVolume(bunCache).shellPrefix : '', installSlots, parallelParts: files.length > 1 ? 2 : 1,
|
|
2003
2113
|
partLimitSeconds, sourceBinding: { cutSha: commit, attemptId }, ...(relaxed ? { testTimeoutMs: GATE_TIMEOUT_RECHECK_MS } : {}) });
|
|
2004
2114
|
const job = await podCommand({ pool: pod.pool, ...(poolOverride ? { poolScheduler: poolOverride } : {}), clone: true,
|
|
2115
|
+
provenanceGate: true,
|
|
2116
|
+
provenance: { actorKind: process.env.ELANOUS_SEAT ? 'seat' : 'loop', actor: process.env.ELANOUS_SEAT || 'release-loop',
|
|
2117
|
+
character: 'gate-shard-runner', launchHost: hostname(), entrance: 'release-recheck', kind: 'gate-recheck',
|
|
2118
|
+
run: process.env.ELANOUS_RUN_ID || attemptId, phase: 'release-gate', requestedAt: new Date().toISOString(),
|
|
2119
|
+
graphNode: 'gate-triage', commit, reason: `release gate recheck ${files.length} files`, pool: pod.pool,
|
|
2120
|
+
memReq: POD_ISOLATION_MEMORY_LIMIT, warmReused: false },
|
|
2005
2121
|
source: { kind: 'commit', sha: commit }, deadlineSeconds, ...(bunCache ? { bunCache } : {}), ...gateHostMirror(pod),
|
|
2006
2122
|
...(installSlots > 0 ? { installSlots: POD_INSTALL_SLOTS_HOST_PATH } : {}), ...(pod.cpu ? { cpu: pod.cpu } : {}),
|
|
2007
2123
|
memoryLimit: POD_ISOLATION_MEMORY_LIMIT, name: `gate-recheck-${randomUUID()}`, command: ['bash', '-lc', shell] });
|
|
@@ -2295,7 +2411,8 @@ export function saveBaselineFileCache(ledger: string, commit: string, rows: Base
|
|
|
2295
2411
|
} finally { if (existsSync(temp)) rmSync(temp); }
|
|
2296
2412
|
}
|
|
2297
2413
|
|
|
2298
|
-
export async function judgeGate(opts: GateOptions, runner: GateRunner = createGateRunner(opts.repo ?? process.cwd(), opts.remote)
|
|
2414
|
+
export async function judgeGate(opts: GateOptions, runner: GateRunner = createGateRunner(opts.repo ?? process.cwd(), opts.remote),
|
|
2415
|
+
imageProbe: typeof preflightGateImageDigest = preflightGateImageDigest): Promise<GateResult> {
|
|
2299
2416
|
const start = Date.now();
|
|
2300
2417
|
if (opts.pod?.warmReplay) opts = { ...opts, pod: { ...opts.pod,
|
|
2301
2418
|
warmShadowScope: { requested: false, attempts: 0 } } };
|
|
@@ -2340,6 +2457,8 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2340
2457
|
|| (opts.baselineVersion && !versionPattern.test(opts.baselineVersion))
|
|
2341
2458
|
|| (opts.baselineCommit && !sha.test(opts.baselineCommit))) throw new Error('invalid commit or version');
|
|
2342
2459
|
if (!opts.baselineVersion) throw new Error('previous release version required (--baseline-version)');
|
|
2460
|
+
if (opts.rehearsalBaseline && (opts.graphRunId || !opts.pod || !/-rc\.\d+$/.test(opts.version)))
|
|
2461
|
+
throw new Error('rehearsal baseline requires a direct Pod gate with an isolated rc version');
|
|
2343
2462
|
// Observation only. Failure to plan cannot change the gate selector or verdict.
|
|
2344
2463
|
try { radiusShadow = planGateRadiusShadow({ repo, ledgerRoot: ledger, version: opts.version,
|
|
2345
2464
|
baselineVersion: opts.baselineVersion, forCommit: opts.commit, instanceRoot: root,
|
|
@@ -2388,12 +2507,31 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2388
2507
|
for (const dir of [cutTree, join(cutTree, 'apps/pwa')]) check(await runner.command('bun', ['install'], dir), `bun install ${dir}`);
|
|
2389
2508
|
// GATE-PARTIAL: a plan made by `release resume --from gate --partial` for exactly this commit re-runs only its files.
|
|
2390
2509
|
// Its logs go to cut-partial/ — the full cut/ logs stay whole (the next release reads them as a baseline source).
|
|
2391
|
-
const
|
|
2392
|
-
|
|
2510
|
+
const partialRead = readPartialPlanResult(roots, opts.version, opts.commit);
|
|
2511
|
+
const explicitPartial = partialRead.plan;
|
|
2512
|
+
const rehearsalStampPresent = ['hard-5h', 'hard-mid'].some((step) =>
|
|
2513
|
+
existsSync(join(root, 'release', opts.version, 'rehearsal', `${step}.json`)));
|
|
2514
|
+
const currentImage = !explicitPartial && opts.graphRunId && opts.pod && rehearsalStampPresent
|
|
2515
|
+
? imageProbe(opts.pod.pool) : null;
|
|
2516
|
+
const radius = !explicitPartial && opts.graphRunId && opts.pod && rehearsalStampPresent
|
|
2517
|
+
? planHardRehearsalRadius({ root, repo, version: opts.version, forCommit: opts.commit,
|
|
2518
|
+
graphPins: gateGraphPins(root, opts.graphRunId), envFingerprint: gateEnvFingerprint(process.env), imageDigest: currentImage })
|
|
2519
|
+
: null;
|
|
2520
|
+
if (radius) debug.log('release-loop.gate', 'radius-live-plan', { version: opts.version, reason: radius.reason,
|
|
2521
|
+
files: radius.plan?.files.length ?? null, rehearsalRunId: radius.rehearsalRunId ?? null });
|
|
2522
|
+
let partial = explicitPartial ?? radius?.plan ?? null;
|
|
2523
|
+
debug.log('release-loop.gate', partial ? 'partial-regate' : 'partial-fallback', {
|
|
2524
|
+
version: opts.version, priorCommit: partial?.priorCommit ?? null, commit: opts.commit,
|
|
2525
|
+
planKind: partial?.kind ?? 'full', remeasureFileCount: partial?.files.length ?? 0,
|
|
2526
|
+
preservedShardCount: partial?.kind === 'recheck' && 'preservedShardCount' in partial
|
|
2527
|
+
&& typeof partial.preservedShardCount === 'number' ? partial.preservedShardCount : 0,
|
|
2528
|
+
fallbackReason: partial ? undefined : partialRead.fallbackReason,
|
|
2529
|
+
});
|
|
2393
2530
|
if (partial?.kind === 'carry') {
|
|
2531
|
+
const carryPriorCommit = partial.priorCommit;
|
|
2394
2532
|
// The plan alone is not evidence: the old cut and its verdict must still be complete and clean at this SHA.
|
|
2395
|
-
if (!verifyDocsOnlyCarry(repo,
|
|
2396
|
-
throw new Error(`carry plan diff is not docs-only: ${
|
|
2533
|
+
if (!verifyDocsOnlyCarry(repo, carryPriorCommit, opts.commit))
|
|
2534
|
+
throw new Error(`carry plan diff is not docs-only: ${carryPriorCommit}..${opts.commit}`);
|
|
2397
2535
|
const trusted = roots.some((location) => {
|
|
2398
2536
|
const dir = join(location, 'release', opts.version);
|
|
2399
2537
|
const failuresPath = join(dir, 'gate-failures.json');
|
|
@@ -2401,11 +2539,11 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2401
2539
|
if (!existsSync(failuresPath) || !existsSync(verdictPath)) return false;
|
|
2402
2540
|
const failures = JSON.parse(readFileSync(failuresPath, 'utf8')) as { commit?: unknown; failures?: unknown; errors?: unknown };
|
|
2403
2541
|
const verdict = JSON.parse(readFileSync(verdictPath, 'utf8')) as { commit?: unknown; outcome?: unknown };
|
|
2404
|
-
return failures.commit ===
|
|
2542
|
+
return failures.commit === carryPriorCommit && Array.isArray(failures.failures) && failures.failures.length === 0
|
|
2405
2543
|
&& (failures.errors === undefined || (Array.isArray(failures.errors) && failures.errors.length === 0))
|
|
2406
|
-
&& verdict.commit ===
|
|
2544
|
+
&& verdict.commit === carryPriorCommit && verdict.outcome === 'ok';
|
|
2407
2545
|
});
|
|
2408
|
-
if (!trusted) throw new Error(`carry plan has no complete clean gate at ${
|
|
2546
|
+
if (!trusted) throw new Error(`carry plan has no complete clean gate at ${carryPriorCommit}`);
|
|
2409
2547
|
}
|
|
2410
2548
|
// GATE-SKIP-KNOWN-RETRY — the ids the verdict will not count as introduced (the recorded baseline ⊕ env-known), read
|
|
2411
2549
|
// before the sweep so a shard failing only with them skips its isolation retries. No recorded baseline = no skip.
|
|
@@ -2420,12 +2558,23 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2420
2558
|
} catch (error) { debug.log('release-loop.gate', 'known-failures-unavailable', { error: String(error) }); }
|
|
2421
2559
|
}
|
|
2422
2560
|
const durationSource = join(ledger, 'release', opts.baselineVersion, 'gate-logs', 'cut');
|
|
2423
|
-
const
|
|
2561
|
+
const runCut = (selected: typeof partial) => selected?.kind === 'carry' ? undefined : runner.sweep(cutTree,
|
|
2562
|
+
join(root, 'release', opts.version, 'gate-logs', selected ? 'cut-partial' : 'cut'),
|
|
2424
2563
|
opts.pod ? { ...opts.pod, durationSource, ...(knownFailures.length ? { knownFailures } : {}), onSelectionTimed: ({ ms }) => { result.selectionMs = ms; },
|
|
2425
2564
|
// GATE-LIVE-OBS: the release ledger's shards.json (UX #24782) — never the run tree's universe; an explicit
|
|
2426
2565
|
// --ledger-root (tests) keeps it in that ledger.
|
|
2427
2566
|
shardsFile: { path: opts.ledgerRoot ? gateShardsPath(opts.version, opts.ledgerRoot) : gateShardsPath(opts.version), version: opts.version } } : undefined,
|
|
2428
|
-
|
|
2567
|
+
selected?.files);
|
|
2568
|
+
let cutRun = await runCut(partial);
|
|
2569
|
+
const radiusSelectionMatched = partial?.files && cutRun?.podSweep?.files
|
|
2570
|
+
&& JSON.stringify([...partial.files].sort()) === JSON.stringify([...cutRun.podSweep.files].sort());
|
|
2571
|
+
if (radius?.plan && (!radiusSelectionMatched
|
|
2572
|
+
|| !partialGateImagesMatch(root, opts.version, currentImage!, opts.commit, cutRun?.podSweep))) {
|
|
2573
|
+
debug.log('release-loop.gate', 'radius-live-image-drift', { version: opts.version,
|
|
2574
|
+
rehearsalRunId: radius.rehearsalRunId, action: 'full-sweep' }, { level: 'warn' });
|
|
2575
|
+
partial = null;
|
|
2576
|
+
cutRun = await runCut(null);
|
|
2577
|
+
}
|
|
2429
2578
|
cutSweepRc = cutRun?.rc ?? null;
|
|
2430
2579
|
cutSweepUsable = !!cutRun && (cutRun.rc === 0 || cutRun.rc === 1) && !cutRun.timedOut
|
|
2431
2580
|
&& !cutRun.abortedShards && !cutRun.stalledEnv?.length;
|
|
@@ -2816,6 +2965,8 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2816
2965
|
if (error instanceof StalledPodShards) {
|
|
2817
2966
|
result.stalledShards = error.stalledShards;
|
|
2818
2967
|
result.partialSummary = error.partialSummary;
|
|
2968
|
+
result.partialFailures = error.partialFailures;
|
|
2969
|
+
result.preservedShardCount = error.preservedShardCount;
|
|
2819
2970
|
if (error.abortedShards) result.abortedShards = error.abortedShards;
|
|
2820
2971
|
}
|
|
2821
2972
|
} finally {
|
|
@@ -2866,6 +3017,13 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2866
3017
|
};
|
|
2867
3018
|
const observed = { ...(result.selectionMs !== undefined ? { selectionMs: result.selectionMs } : {}),
|
|
2868
3019
|
...(result.warmShadow?.length ? { warmShadow: result.warmShadow } : {}) };
|
|
3020
|
+
// Receipt is advisory for a later radius gate. Missing identity makes reuse invalid, never this gate's verdict.
|
|
3021
|
+
const baselineReceipt = gateBaselineReceipt({ root, version: opts.version, commit: opts.commit,
|
|
3022
|
+
graphPins: gateGraphPins(root, opts.graphRunId) ?? (opts.rehearsalBaseline ? gateSourcePins(repo, opts.commit) : null),
|
|
3023
|
+
envFingerprint: gateEnvFingerprint(process.env),
|
|
3024
|
+
fullSweep: result.outcome === 'ok' && cutSweepUsable && !result.partial && !!cutFailures
|
|
3025
|
+
&& !result.rcNonzeroNoFailures.length && !result.stalledShards?.length && !result.stalledEnv.length
|
|
3026
|
+
&& !result.unmeasuredRecheckFiles?.length && !result.unmeasuredErrors?.length });
|
|
2869
3027
|
try {
|
|
2870
3028
|
for (const location of roots) {
|
|
2871
3029
|
const path = verdictFile(location, opts.version);
|
|
@@ -2878,7 +3036,7 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2878
3036
|
try {
|
|
2879
3037
|
const warmHistory = readWarmVerdictHistory(path) ?? [];
|
|
2880
3038
|
writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit,
|
|
2881
|
-
outcome: result.outcome, ...ids, ...observed,
|
|
3039
|
+
outcome: result.outcome, ...ids, ...observed, baselineReceipt,
|
|
2882
3040
|
...(opts.pod?.warmReplay ? { baselineCommit, warmHistory } : {}) }, null, 2) + '\n', { mode: 0o600 });
|
|
2883
3041
|
chmodSync(temp, 0o600);
|
|
2884
3042
|
renameSync(temp, path);
|
|
@@ -2894,7 +3052,7 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2894
3052
|
try {
|
|
2895
3053
|
const warmHistory = readWarmVerdictHistory(path) ?? [];
|
|
2896
3054
|
writeFileSync(temp, JSON.stringify({ version: opts.version, commit: opts.commit,
|
|
2897
|
-
outcome: result.outcome, ...ids, ...observed,
|
|
3055
|
+
outcome: result.outcome, ...ids, ...observed, baselineReceipt,
|
|
2898
3056
|
...(opts.pod?.warmReplay ? { baselineCommit, warmHistory } : {}) }, null, 2) + '\n', { mode: 0o600 });
|
|
2899
3057
|
chmodSync(temp, 0o600);
|
|
2900
3058
|
renameSync(temp, path);
|
|
@@ -3023,6 +3181,7 @@ export function parseOptions(args: string[], env: NodeJS.ProcessEnv): GateOption
|
|
|
3023
3181
|
const arg = args[i];
|
|
3024
3182
|
if (arg === '--help') return 'help';
|
|
3025
3183
|
if (arg === '--json') continue;
|
|
3184
|
+
if (arg === '--rehearsal-baseline') { opts.rehearsalBaseline = true; continue; }
|
|
3026
3185
|
// 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).
|
|
3027
3186
|
if (arg === '--fresh-shards') { freshShards = true; continue; }
|
|
3028
3187
|
if (arg === '--rehearsal-tui') { opts.rehearsalTui = true; continue; }
|
|
@@ -3085,7 +3244,7 @@ export async function runGateNode(argv: string[], env: NodeJS.ProcessEnv, runner
|
|
|
3085
3244
|
debug.log('release-loop.gate', 'executor', { version: opts.version, ...placement, requested: opts.executor ?? null });
|
|
3086
3245
|
}
|
|
3087
3246
|
if (opts === 'help') {
|
|
3088
|
-
console.log('Usage: bun scripts/release-loop/gate-node.ts --commit <sha> --version <v> [--baseline-version <prev>] [--baseline-commit <sha>] [--remote <ssh-host>] [--remote-mirror <path>] [--pod-pool <pool>] [--pod-shards <n>] [--pod-shard-timeout-seconds <n>] [--recheck-file-limit <n>] [--fresh-shards] [--executor <pod|host>] [--json]\nWithout flags, input.commit, input.version and input.previousVersion come from the JSON file at ELANOUS_GRAPH_CONTEXT.\n--executor host (input.gateExecutor) ignores every pod option and sweeps on --remote (input.gateRemote, required).');
|
|
3247
|
+
console.log('Usage: bun scripts/release-loop/gate-node.ts --commit <sha> --version <v> [--baseline-version <prev>] [--baseline-commit <sha>] [--remote <ssh-host>] [--remote-mirror <path>] [--pod-pool <pool>] [--pod-shards <n>] [--pod-shard-timeout-seconds <n>] [--recheck-file-limit <n>] [--fresh-shards] [--executor <pod|host>] [--rehearsal-baseline] [--json]\nWithout flags, input.commit, input.version and input.previousVersion come from the JSON file at ELANOUS_GRAPH_CONTEXT.\n--executor host (input.gateExecutor) ignores every pod option and sweeps on --remote (input.gateRemote, required).\n--rehearsal-baseline pins source graph bytes only for a direct Pod gate on an isolated rc version.');
|
|
3089
3248
|
return 0;
|
|
3090
3249
|
}
|
|
3091
3250
|
version = opts.version;
|
|
@@ -3098,7 +3257,7 @@ export async function runGateNode(argv: string[], env: NodeJS.ProcessEnv, runner
|
|
|
3098
3257
|
throw new Error('release gate host reservation requires graph runId and pinned state root');
|
|
3099
3258
|
const releaseHosts = context && hosts.length
|
|
3100
3259
|
? reserveReleaseGateHosts(reservationRoot!, context.runId!, hosts) : () => undefined;
|
|
3101
|
-
try { result = await judge(opts, runner); }
|
|
3260
|
+
try { result = await judge(context?.runId ? { ...opts, graphRunId: context.runId } : opts, runner); }
|
|
3102
3261
|
finally { releaseHosts(); }
|
|
3103
3262
|
} catch (error) {
|
|
3104
3263
|
result = { outcome: 'error', commit: '', introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: Date.now() - start, error: String(error) };
|
|
@@ -27,7 +27,13 @@ export interface PartialPlan {
|
|
|
27
27
|
|
|
28
28
|
/** G1: a second measurement of only the failed files on the very same release commit.
|
|
29
29
|
* This is deliberately separate from PartialPlan, which compares two different commits. */
|
|
30
|
-
export interface RecheckPlan extends PartialPlan {
|
|
30
|
+
export interface RecheckPlan extends PartialPlan {
|
|
31
|
+
kind: 'recheck';
|
|
32
|
+
/** Files from shards that could not produce a measurement; completed shard results remain in priorFailures/errors. */
|
|
33
|
+
stalledFiles?: string[];
|
|
34
|
+
/** Count of complete shards whose measurements are preserved in this recheck. */
|
|
35
|
+
preservedShardCount?: number;
|
|
36
|
+
}
|
|
31
37
|
|
|
32
38
|
const FULL_SHA = /^[0-9a-f]{40}$/i;
|
|
33
39
|
const RELEASE_VERSION = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
|
|
@@ -92,13 +98,49 @@ function validateRecheckPlan(raw: Partial<RecheckPlan>, version: string, path: s
|
|
|
92
98
|
typeof raw.forCommit !== 'string' || !FULL_SHA.test(raw.forCommit) || raw.priorCommit !== raw.forCommit ||
|
|
93
99
|
!Array.isArray(raw.priorFailures) || !raw.priorFailures.every((id) => typeof id === 'string') ||
|
|
94
100
|
!Array.isArray(raw.priorErrors) || !raw.priorErrors.every((id) => typeof id === 'string') ||
|
|
95
|
-
!Array.isArray(raw.files) || !raw.files.length || !raw.files.every((file) => typeof file === 'string')
|
|
101
|
+
!Array.isArray(raw.files) || !raw.files.length || !raw.files.every((file) => typeof file === 'string') ||
|
|
102
|
+
(raw.preservedShardCount !== undefined && (!Number.isSafeInteger(raw.preservedShardCount) || raw.preservedShardCount < 0))) invalid();
|
|
96
103
|
let expected: string[] = [];
|
|
97
|
-
try {
|
|
104
|
+
try {
|
|
105
|
+
const measuredFiles = [...raw.priorFailures!, ...raw.priorErrors!].map(testFileOfId);
|
|
106
|
+
const stalledFiles = raw.stalledFiles === undefined ? [] : raw.stalledFiles;
|
|
107
|
+
if (!Array.isArray(stalledFiles) || !stalledFiles.every((file) => typeof file === 'string' && TEST_FILE.test(file) && !file.split('/').includes('..'))) invalid();
|
|
108
|
+
if (raw.stalledFiles !== undefined && stalledFiles.some((file) => measuredFiles.includes(file))) invalid();
|
|
109
|
+
expected = [...new Set(stalledFiles)].sort();
|
|
110
|
+
// Legacy plans recheck every prior failed file. Stalled plans re-run only files from incomplete shards; all
|
|
111
|
+
// completed shard outcomes, including runtime errors, are preserved for the combined verdict.
|
|
112
|
+
if (raw.stalledFiles === undefined) expected = [...new Set(measuredFiles)].sort();
|
|
113
|
+
}
|
|
98
114
|
catch { invalid(); }
|
|
99
115
|
if (JSON.stringify(raw.files) !== JSON.stringify(expected)) invalid();
|
|
100
116
|
}
|
|
101
117
|
|
|
118
|
+
/** Plan a same-commit retry after a Pod sweep reports stalled shards. Reuse completed outcomes and rerun stalled files. */
|
|
119
|
+
export function planStalledShardRecheck(input: { version: string; measuredCommit: string; forCommit: string;
|
|
120
|
+
failures: readonly string[]; errors: readonly string[]; stalledFiles: readonly string[]; preservedShardCount?: number;
|
|
121
|
+
existsAtCommit: (file: string) => boolean }):
|
|
122
|
+
{ ok: true; plan: RecheckPlan } | { ok: false; reason: string } {
|
|
123
|
+
if (!RELEASE_VERSION.test(input.version)) return { ok: false, reason: 'invalid release version' };
|
|
124
|
+
if (!FULL_SHA.test(input.measuredCommit) || !FULL_SHA.test(input.forCommit)) return { ok: false, reason: 'commit is not a full sha' };
|
|
125
|
+
if (input.measuredCommit !== input.forCommit) return { ok: false, reason: 'recheck requires the same commit' };
|
|
126
|
+
try { [...input.failures, ...input.errors].forEach(testFileOfId); }
|
|
127
|
+
catch (error) { return { ok: false, reason: String(error instanceof Error ? error.message : error) }; }
|
|
128
|
+
const stalledFiles = [...new Set(input.stalledFiles)].sort();
|
|
129
|
+
if (!stalledFiles.length) return { ok: false, reason: 'no stalled test files to recheck' };
|
|
130
|
+
if (stalledFiles.some((file) => !TEST_FILE.test(file) || file.split('/').includes('..'))) return { ok: false, reason: 'unsafe stalled test path' };
|
|
131
|
+
const measuredFiles = [...new Set([...input.failures, ...input.errors].map(testFileOfId))];
|
|
132
|
+
if (stalledFiles.some((file) => measuredFiles.includes(file)))
|
|
133
|
+
return { ok: false, reason: 'stalled file overlaps a completed shard result' };
|
|
134
|
+
const files = stalledFiles;
|
|
135
|
+
try {
|
|
136
|
+
const missing = files.find((file) => !input.existsAtCommit(file));
|
|
137
|
+
if (missing) return { ok: false, reason: `failed test file missing at commit: ${missing}` };
|
|
138
|
+
} catch (error) { return { ok: false, reason: `test file existence unreadable: ${String(error)}` }; }
|
|
139
|
+
return { ok: true, plan: { kind: 'recheck', version: input.version, priorCommit: input.measuredCommit,
|
|
140
|
+
forCommit: input.forCommit, files, stalledFiles, ...(input.preservedShardCount === undefined ? {} : { preservedShardCount: input.preservedShardCount }),
|
|
141
|
+
priorFailures: [...input.failures], priorErrors: [...input.errors] } };
|
|
142
|
+
}
|
|
143
|
+
|
|
102
144
|
export const partialPlanPath = (root: string, version: string) => join(root, 'release', version, 'gate-partial.json');
|
|
103
145
|
/** The same test-file set the gate sweep runs (`git ls-files` filtered by this suffix). */
|
|
104
146
|
const TEST_FILE = /^(?:[\w.-]+\/)*[\w.-]+\.test\.(?:tsx?|jsx?|mts|cts)$/;
|
|
@@ -182,24 +224,32 @@ export function clearPartialPlan(root: string, version: string): void {
|
|
|
182
224
|
}
|
|
183
225
|
|
|
184
226
|
/** The plan for exactly this commit, or null. A malformed plan is an error (never silently a full or partial gate). */
|
|
185
|
-
export function
|
|
227
|
+
export function readPartialPlanResult(roots: readonly string[], version: string, commit: string):
|
|
228
|
+
{ plan: PartialPlan | null; fallbackReason: string | null } {
|
|
229
|
+
let fallbackReason: string | null = 'no-applicable-plan';
|
|
186
230
|
for (const root of roots) {
|
|
187
231
|
const path = partialPlanPath(root, version);
|
|
188
232
|
if (!existsSync(path)) continue;
|
|
189
233
|
const raw = JSON.parse(readFileSync(path, 'utf8')) as Partial<PartialPlan>;
|
|
234
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error(`invalid gate partial plan: ${path}`);
|
|
190
235
|
if ((raw as Partial<RecheckPlan>).kind !== undefined && (raw as Partial<RecheckPlan>).kind !== 'recheck' && raw.kind !== 'carry')
|
|
191
236
|
throw new Error(`invalid gate partial plan: ${path}`);
|
|
192
|
-
//
|
|
193
|
-
// A legacy full gate may run, but it must never interpret a same-commit recheck as a changed-tip partial gate.
|
|
237
|
+
// Only a well-formed stalled-shard recheck for this exact release commit enters the same-commit consumer path.
|
|
194
238
|
if ((raw as Partial<RecheckPlan>).kind === 'recheck') {
|
|
195
|
-
|
|
239
|
+
const recheck = raw as Partial<RecheckPlan>;
|
|
240
|
+
validateRecheckPlan(recheck, version, path);
|
|
241
|
+
if (recheck.forCommit === commit && recheck.stalledFiles !== undefined)
|
|
242
|
+
return { plan: recheck, fallbackReason: null };
|
|
243
|
+
if (recheck.forCommit === commit) { fallbackReason = 'recheck-not-stalled-only'; continue; }
|
|
244
|
+
fallbackReason = 'plan-commit-mismatch';
|
|
196
245
|
continue;
|
|
197
246
|
}
|
|
198
247
|
if (raw.version !== version || typeof raw.priorCommit !== 'string' || !/^[0-9a-f]{40}$/i.test(raw.priorCommit)
|
|
199
248
|
|| typeof raw.forCommit !== 'string' || !/^[0-9a-f]{40}$/i.test(raw.forCommit) || raw.priorCommit === raw.forCommit
|
|
200
249
|
|| !Array.isArray(raw.files) || (raw.files.length === 0) !== (raw.kind === 'carry')
|
|
201
250
|
|| !raw.files.every((file) => typeof file === 'string' && TEST_FILE.test(file) && !file.split('/').includes('..'))
|
|
202
|
-
|| !Array.isArray(raw.priorFailures) || !Array.isArray(raw.priorErrors))
|
|
251
|
+
|| !Array.isArray(raw.priorFailures) || !Array.isArray(raw.priorErrors))
|
|
252
|
+
throw new Error(`invalid gate partial plan: ${path}`);
|
|
203
253
|
if (raw.kind === 'carry' && (raw.priorFailures.length || raw.priorErrors.length)) throw new Error(`invalid gate partial plan: ${path}`);
|
|
204
254
|
// Every prior failure's file is re-run (planPartialRegate guarantees it) — a plan that would carry a failure it did
|
|
205
255
|
// not re-run is malformed, not «partial».
|
|
@@ -208,10 +258,14 @@ export function readPartialPlan(roots: readonly string[], version: string, commi
|
|
|
208
258
|
try { failureFiles = [...raw.priorFailures, ...raw.priorErrors].map((id) => testFileOfId(String(id))); }
|
|
209
259
|
catch { throw new Error(`invalid gate partial plan: ${path}`); }
|
|
210
260
|
if (failureFiles.some((file) => !rerun.has(file))) throw new Error(`invalid gate partial plan (prior failure not re-run): ${path}`);
|
|
211
|
-
if (raw.forCommit !== commit) continue;
|
|
212
|
-
return raw as PartialPlan;
|
|
261
|
+
if (raw.forCommit !== commit) { fallbackReason = 'plan-commit-mismatch'; continue; }
|
|
262
|
+
return { plan: raw as PartialPlan, fallbackReason: null };
|
|
213
263
|
}
|
|
214
|
-
return null;
|
|
264
|
+
return { plan: null, fallbackReason };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function readPartialPlan(roots: readonly string[], version: string, commit: string): PartialPlan | null {
|
|
268
|
+
return readPartialPlanResult(roots, version, commit).plan;
|
|
215
269
|
}
|
|
216
270
|
|
|
217
271
|
/** Cut failures after a partial re-run: prior results for files not re-run ⊕ this run's results for the re-run files. */
|