elanous 0.2.36 → 0.2.38
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/{uC-N0emedeNOFuaBQFv-I → RrjXTwz-urRAbChP1bX02}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{9250-072df22eaadaa6b5.js → 1026-44010f405704050c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4304.e9b2512834a9e23e.js → 1632.7d87f998e714bede.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1938.0e6c60ee91c4d7f5.js +148 -0
- package/apps/pwa/out/_next/static/chunks/{7784.1f0ac4a16d190cf4.js → 2104.70e086d5174a4736.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6566.926a1d1b7c911442.js → 214.186a430da28338f1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +93 -0
- package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{5711.957b095705c12560.js → 2415.738b777642a02233.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4286.b70c4520306817e8.js → 3086.fb14b60ce98b53d3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3148-98efd4869d660a87.js → 3124-561f7f037943cde2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3727.7949ccaacaa71242.js → 3291.f6c1005387d514bd.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +36 -0
- package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +287 -0
- package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8904.7d51af2dc033965c.js → 3528.e4b8ab70d339f965.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +94 -0
- package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3f0de3de-2340c532c00395db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3031-85328a92fcce4da6.js → 4199-f7c6eb40cd0322f8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +32 -0
- package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +90 -0
- package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +79 -0
- package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +74 -0
- package/apps/pwa/out/_next/static/chunks/5041-5aada92ca215ffdd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{528.38ce20ef8aa251ff.js → 5203.51e5d8b5f1dcfe53.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2683.c9773a0c589b031b.js → 5307.d7328020227880c2.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +1 -0
- package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +8 -0
- package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{552.b7d061ad91eeac51.js → 5638.107314dc479e2f37.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6142.913b44e260a3f925.js +64 -0
- package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6925.562d532110879886.js → 6493.27ad77de7aac7966.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +62 -0
- package/apps/pwa/out/_next/static/chunks/{275-02ea4c2a33980422.js → 7161-8f22db3ec5ed005e.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3136.30aaaa5fa03662a3.js → 7488.966b116789f3d41a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4116.a84a92a2492c080e.js → 7524.ce973525d30b3d52.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +77 -0
- package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3324.a09703033abcbd2f.js → 7628.6b16863ac3972333.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3410.7f9af5ab77cbe65f.js → 7954.4f7a8832663ee979.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{771.c3cdb6c1f7f47c02.js → 8019.21ca554a821dad01.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4615.8525eb0add35eba6.js → 8487.291666583bebe640.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8509.3a54d4e61893d7cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6943.c6b24124853a47b2.js → 8879.ac06755bcf3e44a1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +149 -0
- package/apps/pwa/out/_next/static/chunks/{575.d929793a53f27c4b.js → 8911.bf5e712acb25fb6c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9f31e478.fefcbcd3c388ebc5.js → 8994d93e.33ba491f95345fc2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{da5ecc5c-b005ad8cac737d57.js → 89d6c04f-6b8ab341748e468a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{599.c39c571b6733f2a2.js → 9223.cbcc88e0e9950426.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9299.24e2a7d9b6d1f91b.js +226 -0
- package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +24 -0
- package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8037.e254fd797aa224d1.js → 9581.da63ddf41acfad46.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +2 -0
- package/apps/pwa/out/_next/static/chunks/{ceba0382.650712b56b85b582.js → 9fe1b809.738da85c8b17e3fb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-866aac5ff226a7f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-e7abc34a48a6f71e.js → page-291ab19fe2acb173.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-c15958835534404b.js → page-6b140f77593576eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3a3d9966.cc4d4585a2708e7c.js → b7459770.6539b11860eb8a9c.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{053a429e.9a63436527cc751c.js → b7478fef.5917716286213fcc.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/bb6987f9.3647e1a23b0e3217.js +122 -0
- package/apps/pwa/out/_next/static/chunks/{2812ca6a.3b9f4a7a08885744.js → de8b930d.d94c0f42acf807fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{873d6c12.09bd499f57171543.js → eaad0cba.771200940c529df7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-4b12a946f352cee2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +1 -0
- package/apps/pwa/out/_next/static/css/{b5d88eba78a3d7bf.css → be9019f696217521.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/drafts/recipes.yaml +27 -7
- package/graphs/release/recipes.yaml +9 -0
- package/graphs/release/release-loop.yaml +26 -18
- package/graphs/work/draft-close.yaml +54 -0
- package/graphs/work/green-close.yaml +37 -0
- package/graphs/work/recipes.yaml +46 -1
- package/graphs/work/run-research.yaml +35 -0
- package/package.json +1 -1
- package/scripts/__fixtures__/authoring-paths-10x3.json +32 -0
- package/scripts/ask-op-inbox-once.ts +17 -0
- package/scripts/boundary-proof-mapping-audit.ts +88 -0
- package/scripts/brand/check.ts +13 -4
- package/scripts/codex-fallback-live-probe.ts +17 -15
- package/scripts/fleet/node-setup.sh +32 -2
- package/scripts/fleet/run-light-worker.sh +9 -0
- package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
- package/scripts/gate-0226-failure-census.ts +546 -0
- package/scripts/goals/authoring-metrics.ts +258 -0
- package/scripts/graph-units/draft-close-node.ts +222 -0
- package/scripts/hook-order-sweep.ts +7 -4
- package/scripts/intake-collect-telegram-saved-stage.ts +48 -0
- package/scripts/land-global-checks.ts +69 -1
- package/scripts/measure-nl-routing-corpus.ts +207 -2
- package/scripts/provision-export-redactions.ts +15 -0
- package/scripts/public-copy-lint.ts +122 -0
- package/scripts/public-export.ts +69 -2
- package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
- package/scripts/ratchets/train-side-invariants.sh +7 -1
- package/scripts/release-loop/cut-branch.ts +61 -12
- package/scripts/release-loop/docs-node.ts +140 -0
- package/scripts/release-loop/gate-closure.ts +48 -0
- package/scripts/release-loop/gate-diff.ts +2 -1
- package/scripts/release-loop/gate-node.ts +161 -25
- package/scripts/release-loop/gate-partial.ts +82 -3
- package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
- package/scripts/release-loop/gate-radius-live.ts +4 -2
- package/scripts/release-loop/known-issues-node.ts +6 -4
- package/scripts/release-loop/notes-repair.ts +216 -0
- package/scripts/release-loop/prepare-node.ts +61 -5
- package/scripts/release-loop/resume-cap.ts +2 -1
- package/scripts/release-loop/resume-release.ts +406 -7
- package/scripts/release-loop/resume-test-traffic.ts +10 -0
- package/scripts/release-loop/resume.ts +13 -5
- package/scripts/release-loop/traffic-node.ts +12 -4
- package/scripts/release-loop/traffic-transition.ts +53 -13
- package/scripts/release-loop/version-node.ts +109 -15
- package/scripts/train/green-leg.ts +176 -0
- package/scripts/tui-continue-real-evidence.ts +47 -0
- package/scripts/ux-sim.ts +1 -1
- package/scripts/video-pipeline.ts +2 -2
- package/src/acp/client.ts +31 -5
- package/src/acp/core-turn-bridge.ts +12 -1
- package/src/acp/stderr-summary.ts +49 -0
- package/src/agent/monad-agent-turn.ts +1 -0
- package/src/agent/run-context.ts +1 -1
- package/src/agent/task-notification.ts +3 -1
- package/src/agent/terminal-surface.ts +217 -0
- package/src/agent-substrate/pr-reviewer.ts +11 -3
- package/src/agent-substrate/review-observation.ts +10 -0
- package/src/agent-substrate/self-review-cli.ts +537 -57
- package/src/auto-research/question-ladder-contract.ts +137 -0
- package/src/auto-research/research-turn.ts +134 -0
- package/src/autopilot/discovery/doc-lint.ts +1 -1
- package/src/autopilot/lineage/sources.ts +1 -1
- package/src/autopilot/pr-manager.ts +64 -13
- package/src/boot/daemon-runtime.ts +35 -3
- package/src/boot/daemon-tools/pty-shell.ts +2 -1
- package/src/bots/screen-probe.ts +1 -1
- package/src/budget/run-usage-rollup.ts +12 -7
- package/src/budget/unified-usage.ts +20 -0
- package/src/capture/tui-self-report.ts +42 -5
- package/src/chat/index.ts +1 -0
- package/src/chat/tool-render/dispatch.ts +8 -1
- package/src/cli/autopilot-cli.ts +24 -9
- package/src/cli/decisions-cli.ts +7 -4
- package/src/cli/doctor-cli.ts +116 -7
- package/src/cli/guardian-cli.ts +3 -1
- package/src/cli/intake-cli.ts +48 -12
- package/src/cli/lesson-cli.ts +69 -9
- package/src/cli/logs-cli.ts +357 -2
- package/src/cli/memory-cli.ts +30 -1
- package/src/cli/msg-cli.ts +15 -11
- package/src/cli/pr-granularity.ts +5 -3
- package/src/cli/pr-land-overlap-evidence.ts +38 -5
- package/src/cli/pr-land-refusal.ts +1 -1
- package/src/cli/pty-takeover-cli.ts +58 -5
- package/src/cli/release-checklist-read-cli.ts +112 -4
- package/src/cli/release-cli.ts +89 -18
- package/src/cli/review-carry.ts +77 -0
- package/src/cli/self-update.ts +24 -6
- package/src/cli/self-utterances-cli.ts +13 -16
- package/src/cli/tasks-card-show.ts +31 -1
- package/src/cli/tasks-cli.ts +370 -33
- package/src/cli/tasks-read-cli.ts +13 -5
- package/src/cli/usage-cli.ts +12 -10
- package/src/context-bus/claude-memory-import.ts +99 -0
- package/src/context-bus/context-now.ts +86 -2
- package/src/context-bus/long-term-memory.ts +125 -0
- package/src/core-turn/run-core-turn.ts +9 -2
- package/src/core-turn/run-goal-loop.ts +5 -2
- package/src/core-turn/types.ts +5 -0
- package/src/dashboard/chat/acp-chat.ts +9 -0
- package/src/dashboard/index.ts +115 -30
- package/src/dashboard/input/agent-wake.ts +43 -0
- package/src/dashboard/input/chat-main-acp-dispatch.ts +21 -1
- package/src/dashboard/input/terminal-modal-router.ts +8 -159
- package/src/dashboard/replay-preview.ts +25 -0
- package/src/dashboard/side-basic-runtime.ts +61 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +19 -8
- package/src/dashboard/synchronized-frame-output.ts +74 -0
- package/src/dashboard/term-slash-runtime.ts +2 -0
- package/src/dashboard/turn-preamble.ts +28 -4
- package/src/display/coordinator.ts +45 -12
- package/src/display/resize-listener.ts +41 -20
- package/src/display/synchronized-output-region.ts +60 -0
- package/src/domains/guardian-tick.ts +9 -0
- package/src/domains/surface-events.ts +80 -1
- package/src/exec-requests/planner.ts +37 -2
- package/src/execution-loop/launch-gate.ts +4 -3
- package/src/git-fs/cli-stderr.ts +45 -0
- package/src/git-fs/gh-cli.ts +6 -3
- package/src/git-fs/git-cli.ts +11 -5
- package/src/git-fs/watcher.ts +27 -22
- package/src/git-fs/worktree.ts +19 -3
- package/src/graph-runner/graph-cli.ts +26 -2
- package/src/graph-runner/graph-grow.ts +37 -9
- package/src/graph-runner/graph-run-api.ts +3 -2
- package/src/graph-runner/runner.ts +34 -7
- package/src/graph-wizard/generate.ts +29 -6
- package/src/grok/credential.ts +107 -36
- package/src/harness/harness-cli-command.ts +179 -33
- package/src/harness/review-adapter.ts +26 -6
- package/src/hq/fence-wrapper.ts +1 -1
- package/src/hq/transfer.ts +1 -1
- package/src/index.ts +151 -18
- package/src/instance/test-write-guard-real-transport.fixture.ts +52 -0
- package/src/intake-plane/collect-telegram-saved.ts +54 -5
- package/src/interactive-terminal-modal.ts +3 -0
- package/src/keybindings.ts +17 -22
- package/src/llm/provider-credentials.ts +1 -1
- package/src/llm/route-decision.ts +13 -0
- package/src/llm-tool-name.ts +37 -0
- package/src/llm-tool-schema.ts +55 -0
- package/src/llm.ts +203 -21
- package/src/loops/checker.ts +100 -0
- package/src/loops/consensus.ts +26 -2
- package/src/loops/loop-cli.ts +9 -4
- package/src/loops/orchestrator/anomaly-cluster.ts +243 -0
- package/src/loops/orchestrator/inbox-once.ts +28 -0
- package/src/loops/orchestrator/inbox.ts +130 -1
- package/src/loops/orchestrator/tick.ts +55 -7
- package/src/maturity/feature-maturity.ts +1 -0
- package/src/model-tier/llm-tier-map.ts +12 -17
- package/src/msg/msg-store.ts +17 -0
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/channel-ask-op.ts +96 -0
- package/src/nexus/api/discord-trigger-bot.ts +28 -1
- package/src/nexus/api/graph-wizard-api.ts +27 -2
- package/src/nexus/api/grid.ts +24 -4
- package/src/nexus/api/http-server.ts +1 -1
- package/src/nexus/api/ops-api.ts +14 -6
- package/src/nexus/api/telegram-trigger-bot.ts +24 -0
- package/src/nexus/api/terminals.ts +28 -6
- package/src/nexus/state/state.ts +7 -1
- package/src/oauth/codex-account-store.ts +34 -1
- package/src/ops/loops-map.ts +46 -0
- package/src/ops/overview-cache.ts +22 -4
- package/src/ops/overview.ts +41 -5
- package/src/patents/ledger.ts +18 -1
- package/src/policy/llm-policy.ts +3 -1
- package/src/preview/terminal.ts +4 -2
- package/src/prompt-cache/anthropic.ts +2 -0
- package/src/prompt-enhance/enhance.ts +9 -4
- package/src/pty-shell/availability.ts +7 -0
- package/src/pty-shell/herdr-agent-report.ts +40 -31
- package/src/pty-shell/herdr-prune-stale.ts +17 -0
- package/src/pty-shell/herdr-sequence-lease.ts +60 -0
- package/src/pty-shell/pty-control-ipc.ts +187 -18
- package/src/pty-shell/pty-manifest.ts +16 -2
- package/src/pty-shell/registry.ts +25 -15
- package/src/pty-shell/tui-run-state.ts +235 -1
- package/src/release-loop/checklist.ts +50 -5
- package/src/release-loop/feature-store.ts +9 -9
- package/src/release-loop/gate-shards.ts +61 -0
- package/src/release-loop/landed-but-yellow.ts +93 -12
- package/src/release-loop/light-rc.ts +7 -4
- package/src/release-loop/rehearsal.ts +1 -1
- package/src/repl/index.ts +18 -0
- package/src/research/axis-fanout.ts +133 -0
- package/src/research/edge-decision.ts +88 -0
- package/src/research/output-router.ts +127 -0
- package/src/research-bridge/format.ts +16 -1
- package/src/research-bridge/index.ts +1 -0
- package/src/research-bridge/invoke.ts +41 -5
- package/src/seat-loop/seat-report.ts +1 -0
- package/src/self-dev/ask-launch-flow.ts +86 -10
- package/src/self-dev/decompose-proposal.ts +29 -18
- package/src/self-dev/decompose.ts +45 -9
- package/src/self-dev/dev-pipeline.ts +29 -7
- package/src/self-dev/draft-residue.ts +221 -2
- package/src/self-dev/draft-sweep.ts +254 -16
- package/src/self-dev/draft-triage-rules.ts +19 -5
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/review-provider-fallback.ts +45 -7
- package/src/self-dev/run-supervisor.ts +22 -7
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-run.ts +310 -6
- package/src/self-implement/comment-only-source.ts +54 -0
- package/src/self-implement/doctor-visit.ts +108 -0
- package/src/self-implement/gate-artifacts.ts +6 -2
- package/src/self-implement/gate-baseline.ts +99 -1
- package/src/self-implement/gate-cli.ts +231 -82
- package/src/self-implement/gate-failure-signature.ts +44 -0
- package/src/self-implement/gate-remote.ts +30 -4
- package/src/self-implement/gate-scope.ts +13 -1
- package/src/self-implement/goal-author.ts +407 -21
- package/src/self-implement/goal-doc/section.ts +22 -0
- package/src/self-implement/goal-supervisor-fill.ts +110 -27
- package/src/self-implement/importer-test-index.ts +215 -2
- package/src/self-implement/knowhow-pack.ts +125 -12
- package/src/self-implement/l8-merge-queue.ts +198 -32
- package/src/self-implement/off-diff-evidence.ts +23 -0
- package/src/self-implement/orchestrator.ts +369 -33
- package/src/self-implement/pod-inplace-worktree.ts +82 -0
- package/src/self-implement/pod-warm-pool-profile.ts +2 -2
- package/src/self-implement/premise-review.ts +7 -5
- package/src/self-implement/review-round-brief.ts +300 -0
- package/src/self-implement/rework-policy.ts +14 -0
- package/src/self-implement/run-ledger.ts +428 -6
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/running-runs.ts +17 -3
- package/src/self-implement/seams.ts +45 -16
- package/src/self-implement/self-implement-cli.ts +26 -2
- package/src/self-implement/stop-autoheal.ts +1 -0
- package/src/self-implement/test-seams.ts +13 -1
- package/src/self-implement/train-reach-grouping.ts +8 -2
- package/src/session/channel-ask-op-envelope.ts +36 -0
- package/src/session/channel-op-reply-route.ts +200 -0
- package/src/session/chat.ts +10 -1
- package/src/session/id-prefix.ts +60 -0
- package/src/session/index.ts +6 -0
- package/src/session-runtime/index.ts +18 -23
- package/src/skills/runner.ts +7 -3
- package/src/skills/tools/dev-harness.ts +2 -2
- package/src/skills/tools/pty.ts +5 -0
- package/src/skills/tools/schedule-wakeup.ts +1 -6
- package/src/status/bar.ts +3 -3
- package/src/status/metrics.ts +12 -1
- package/src/steward/rejudge-tick.ts +12 -5
- package/src/steward/resync-tick.ts +31 -4
- package/src/storage/file-lock.ts +17 -4
- package/src/task-agent/actions.ts +199 -4
- package/src/task-agent/adopt-pr.ts +63 -2
- package/src/task-agent/boundary-proof-mapping.ts +12 -0
- package/src/task-agent/boundary-proof-producer.ts +147 -0
- package/src/task-agent/completion-evidence.ts +2 -1
- package/src/task-agent/evidence-command-normalize.ts +42 -0
- package/src/task-agent/export-redactions-provision.ts +43 -0
- package/src/task-agent/green-close-recipe.ts +239 -0
- package/src/task-agent/green-sweep.ts +64 -10
- package/src/task-agent/live-moves.ts +48 -3
- package/src/task-agent/map-host-adapter.ts +134 -0
- package/src/task-agent/map-reduce.ts +158 -0
- package/src/task-agent/map-run-ledger.ts +226 -0
- package/src/task-agent/parent-host.ts +74 -17
- package/src/task-agent/rejudge-on-head.ts +72 -5
- package/src/task-agent/repair-cycle.ts +108 -8
- package/src/task-agent/repair-next-move.ts +12 -2
- package/src/task-agent/repair-worker.ts +37 -1
- package/src/task-agent/review-prior-fix.ts +12 -2
- package/src/task-agent/shadow.ts +188 -5
- package/src/task-agent/task-hand.ts +253 -20
- package/src/task-agent/task-parent-role-llm.ts +9 -0
- package/src/task-agent/tier-split.ts +40 -5
- package/src/task-agent/work-order.ts +53 -2
- package/src/task-orchestrator/dispatcher.ts +46 -1
- package/src/task-orchestrator/generator-prompt.ts +6 -0
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +16 -6
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +31 -4
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +8 -6
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +97 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +77 -8
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +15 -9
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +338 -79
- package/src/task-orchestrator/surfaces/self-implement.ts +37 -2
- package/src/terminal/session-registry.ts +1 -0
- package/src/terminal/terminal-modal-router.ts +156 -0
- package/src/testing/linux-env.ts +177 -0
- package/src/tool-hints/gate.ts +6 -4
- package/src/tool-hints/signals.ts +33 -1
- package/src/tui/chat/background-job-status.ts +8 -2
- package/src/tui/chat/goal-interim.ts +5 -1
- package/src/tui/entry.ts +722 -30
- package/src/tui/input/at-picker.ts +55 -0
- package/src/tui/sidetab/attach.ts +304 -0
- package/src/tui/sidetab/list.ts +176 -0
- package/src/tui/sidetab/nl-tool.ts +136 -0
- package/src/tui/slash/resume-command.ts +23 -0
- package/src/tui/slash/resume.ts +38 -35
- package/src/tui/slash/signals.ts +114 -0
- package/src/tui/slash/term-next.ts +72 -0
- package/src/tui-client/local-chat-turn.ts +31 -9
- package/src/user-config.ts +30 -3
- package/src/ux-sim/boot-daemon-tools-pty-shell-device.ts +136 -0
- package/src/ux-sim/classic-tui-seat-scenarios.ts +158 -4
- package/src/ux-sim/fake-gh.ts +174 -0
- package/src/ux-sim/fake-kubectl.ts +142 -0
- package/src/ux-sim/fake-llm.ts +17 -6
- package/src/ux-sim/next-tui-seat-scenarios.ts +176 -6
- package/src/ux-sim/resume-picker-device.ts +173 -0
- package/src/ux-sim/session-id-seed.ts +60 -0
- package/src/ux-sim/skills-tools-shell-device.ts +156 -0
- package/src/ux-sim/task-agent-parent-host-device.ts +264 -0
- package/src/ux-sim/task-agent-rejudge-on-head-device.ts +114 -0
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +0 -287
- package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +0 -64
- package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +0 -36
- package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +0 -149
- package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +0 -24
- package/apps/pwa/out/_next/static/chunks/2986.45d7652e4f13557e.js +0 -2
- package/apps/pwa/out/_next/static/chunks/3155.2587a55196ecb394.js +0 -226
- package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +0 -8
- package/apps/pwa/out/_next/static/chunks/3538.a445e50bb359d068.js +0 -32
- package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +0 -286
- package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +0 -1
- package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +0 -1
- package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +0 -148
- package/apps/pwa/out/_next/static/chunks/5085-bce4904931767ca6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +0 -93
- package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +0 -122
- package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +0 -79
- package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +0 -1
- package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +0 -27
- package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7481.39f7a4654907bf6e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7891.03f910124a737985.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +0 -1
- package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +0 -62
- package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +0 -90
- package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +0 -77
- package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9514.131c52cc75fe6439.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-083747f1d4518f61.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ccae1c4b-0cf414f5eff1b10d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +0 -1
- package/scripts/migrate-monad-to-elanous.ts +0 -195
- package/scripts/rebrand-elanous.ts +0 -242
- /package/apps/pwa/out/_next/static/{uC-N0emedeNOFuaBQFv-I → RrjXTwz-urRAbChP1bX02}/_ssgManifest.js +0 -0
|
@@ -3,7 +3,7 @@ import { spawn, spawnSync } from 'node:child_process';
|
|
|
3
3
|
import { appendFileSync, chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { hostname, tmpdir } from 'node:os';
|
|
5
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
6
|
-
import { dirname, join, resolve } from 'node:path';
|
|
6
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
7
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';
|
|
@@ -12,6 +12,7 @@ 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
14
|
import { loadGateBatchSafe } from './gate-batch-safe';
|
|
15
|
+
import { observeGatePrewarmCutShadow, type GatePrewarmInput } from './gate-prewarm-plan.js';
|
|
15
16
|
import { gateHistory } from './gate-history.js';
|
|
16
17
|
import { baselineFromCutLogs } from './baseline-from-logs';
|
|
17
18
|
import { mergePartialFailures, readPartialPlanResult, testFileOfId, verifyDocsOnlyCarry } from './gate-partial';
|
|
@@ -31,7 +32,7 @@ import { emitNodeResult, readGraphContext } from './node-verdict.js';
|
|
|
31
32
|
import { isGateExecutor, type GateExecutor } from './gate-executor.js';
|
|
32
33
|
import { runPodCommand, parsePodCpu, podCpuMillis, resolvePodCpu, type RunPodCommandOptions, type PodCommandResult, type PodCpu } from '../../src/task-orchestrator/surfaces/pod-command-job.js';
|
|
33
34
|
import { POD_BUN_CACHE_HOST_PATH, parseInstallSeconds, podBunCacheVolume } from '../../src/task-orchestrator/surfaces/pod-bun-cache.js';
|
|
34
|
-
import { PodPoolScheduler, parsePodPool, checkPodPool, defaultRemoteRun, type PodPoolMember } from '../../src/task-orchestrator/surfaces/pod-pool.js';
|
|
35
|
+
import { PodPoolScheduler, parsePodPool, checkPodPool, defaultRemoteRun, snapshotWarmPoolMembers, type PodPoolMember } from '../../src/task-orchestrator/surfaces/pod-pool.js';
|
|
35
36
|
import { POD_INSTALL_SLOTS_DEFAULT, POD_INSTALL_SLOTS_HOST_PATH, installSlotScript } from '../../src/task-orchestrator/surfaces/pod-install-slots.js';
|
|
36
37
|
import { gateDepsInstallScript, parseGateDeps } from '../../src/task-orchestrator/surfaces/pod-gate-deps.js';
|
|
37
38
|
import { warmReferenceFromJobArtifacts, writeWarmJobManifest } from './gate-warm-artifacts.js';
|
|
@@ -41,7 +42,7 @@ import { requestWarmPodReplay, finalizeWarmPodReplay, quarantineWarmPodReplay, t
|
|
|
41
42
|
import { resolveWarmPoolProfile } from '../../src/self-implement/pod-warm-pool-profile.js';
|
|
42
43
|
import { decideWarmReuse, type WarmReuseSwitchConfig, type WarmReuseEvidence } from '../../src/task-orchestrator/surfaces/pod-warm-switch.js';
|
|
43
44
|
import { getUserConfig } from '../../src/user-config.js';
|
|
44
|
-
import { gateShardsPath, recordGateShardsVerdict, writeGateShards, type GateShard } from '../../src/release-loop/gate-shards.js';
|
|
45
|
+
import { beginGateShardAttempt, finalizeTerminalGateShards, gateShardsPath, recordGateShardsVerdict, writeGateShards, type GateJobTerminal, type GateShard } from '../../src/release-loop/gate-shards.js';
|
|
45
46
|
import { defaultKubectl } from '../../src/task-orchestrator/surfaces/self-implement-pod.js';
|
|
46
47
|
import { executeTuiNodeCheck, type ExecutedTuiCheck } from './tui-node-checks.js';
|
|
47
48
|
import { runWithReleaseGateTraffic } from './gate-traffic-mode.js';
|
|
@@ -128,6 +129,72 @@ export interface GateRunner {
|
|
|
128
129
|
/** GATE-FLOW-SIM — the clock this runner measures with (the injected fake clock in a scenario); absent = `Date.now`. */
|
|
129
130
|
now?(): number;
|
|
130
131
|
}
|
|
132
|
+
|
|
133
|
+
/** One watchdog tick. Batch Kubernetes reads per host and trust only the current attempt's result marker. */
|
|
134
|
+
export function reconcileStaleGateShardBoard(input: {
|
|
135
|
+
version: string;
|
|
136
|
+
board: GateShard[];
|
|
137
|
+
logDir?: string;
|
|
138
|
+
kubectl: typeof defaultKubectl;
|
|
139
|
+
now?: Date;
|
|
140
|
+
}): { board: GateShard[]; finalized: Array<{ shard: string; job?: string; state: GateShard['state']; source: 'result-json' | 'kubernetes-job-terminal'; endedAt: string }> } {
|
|
141
|
+
const terminalJobs = new Map<string, GateJobTerminal>();
|
|
142
|
+
const results = new Map<string, { completed?: boolean; jobName?: string; attemptId?: string; jobFailed?: boolean; rc?: number | null; reason?: 'timeout' | 'stall' }>();
|
|
143
|
+
const active = input.board.filter((shard) => shard.state === 'running' || shard.state === 'retry');
|
|
144
|
+
if (!active.length) return { board: input.board, finalized: [] };
|
|
145
|
+
for (const shard of active) {
|
|
146
|
+
if (input.logDir && shard.resultFile) {
|
|
147
|
+
try {
|
|
148
|
+
const raw = JSON.parse(readFileSync(join(input.logDir, basename(shard.resultFile)), 'utf8')) as Record<string, unknown>;
|
|
149
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw) && raw.completed === true && typeof shard.job === 'string'
|
|
150
|
+
&& raw.jobName === shard.job && typeof shard.attemptId === 'string' && raw.attemptId === shard.attemptId) {
|
|
151
|
+
results.set(shard.id, { completed: true, jobName: shard.job, attemptId: shard.attemptId,
|
|
152
|
+
jobFailed: raw.jobFailed === true, rc: typeof raw.rc === 'number' ? raw.rc : null,
|
|
153
|
+
...(raw.reason === 'timeout' || raw.reason === 'stall' ? { reason: raw.reason } : {}) });
|
|
154
|
+
}
|
|
155
|
+
} catch { /* this attempt has not produced its result file yet */ }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const byHost = new Map<string, GateShard[]>();
|
|
159
|
+
for (const shard of active) if (shard.job && shard.host) byHost.set(shard.host, [...(byHost.get(shard.host) ?? []), shard]);
|
|
160
|
+
for (const [host, shards] of byHost) {
|
|
161
|
+
const retryIndividually = new Set(shards.map((shard) => shard.job!));
|
|
162
|
+
try {
|
|
163
|
+
const status = input.kubectl(['--context', host, '-n', 'elanous-test', 'get', 'jobs', ...shards.map((shard) => shard.job!), '-o', 'json']);
|
|
164
|
+
const parsed = JSON.parse(status.stdout) as { items?: Array<{ metadata?: { name?: string }; status?: { conditions?: Array<{ type?: string; status?: string }> } }>; metadata?: { name?: string }; status?: { conditions?: Array<{ type?: string; status?: string }> } };
|
|
165
|
+
const jobs = parsed.items ?? (parsed.metadata?.name ? [parsed as { metadata?: { name?: string }; status?: { conditions?: Array<{ type?: string; status?: string }> } }] : []);
|
|
166
|
+
for (const shard of shards) {
|
|
167
|
+
if (jobs.some((job) => job.metadata?.name === shard.job)) retryIndividually.delete(shard.job!);
|
|
168
|
+
const conditions = jobs.find((job) => job.metadata?.name === shard.job)?.status?.conditions ?? [];
|
|
169
|
+
if (conditions.some((condition) => condition.status === 'True' && condition.type === 'Complete')) terminalJobs.set(shard.job!, 'complete');
|
|
170
|
+
else if (conditions.some((condition) => condition.status === 'True' && condition.type === 'Failed')) terminalJobs.set(shard.job!, 'failed');
|
|
171
|
+
}
|
|
172
|
+
} catch { /* a transient status read does not affect the gate verdict */ }
|
|
173
|
+
// One missing/deleted Job can make a multi-name kubectl request non-zero; retry each name so siblings still reconcile.
|
|
174
|
+
for (const shard of shards) {
|
|
175
|
+
if (!retryIndividually.has(shard.job!)) continue;
|
|
176
|
+
try {
|
|
177
|
+
const status = input.kubectl(['--context', host, '-n', 'elanous-test', 'get', 'job', shard.job!, '-o', 'json']);
|
|
178
|
+
const parsed = JSON.parse(status.stdout) as { metadata?: { name?: string }; status?: { conditions?: Array<{ type?: string; status?: string }> } };
|
|
179
|
+
const conditions = parsed.status?.conditions ?? [];
|
|
180
|
+
if (parsed.metadata?.name === shard.job && conditions.some((condition) => condition.status === 'True' && condition.type === 'Complete')) terminalJobs.set(shard.job!, 'complete');
|
|
181
|
+
else if (parsed.metadata?.name === shard.job && conditions.some((condition) => condition.status === 'True' && condition.type === 'Failed')) terminalJobs.set(shard.job!, 'failed');
|
|
182
|
+
} catch { /* this Job is still active, gone, or unreadable */ }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const reconciled = finalizeTerminalGateShards({ v: 1, version: input.version, updatedAt: (input.now ?? new Date()).toISOString(), shards: input.board },
|
|
186
|
+
terminalJobs, results, input.now ?? new Date());
|
|
187
|
+
const finalized = reconciled.shards.flatMap((shard) => {
|
|
188
|
+
if ((shard.state === 'running' || shard.state === 'retry') || !shard.endedAt) return [];
|
|
189
|
+
const previous = input.board.find((row) => row.id === shard.id);
|
|
190
|
+
if (!previous || (previous.state !== 'running' && previous.state !== 'retry')) return [];
|
|
191
|
+
const result = results.get(shard.id);
|
|
192
|
+
const source = result?.completed === true
|
|
193
|
+
? 'result-json' as const : 'kubernetes-job-terminal' as const;
|
|
194
|
+
return [{ shard: shard.id, ...(shard.job ? { job: shard.job } : {}), state: shard.state, source, endedAt: shard.endedAt }];
|
|
195
|
+
});
|
|
196
|
+
return { board: reconciled.shards, finalized };
|
|
197
|
+
}
|
|
131
198
|
export interface GateOptions {
|
|
132
199
|
commit: string;
|
|
133
200
|
/** The graph run that launched this gate; direct hard rehearsal instead pins source bytes explicitly. */
|
|
@@ -159,6 +226,8 @@ export interface GateOptions {
|
|
|
159
226
|
warmFinalize?: (command: WarmWorkerCommand) => Promise<void>;
|
|
160
227
|
/** Set only on the cut recheck; baseline Jobs never consume the cut worker. */
|
|
161
228
|
warmCutSha?: string;
|
|
229
|
+
/** A measured planner snapshot may accompany the cut; absent fields remain visibly unmeasured. */
|
|
230
|
+
warmPrewarmInput?: GatePrewarmInput;
|
|
162
231
|
warmBaselineSha?: string;
|
|
163
232
|
warmReuseConfig?: WarmReuseSwitchConfig;
|
|
164
233
|
/** At most three cut isolation files may request a shadow replay per verdict. */
|
|
@@ -258,7 +327,7 @@ export interface GateResult {
|
|
|
258
327
|
/** GATE-WARM-BOOT-SCAN — observation only: the cut sweep's test selection time (pod sweep · absent otherwise). */
|
|
259
328
|
selectionMs?: number;
|
|
260
329
|
error?: string;
|
|
261
|
-
stalledShards?: Array<{ shard: number; files: string[]; reason: 'incomplete' | 'no-output' | 'job-failed' | 'exit-code' | 'unattributed' | 'timeout'; lastFile?: string; summaryFailures?: number; namedFailures?: number; detail?: string;
|
|
330
|
+
stalledShards?: Array<{ shard: number; files: string[]; reason: 'incomplete' | 'no-output' | 'job-failed' | 'exit-code' | 'unattributed' | 'timeout' | 'admission-timeout' | 'admission-error'; lastFile?: string; summaryFailures?: number; namedFailures?: number; detail?: string;
|
|
262
331
|
/** Pool member that ran the final unmeasured attempt; enables a bounded cross-host tail remeasure. */
|
|
263
332
|
lastHost?: string;
|
|
264
333
|
/** Failure of the optional cross-host tail attempt; original stall fields remain authoritative. */
|
|
@@ -1342,9 +1411,8 @@ export function limitedLocalCommand(cmd: string, args: string[], cwd: string, li
|
|
|
1342
1411
|
* GATE-MEM-ADMIT (0.2.20) — the gate's shard Jobs ask the same pool admission harness goal Pods ask
|
|
1343
1412
|
* (`PodPoolScheduler.acquireAdmission` · memory headroom by observed usage · `limitedBy`). 0.2.19: 8 shards sat Pending
|
|
1344
1413
|
* for CPU (requests 31.2/32) because harness Pods held the node and the gate counted only its own Jobs (#24698).
|
|
1345
|
-
*
|
|
1346
|
-
*
|
|
1347
|
-
* so the gate keeps priority.
|
|
1414
|
+
* A timed out or failed admission means the lease cannot protect capacity, so the shard remains unmeasured.
|
|
1415
|
+
* A later release resume can retry it when capacity is available.
|
|
1348
1416
|
*/
|
|
1349
1417
|
export interface GateAdmission {
|
|
1350
1418
|
acquire(signal: AbortSignal): Promise<() => void>;
|
|
@@ -1357,7 +1425,7 @@ export interface GateAdmissionResult { outcome: GateAdmissionOutcome; waitedMs:
|
|
|
1357
1425
|
export const gateAdmissionWaitText = (reading: string | null) => `메모리 여유 대기(admission) · ${reading ?? '측정 전'}`.slice(0, 160);
|
|
1358
1426
|
/**
|
|
1359
1427
|
* GATE-MULTI-HOST (0.2.25 · 대표) — the gate pool is a host roster (`release.loop.gatePodPool` =
|
|
1360
|
-
* `pool-node-
|
|
1428
|
+
* `pool-node-a@node-a:N,pool-node-b@node-b:M,…`); shards spread over it by free share (selfCapped). A member that fails a
|
|
1361
1429
|
* shard's launch or goes silent mid-Job is probed; if it is unreachable it leaves the roster for the rest of this gate and
|
|
1362
1430
|
* the shard runs again on the others — one dead host no longer stops the gate. One-member pools keep the old behaviour.
|
|
1363
1431
|
*/
|
|
@@ -1412,6 +1480,7 @@ export function defaultSshCommand(host: string, script: string, limitMs?: number
|
|
|
1412
1480
|
}
|
|
1413
1481
|
|
|
1414
1482
|
export function createGateRunner(repo: string, remote?: string, commandOverride?: GateRunner['command'], podCommand: (options: RunPodCommandOptions) => Promise<PodCommandResult> = runPodCommand, poolOverride?: PodPoolScheduler, podLogTail?: (job: PodCommandResult) => string, tools: GateTools = {}): GateRunner {
|
|
1483
|
+
const observedPrewarmCuts = new Set<string>();
|
|
1415
1484
|
let remoteMirror: string | undefined;
|
|
1416
1485
|
// GATE-FLOW-SIM: the one place the real outside world is named — an injected seam replaces it, absent = today's tools.
|
|
1417
1486
|
const clock = tools.now ?? Date.now;
|
|
@@ -1670,11 +1739,36 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1670
1739
|
board[shard] = next;
|
|
1671
1740
|
flushBoard();
|
|
1672
1741
|
};
|
|
1742
|
+
const resetShardAttempt = (shard: number) => {
|
|
1743
|
+
const row = board[shard];
|
|
1744
|
+
if (!row) return;
|
|
1745
|
+
board[shard] = beginGateShardAttempt(row);
|
|
1746
|
+
flushBoard();
|
|
1747
|
+
};
|
|
1673
1748
|
flushBoard();
|
|
1749
|
+
// A result collector can lose its callback after the Kubernetes Job has already completed. Reconcile
|
|
1750
|
+
// the public shard board independently so a finished Job cannot remain «running» indefinitely.
|
|
1751
|
+
const shardsFile = pod.shardsFile;
|
|
1752
|
+
let reconcileTimer: ReturnType<typeof setInterval> | undefined;
|
|
1753
|
+
const reconcileTick = () => {
|
|
1754
|
+
if (!shardsFile) return;
|
|
1755
|
+
try {
|
|
1756
|
+
const reconciled = reconcileStaleGateShardBoard({ version: shardsFile.version, board, ...(logDir ? { logDir } : {}), kubectl });
|
|
1757
|
+
for (const item of reconciled.finalized) {
|
|
1758
|
+
const index = board.findIndex((shard) => shard.id === item.shard);
|
|
1759
|
+
if (index < 0) continue;
|
|
1760
|
+
board[index] = reconciled.board.find((shard) => shard.id === item.shard)!;
|
|
1761
|
+
debug.log('release.gate', 'shard-stale-finalized', item);
|
|
1762
|
+
}
|
|
1763
|
+
flushBoard();
|
|
1764
|
+
} catch (error) {
|
|
1765
|
+
debug.log('release.gate', 'shard-watchdog-tick-failed', { error: String(error) }, { level: 'warn' });
|
|
1766
|
+
}
|
|
1767
|
+
};
|
|
1674
1768
|
/** The gate's scheduler, seen through one shard: a slot wait and the Pod start become row states. */
|
|
1675
1769
|
// GATE-MEM-ADMIT: `placed` releases the shard's admission once a member is chosen — from then on the Job is
|
|
1676
1770
|
// Pending/Running in the cluster and the next admission reading counts it, so holding the lease would count it twice.
|
|
1677
|
-
const trackedPool = (shard: number, retry: boolean, placed: (member: NonNullable<Awaited<ReturnType<PodPoolScheduler['tryAcquire']>>>) => void = () => {}, skipMembers: ReadonlySet<string> = new Set()): PodPoolScheduler => ({
|
|
1771
|
+
const trackedPool = (shard: number, retry: boolean, jobName: string, resultFile: string, attemptId: string, placed: (member: NonNullable<Awaited<ReturnType<PodPoolScheduler['tryAcquire']>>>) => void = () => {}, skipMembers: ReadonlySet<string> = new Set()): PodPoolScheduler => ({
|
|
1678
1772
|
members: poolScheduler.members,
|
|
1679
1773
|
tryAcquire: async (...[skip, onEmpty, mode]: Parameters<PodPoolScheduler['tryAcquire']>) => {
|
|
1680
1774
|
// GATE-MULTI-HOST: a lost member is skipped while another member is left (all lost = the old behaviour).
|
|
@@ -1682,13 +1776,14 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1682
1776
|
const excluded = new Set([...(skip ?? []), ...skipMembers, ...(downMembers.size && anyLeft ? downMembers : [])]);
|
|
1683
1777
|
const member = await poolScheduler.tryAcquire(excluded.size ? excluded : undefined, onEmpty, mode);
|
|
1684
1778
|
if (member) placed(member);
|
|
1685
|
-
if (member) markShard(shard, { state: retry ? 'retry' : 'running', startedAt: board[shard]?.startedAt ?? new Date().toISOString(), host: member.context }, ['waitReason']);
|
|
1779
|
+
if (member) markShard(shard, { state: retry ? 'retry' : 'running', startedAt: board[shard]?.startedAt ?? new Date().toISOString(), host: member.context, job: jobName, resultFile, attemptId }, ['waitReason']);
|
|
1686
1780
|
else markShard(shard, { waitReason: 'Pod 자리 대기' });
|
|
1687
1781
|
return member;
|
|
1688
1782
|
},
|
|
1689
1783
|
release: (member: Parameters<PodPoolScheduler['release']>[0]) => poolScheduler.release(member),
|
|
1690
1784
|
}) as unknown as PodPoolScheduler;
|
|
1691
1785
|
const runShard = async (paths: string[], shard: number, depth = 0, branch = '', retriedNoOutput = false, fresh = pod.freshShards === true, parentAttempt?: string, hostRetries = 0, batchIsolation = false, skipMembers: ReadonlySet<string> = new Set(), singleShotTail = false): Promise<{ runs: ShardRun[]; stalled: NonNullable<GateResult['stalledShards']> }> => {
|
|
1786
|
+
if (branch || depth > 0 || parentAttempt !== undefined || hostRetries > 0) resetShardAttempt(shard);
|
|
1692
1787
|
// 파일별 소요는 junit 으로 남긴다 — 콘솔 요약(판정 원천)은 그대로이고, 느린 시험 목록(K10 D4)·계층 분리(D2)의 자가 된다.
|
|
1693
1788
|
// GATE-TIMEOUT-HEAL: parts (each with its own junit) under a soft deadline inside this shard's own Job deadline.
|
|
1694
1789
|
const shardDeadline = shardDeadlineSeconds(batchIsolation ? Math.max(...paths.map((file) => estimated([file]))) * Math.ceil(paths.length / batchWidth) : estimated(paths), deadlineSeconds);
|
|
@@ -1752,9 +1847,11 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1752
1847
|
if (descent === 'retry') {
|
|
1753
1848
|
// «descend» is only the way down; «resumed» comes from each leaf whose log reads cleanly (review r4).
|
|
1754
1849
|
debug.log('release-loop.gate', 'pod-shard-descend', { shard, branch, files: paths.length, via: 'retry' });
|
|
1850
|
+
resetShardAttempt(shard);
|
|
1755
1851
|
return runShard(paths, shard, depth, `${branch}-retry`, true, undefined, attemptId, hostRetries, batchIsolation, skipMembers);
|
|
1756
1852
|
}
|
|
1757
1853
|
if (descent === 'split') {
|
|
1854
|
+
resetShardAttempt(shard);
|
|
1758
1855
|
output = undefined;
|
|
1759
1856
|
debug.log('release-loop.gate', 'pod-shard-descend', { shard, branch, files: paths.length, via: 'split' });
|
|
1760
1857
|
} else if (reused) {
|
|
@@ -1769,9 +1866,14 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1769
1866
|
stamp('admissionEnd');
|
|
1770
1867
|
if (admitted.outcome !== 'off') debug.log('release-loop.gate', 'shard-admission', { shard, branch, outcome: admitted.outcome, waitedMs: admitted.waitedMs, ...(admitted.reason ? { reason: admitted.reason } : {}) },
|
|
1771
1868
|
admitted.outcome === 'granted' ? undefined : { level: 'warn' });
|
|
1869
|
+
if (admitted.outcome === 'admission-error' || admitted.outcome === 'admission-timeout') {
|
|
1870
|
+
admitted.release();
|
|
1871
|
+
return { runs: [], stalled: [{ shard, files: paths, reason: admitted.outcome, ...(admitted.reason ? { detail: admitted.reason } : {}) }] };
|
|
1872
|
+
}
|
|
1772
1873
|
// The admission wait is not the shard's run time: deadline/timeout judgment and the measured duration start here.
|
|
1773
1874
|
start = clock();
|
|
1774
1875
|
const jobName = `gate-${randomUUID()}`;
|
|
1876
|
+
const resultFile = `pod-${shard}${branch}.json`;
|
|
1775
1877
|
jobNameForCapture = jobName;
|
|
1776
1878
|
// The member's context is known once the Job is placed; the live log is read (and the Job stopped) there.
|
|
1777
1879
|
let jobContext: string | undefined;
|
|
@@ -1801,7 +1903,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1801
1903
|
graphNode: 'gate', version: pod.shardsFile?.version, commit, shard: `${shard + 1}-of-${shards.length}`,
|
|
1802
1904
|
reason: `release gate shard ${shard + 1}/${shards.length}`, pool: pod.pool, cpuReq: cpu.request,
|
|
1803
1905
|
memReq: memoryLimit ?? POD_ISOLATION_MEMORY_LIMIT, warmReused: false },
|
|
1804
|
-
pool: pod.pool, poolScheduler: trackedPool(shard, depth > 0 || branch !== '', (member) => {
|
|
1906
|
+
pool: pod.pool, poolScheduler: trackedPool(shard, depth > 0 || branch !== '', jobName, resultFile, attemptId, (member) => {
|
|
1805
1907
|
stamp('poolPlaced'); jobContext = member.context; jobContextForCapture = member.context; placedOn = member.context; placed();
|
|
1806
1908
|
if (branch === '-tail') tailPlacedHost = member.context;
|
|
1807
1909
|
}, skipMembers), clone: true, source: { kind: 'commit', sha: commit }, deadlineSeconds: shardDeadline,
|
|
@@ -1898,7 +2000,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
1898
2000
|
const unfinishedDestination = join(logDir, `pod-${shard}${branch}.unfinished.log`);
|
|
1899
2001
|
if (unfinishedLog !== undefined) writeFileSync(unfinishedDestination, unfinishedLog, { mode: 0o600 });
|
|
1900
2002
|
else rmSync(unfinishedDestination, { force: true });
|
|
1901
|
-
writeFileSync(join(logDir, `pod-${shard}${branch}.json`), JSON.stringify({ durationMs, rc: rc ?? null,
|
|
2003
|
+
writeFileSync(join(logDir, `pod-${shard}${branch}.json`), JSON.stringify({ completed: true, jobName: jobNameForCapture, durationMs, rc: rc ?? null,
|
|
1902
2004
|
...(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 } : {}),
|
|
1903
2005
|
...(Object.keys(phaseTimes).length ? { phaseTimes } : {}), ...(podStages ? { podStages } : {}),
|
|
1904
2006
|
...(podLifecycle && Object.keys(podLifecycle).length ? { podLifecycle } : {}),
|
|
@@ -2134,19 +2236,26 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
2134
2236
|
// 모든 조각이 끝난 뒤 판정한다 — 한 조각의 예외로 먼저 돌아가면 다른 Pod 가 도는 채로 정리가 시작된다(#22002 리뷰 R3).
|
|
2135
2237
|
// GATE-RISK-LANE — the risk shard's own wall time (planned vs measured in its log line); it never changes a verdict.
|
|
2136
2238
|
const shardDurations: number[] = [];
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2239
|
+
let settled: Array<PromiseSettledResult<Awaited<ReturnType<typeof runShard>>>>;
|
|
2240
|
+
if (shardsFile) {
|
|
2241
|
+
reconcileTimer = setInterval(reconcileTick, 30_000);
|
|
2242
|
+
reconcileTimer.unref();
|
|
2243
|
+
}
|
|
2244
|
+
try {
|
|
2245
|
+
settled = await Promise.allSettled(shards.map(async (item, shard) => {
|
|
2246
|
+
const shardStartedAt = clock();
|
|
2247
|
+
try {
|
|
2248
|
+
const done = await runShard(item.files, shard);
|
|
2249
|
+
shardDurations[shard] = clock() - shardStartedAt;
|
|
2250
|
+
const state = !done.stalled.length ? 'done' as const : done.stalled.some((stall) => stall.reason === 'timeout') ? 'timeout' as const : 'failed' as const;
|
|
2251
|
+
markShard(shard, { state, endedAt: new Date().toISOString() }, ['waitReason']);
|
|
2252
|
+
return done;
|
|
2253
|
+
} catch (error) {
|
|
2254
|
+
markShard(shard, { state: 'failed', endedAt: new Date().toISOString() }, ['waitReason']);
|
|
2255
|
+
throw error;
|
|
2256
|
+
}
|
|
2257
|
+
}));
|
|
2258
|
+
} finally { if (reconcileTimer) clearInterval(reconcileTimer); }
|
|
2150
2259
|
const rejected = settled.find((result): result is PromiseRejectedResult => result.status === 'rejected');
|
|
2151
2260
|
if (rejected) throw rejected.reason;
|
|
2152
2261
|
const results = settled.flatMap((result) => result.status === 'fulfilled' ? [result.value] : []);
|
|
@@ -2240,6 +2349,19 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
|
|
|
2240
2349
|
|| file.split('/').some((part) => part === '.' || part === '..')))
|
|
2241
2350
|
throw new Error('unsafe pod recheck files');
|
|
2242
2351
|
if (!sha.test(commit)) throw new Error('invalid pod recheck commit');
|
|
2352
|
+
if (pod.warmCutSha === commit && !observedPrewarmCuts.has(commit)) {
|
|
2353
|
+
observedPrewarmCuts.add(commit);
|
|
2354
|
+
try {
|
|
2355
|
+
const pool = poolOverride ?? new PodPoolScheduler(parsePodPool(pod.pool), { kubectl });
|
|
2356
|
+
const snapshot = observeGatePrewarmCutShadow(
|
|
2357
|
+
pod.warmPrewarmInput?.cutSha === commit ? pod.warmPrewarmInput : { cutSha: commit },
|
|
2358
|
+
() => poolOverride && !tools.kubectl ? null : snapshotWarmPoolMembers(pool.members, kubectl), () => pool.snapshot());
|
|
2359
|
+
debug.log('pod.pool', snapshot.status === 'observed' ? 'gate-prewarm-shadow' : 'gate-prewarm-shadow-unmeasured',
|
|
2360
|
+
{ cutSha: commit, ...snapshot });
|
|
2361
|
+
} catch (error) {
|
|
2362
|
+
debug.log('pod.pool', 'gate-prewarm-shadow-unmeasured', { cutSha: commit, reason: String(error) });
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2243
2365
|
const rulesBaseSha = await rulesGateBaseFor(commit, files);
|
|
2244
2366
|
const installSlots = pod.installSlots ?? POD_INSTALL_SLOTS_DEFAULT;
|
|
2245
2367
|
if (!Number.isSafeInteger(installSlots) || installSlots < 0) throw new Error('invalid pod recheck install slots');
|
|
@@ -2704,6 +2826,14 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2704
2826
|
if (radius) debug.log('release-loop.gate', 'radius-live-plan', { version: opts.version, reason: radius.reason,
|
|
2705
2827
|
files: radius.plan?.files.length ?? null, rehearsalRunId: radius.rehearsalRunId ?? null });
|
|
2706
2828
|
let partial = explicitPartial ?? radius?.plan ?? null;
|
|
2829
|
+
const explicitPodPlan = !!explicitPartial && explicitPartial.kind !== 'recheck' && !!opts.pod;
|
|
2830
|
+
const explicitPodDigest = explicitPodPlan ? explicitPartial!.shardImageDigests?.[0] : undefined;
|
|
2831
|
+
const probedPodDigest = explicitPodDigest ? imageProbe(opts.pod!.pool) : null;
|
|
2832
|
+
if (explicitPodPlan && (!explicitPodDigest || probedPodDigest !== explicitPodDigest)) {
|
|
2833
|
+
debug.log('release-loop.gate', 'partial-image-preflight-fallback', { version: opts.version,
|
|
2834
|
+
reason: !explicitPodDigest || !probedPodDigest ? 'executed-pod-image-digest-missing' : 'executed-pod-image-digest-mismatch' }, { level: 'warn' });
|
|
2835
|
+
partial = null;
|
|
2836
|
+
}
|
|
2707
2837
|
debug.log('release-loop.gate', partial ? 'partial-regate' : 'partial-fallback', {
|
|
2708
2838
|
version: opts.version, priorCommit: partial?.priorCommit ?? null, commit: opts.commit,
|
|
2709
2839
|
planKind: partial?.kind ?? 'full', remeasureFileCount: partial?.files.length ?? 0,
|
|
@@ -2762,6 +2892,12 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
2762
2892
|
partial = null;
|
|
2763
2893
|
cutRun = await runCut(null);
|
|
2764
2894
|
}
|
|
2895
|
+
if (explicitPodDigest && partial === explicitPartial && (!radiusSelectionMatched
|
|
2896
|
+
|| !partialGateImagesMatch(root, opts.version, explicitPodDigest, opts.commit, cutRun?.podSweep))) {
|
|
2897
|
+
debug.log('release-loop.gate', 'partial-image-drift', { version: opts.version, action: 'full-sweep' }, { level: 'warn' });
|
|
2898
|
+
partial = null;
|
|
2899
|
+
cutRun = await runCut(null);
|
|
2900
|
+
}
|
|
2765
2901
|
if (radius?.plan && partial === radius.plan) debug.log('release-loop.gate', 'baseline-consumed', {
|
|
2766
2902
|
version: opts.version, baselineCommit: radius.plan.priorCommit, commit: opts.commit,
|
|
2767
2903
|
selectedFiles: radius.plan.files.length, rehearsalRunId: radius.rehearsalRunId,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// GATE-REUSE-BY-DIFF (0.2.25): a code change no longer forces the full sweep — with the tip's import closure
|
|
6
6
|
// (gate-closure.ts) the plan adds every test that can reach a changed file, and every test whose closure is opaque.
|
|
7
7
|
// `release resume --from gate` now plans this by default when the tip moved (`--no-partial` = full gate).
|
|
8
|
-
import { existsSync, linkSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { existsSync, linkSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
11
|
import { dirname, join } from 'node:path';
|
|
@@ -23,6 +23,64 @@ export interface PartialPlan {
|
|
|
23
23
|
files: string[];
|
|
24
24
|
priorFailures: string[];
|
|
25
25
|
priorErrors: string[];
|
|
26
|
+
/** Per-shard executed container imageID digest (never a Job image ref/tag). Present only when every shard recorded one. */
|
|
27
|
+
shardImageDigests?: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** A Pod shard result's executed image ID digest. Job image refs/tags are not this field. */
|
|
31
|
+
export interface PartialPlanShardImage {
|
|
32
|
+
imageDigest?: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type PartialPlanImageDigestDecision =
|
|
36
|
+
{ reuse: 1; reason: 'executed-pod-image-digest-match' }
|
|
37
|
+
| { reuse: 0; reason: 'executed-pod-image-digest-missing' | 'executed-pod-image-digest-mismatch' };
|
|
38
|
+
|
|
39
|
+
const IMAGE_DIGEST = /^sha256:[0-9a-f]{64}$/i;
|
|
40
|
+
|
|
41
|
+
function executedImageDigest(value: unknown): string | null {
|
|
42
|
+
return typeof value === 'string' && IMAGE_DIGEST.test(value) ? value.toLowerCase() : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function shardExecutedDigests(shards: readonly PartialPlanShardImage[]): Array<string | null> {
|
|
46
|
+
return shards.map((shard) => executedImageDigest(shard.imageDigest));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Reuse is allowed only when every shard digest is present and equal. Missing vs mismatch are distinct reasons. */
|
|
50
|
+
export function partialPlanImageDigestsMatch(
|
|
51
|
+
prior: readonly PartialPlanShardImage[],
|
|
52
|
+
current?: readonly PartialPlanShardImage[],
|
|
53
|
+
): PartialPlanImageDigestDecision {
|
|
54
|
+
const left = shardExecutedDigests(prior);
|
|
55
|
+
if (!left.length || left.some((digest) => !digest)) return { reuse: 0, reason: 'executed-pod-image-digest-missing' };
|
|
56
|
+
const first = left[0]!;
|
|
57
|
+
if (left.some((digest) => digest !== first)) return { reuse: 0, reason: 'executed-pod-image-digest-mismatch' };
|
|
58
|
+
if (current !== undefined) {
|
|
59
|
+
const right = shardExecutedDigests(current);
|
|
60
|
+
if (!right.length || right.some((digest) => !digest)) return { reuse: 0, reason: 'executed-pod-image-digest-missing' };
|
|
61
|
+
if (right.some((digest) => digest !== first)) return { reuse: 0, reason: 'executed-pod-image-digest-mismatch' };
|
|
62
|
+
}
|
|
63
|
+
return { reuse: 1, reason: 'executed-pod-image-digest-match' };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function planImageDigestDecision(digests: readonly unknown[]): PartialPlanImageDigestDecision {
|
|
67
|
+
return partialPlanImageDigestsMatch(digests.map((imageDigest) => ({ imageDigest: typeof imageDigest === 'string' ? imageDigest : null })));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Every executed root/retry Pod row. Reads `imageDigest` (container imageID); Job `image` ref/tag is ignored. */
|
|
71
|
+
export function collectExecutedPodShardImages(dir: string, commit?: string): PartialPlanShardImage[] {
|
|
72
|
+
if (!existsSync(dir)) return [];
|
|
73
|
+
try {
|
|
74
|
+
return readdirSync(dir).filter((name) => /^pod-\d+(?:-[\w-]+)?\.json$/.test(name))
|
|
75
|
+
.sort((a, b) => Number(/^pod-(\d+)/.exec(a)![1]) - Number(/^pod-(\d+)/.exec(b)![1]) || a.localeCompare(b))
|
|
76
|
+
.map((name) => {
|
|
77
|
+
try {
|
|
78
|
+
const row = JSON.parse(readFileSync(join(dir, name), 'utf8')) as { commit?: string; imageDigest?: string };
|
|
79
|
+
if (commit && row.commit !== commit) return { imageDigest: null };
|
|
80
|
+
return { imageDigest: row.imageDigest ?? null };
|
|
81
|
+
} catch { return { imageDigest: null }; }
|
|
82
|
+
});
|
|
83
|
+
} catch { return []; }
|
|
26
84
|
}
|
|
27
85
|
|
|
28
86
|
/** G1: a second measurement of only the failed files on the very same release commit.
|
|
@@ -172,10 +230,22 @@ export function planPartialRegate(input: { version: string; priorCommit: string;
|
|
|
172
230
|
closure?: (changedCode: string[]) => ClosureVerdict;
|
|
173
231
|
/** Tracked at the tip — a deleted changed test is not re-run (nothing to run); a deleted prior-failure file is a full
|
|
174
232
|
* gate (its failure can be neither re-measured nor carried). Without it every changed test is planned. */
|
|
175
|
-
existsAtTip?: (file: string) => boolean
|
|
233
|
+
existsAtTip?: (file: string) => boolean;
|
|
234
|
+
/** Executed Pod shard imageID digests from the prior full gate. A Job image ref/tag is not this field. */
|
|
235
|
+
priorShards?: readonly PartialPlanShardImage[];
|
|
236
|
+
/** Executed Pod shard imageID digests of the current sweep, when already measured. */
|
|
237
|
+
currentShards?: readonly PartialPlanShardImage[];
|
|
238
|
+
/** Directory of prior full-gate `pod-N.json` rows; collected when `priorShards` is omitted. */
|
|
239
|
+
priorCutLogs?: string;
|
|
240
|
+
/** Directory of current-sweep `pod-N.json` rows; collected when `currentShards` is omitted. */
|
|
241
|
+
currentCutLogs?: string }):
|
|
176
242
|
{ ok: true; plan: PartialPlan; closure?: { reached: number; opaque: number } } | { ok: false; reason: string } {
|
|
177
243
|
if (!/^[0-9a-f]{40}$/i.test(input.priorCommit) || !/^[0-9a-f]{40}$/i.test(input.forCommit)) return { ok: false, reason: 'commit is not a full sha' };
|
|
178
244
|
if (input.priorCommit === input.forCommit) return { ok: false, reason: 'no new commit since the prior gate' };
|
|
245
|
+
const priorShards = input.priorShards ?? (input.priorCutLogs ? collectExecutedPodShardImages(input.priorCutLogs, input.priorCommit) : undefined);
|
|
246
|
+
const currentShards = input.currentShards ?? (input.currentCutLogs ? collectExecutedPodShardImages(input.currentCutLogs, input.forCommit) : undefined);
|
|
247
|
+
const imageIdentity = priorShards ? partialPlanImageDigestsMatch(priorShards, currentShards) : undefined;
|
|
248
|
+
if (imageIdentity && imageIdentity.reuse === 0) return { ok: false, reason: imageIdentity.reason };
|
|
179
249
|
const source = input.changedFiles.filter((file) => !TEST_FILE.test(file) && !isInert(file));
|
|
180
250
|
const list = (files: string[]) => `${files.slice(0, 5).join(', ')}${files.length > 5 ? ` (+${files.length - 5})` : ''}`;
|
|
181
251
|
// Only code is followed through the closure: a changed fixture, JSON, lockfile, config or script is a full gate.
|
|
@@ -204,8 +274,12 @@ export function planPartialRegate(input: { version: string; priorCommit: string;
|
|
|
204
274
|
// but it changes the measured suite and must not masquerade as a carry.
|
|
205
275
|
if (!files.length && (!input.changedFiles.length || input.changedFiles.some((file) => !isInert(file))))
|
|
206
276
|
return { ok: false, reason: 'nothing to re-run (not a docs-only append)' };
|
|
277
|
+
const shardImageDigests = imageIdentity?.reuse === 1
|
|
278
|
+
? shardExecutedDigests(priorShards!).filter((digest): digest is string => !!digest)
|
|
279
|
+
: undefined;
|
|
207
280
|
return { ok: true, plan: { ...(!files.length ? { kind: 'carry' as const } : {}), version: input.version, priorCommit: input.priorCommit, forCommit: input.forCommit, files,
|
|
208
|
-
priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors]
|
|
281
|
+
priorFailures: [...input.priorFailures], priorErrors: [...input.priorErrors],
|
|
282
|
+
...(shardImageDigests ? { shardImageDigests } : {}) }, ...(closure ? { closure } : {}) };
|
|
209
283
|
}
|
|
210
284
|
|
|
211
285
|
export function writePartialPlan(root: string, plan: PartialPlan): string {
|
|
@@ -259,6 +333,11 @@ export function readPartialPlanResult(roots: readonly string[], version: string,
|
|
|
259
333
|
catch { throw new Error(`invalid gate partial plan: ${path}`); }
|
|
260
334
|
if (failureFiles.some((file) => !rerun.has(file))) throw new Error(`invalid gate partial plan (prior failure not re-run): ${path}`);
|
|
261
335
|
if (raw.forCommit !== commit) { fallbackReason = 'plan-commit-mismatch'; continue; }
|
|
336
|
+
if (raw.shardImageDigests !== undefined) {
|
|
337
|
+
if (!Array.isArray(raw.shardImageDigests)) throw new Error(`invalid gate partial plan: ${path}`);
|
|
338
|
+
const identity = planImageDigestDecision(raw.shardImageDigests);
|
|
339
|
+
if (identity.reuse === 0) { fallbackReason = identity.reason; continue; }
|
|
340
|
+
}
|
|
262
341
|
return { plan: raw as PartialPlan, fallbackReason: null };
|
|
263
342
|
}
|
|
264
343
|
return { plan: null, fallbackReason };
|
|
@@ -32,6 +32,41 @@ export type GatePrewarmPlan =
|
|
|
32
32
|
| { action: 'prepare-mirror'; cutSha: string; lockHash: string }
|
|
33
33
|
| { action: 'start-worker'; cutSha: string; lockHash: string; slotAfter: number };
|
|
34
34
|
|
|
35
|
+
/** A cut observation names the intended gate profile without granting a Pod slot. */
|
|
36
|
+
export function planGatePrewarmCutShadow(input: GatePrewarmInput | { cutSha: string }, warmMemberCount: number | null):
|
|
37
|
+
{ profile: 'gate'; transition: 'shadow'; plan: GatePrewarmPlan; reason?: 'warm-members-exceed-occupied' } {
|
|
38
|
+
const shadow = { profile: 'gate' as const, transition: 'shadow' as const };
|
|
39
|
+
if (!('nowMs' in input) || warmMemberCount === null) {
|
|
40
|
+
return { ...shadow, plan: { action: 'defer', reason: 'unmeasured' } };
|
|
41
|
+
}
|
|
42
|
+
if (input.occupiedPods !== null && warmMemberCount > input.occupiedPods) {
|
|
43
|
+
return { ...shadow, plan: { action: 'defer', reason: 'unmeasured' }, reason: 'warm-members-exceed-occupied' };
|
|
44
|
+
}
|
|
45
|
+
return { ...shadow, plan: planGatePrewarm(input) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type WarmMemberSnapshot = Record<string, readonly unknown[]>;
|
|
49
|
+
|
|
50
|
+
/** Compare the same observed cut on both sides of a read-only profile decision. */
|
|
51
|
+
export function observeGatePrewarmCutShadow(input: GatePrewarmInput | { cutSha: string },
|
|
52
|
+
readWarmMembers: () => WarmMemberSnapshot | null, readPlacement: () => Record<string, number>) {
|
|
53
|
+
const placementBefore = readPlacement();
|
|
54
|
+
const membersBefore = readWarmMembers();
|
|
55
|
+
const memberCountBefore = membersBefore ? Object.values(membersBefore).reduce((n, rows) => n + rows.length, 0) : null;
|
|
56
|
+
const shadow = planGatePrewarmCutShadow(input, memberCountBefore);
|
|
57
|
+
const membersAfter = readWarmMembers();
|
|
58
|
+
const placementAfter = readPlacement();
|
|
59
|
+
const memberCountAfter = membersAfter ? Object.values(membersAfter).reduce((n, rows) => n + rows.length, 0) : null;
|
|
60
|
+
const stable = membersBefore !== null && membersAfter !== null
|
|
61
|
+
&& JSON.stringify(membersBefore) === JSON.stringify(membersAfter)
|
|
62
|
+
&& JSON.stringify(placementBefore) === JSON.stringify(placementAfter);
|
|
63
|
+
if (!stable) return { profile: 'gate' as const, transition: 'shadow' as const, status: 'unmeasured' as const,
|
|
64
|
+
plan: { action: 'defer' as const, reason: 'unmeasured' as const }, reason: 'warm-members-unmeasured-or-changed' as const,
|
|
65
|
+
memberCountBefore, memberCountAfter, membersBefore, membersAfter, placementBefore, placementAfter };
|
|
66
|
+
return { ...shadow, status: shadow.plan.action === 'defer' && shadow.plan.reason === 'unmeasured' ? 'unmeasured' as const : 'observed' as const,
|
|
67
|
+
memberCountBefore, memberCountAfter, membersBefore, membersAfter, placementBefore, placementAfter };
|
|
68
|
+
}
|
|
69
|
+
|
|
35
70
|
const count = (value: number | null): value is number =>
|
|
36
71
|
value !== null && Number.isSafeInteger(value) && value >= 0;
|
|
37
72
|
|
|
@@ -152,8 +152,10 @@ export function planHardRehearsalRadius(input: { root: string; repo: string; ver
|
|
|
152
152
|
const planned = planPartialRegate({ version: input.version, priorCommit: stamp.sha, forCommit: input.forCommit,
|
|
153
153
|
changedFiles: effective, priorFailures: failures.failures, priorErrors: failures.errors ?? [],
|
|
154
154
|
existsAtTip: (file) => tree.files.includes(file),
|
|
155
|
-
closure: (code) => testsReachingChanged(tree, code, tests)
|
|
156
|
-
|
|
155
|
+
closure: (code) => testsReachingChanged(tree, code, tests),
|
|
156
|
+
priorCutLogs: join(dir, 'gate-logs', 'cut') });
|
|
157
|
+
if (!planned.ok && (effective.length || planned.reason.startsWith('executed-pod-image-digest-')))
|
|
158
|
+
return full(planned.reason);
|
|
157
159
|
let fileSet: string[];
|
|
158
160
|
let base: PartialPlan;
|
|
159
161
|
if (planned.ok) {
|
|
@@ -22,7 +22,7 @@ const INTRO = 'The following issues are known in this release.';
|
|
|
22
22
|
const resolved = /\b(?:fixed|resolved|no longer|has been addressed|is addressed|was addressed)\b/i;
|
|
23
23
|
const unsafe = /[^\x20-\x7e]|#\d+|\/Users\/|\.test\.ts\b|\[(?:TC|MK|OP|UX|S|T|F|O)\]|\b(?:TC|MK|OP|UX)\s+track\b|\b(?:PR|pull request)\s*\d+\b|\b(?:scripts|src|test)\/\S+|\bfile:\/\/|(?<![\w:/])\/(?!\/)[\w.-]+(?:\/[\w.-]+)*|\b[A-Z]:\\(?:[^\s\\]+\\)*[^\s\\]+|\b(?:RFC|HANDOFF|MANUAL)-/i;
|
|
24
24
|
|
|
25
|
-
type Issue = { id: string; title?: string; evidence?: string; note?: string };
|
|
25
|
+
type Issue = { id: string; title?: string; evidence?: string; knownIssue?: string; note?: string };
|
|
26
26
|
|
|
27
27
|
// Accepted regressions with the same public note describe one issue, even if several gates recorded it.
|
|
28
28
|
function issueGroup(issue: Issue, checklistIssues: ReadonlySet<Issue>): string {
|
|
@@ -62,9 +62,9 @@ function generatedBullets(raw: string, sourceIds: string[]): string[] {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function coversIssue(bullet: string, issue: Issue, others: Issue[]): boolean {
|
|
65
|
-
const source = issue.
|
|
65
|
+
const source = issue.knownIssue ?? issue.note ?? '';
|
|
66
66
|
const words = source.toLowerCase().match(/[a-z]{5,}/g) ?? [];
|
|
67
|
-
const otherWords = new Set(others.flatMap((other) => ((other.
|
|
67
|
+
const otherWords = new Set(others.flatMap((other) => ((other.knownIssue ?? other.note ?? '').toLowerCase().match(/[a-z]{5,}/g) ?? []).map((word) => word.slice(0, 5))));
|
|
68
68
|
const publicWords = new Set((bullet.toLowerCase().match(/[a-z]{5,}/g) ?? []).map((word) => word.slice(0, 5)));
|
|
69
69
|
const distinctive = [...new Set(words.map((word) => word.slice(0, 5)))].filter((word) => !otherWords.has(word));
|
|
70
70
|
const negative = /\b(?:not|never|no|cannot|can't|doesn't|don't|won't|fails? to|isn't|aren't)\b/i;
|
|
@@ -130,7 +130,9 @@ export function runKnownIssues(context: GraphContext = readGraphContext(), run:
|
|
|
130
130
|
if (context.outputs.docs?.branch !== `release-docs/${version}`) throw new Error('docs branch/version mismatch');
|
|
131
131
|
const notes = join(worktree, 'release/public/docs/releases', `${version}.md`);
|
|
132
132
|
if (!existsSync(notes)) throw new Error(`release notes missing: ${notes}`);
|
|
133
|
-
|
|
133
|
+
// A checklist title is an internal task label, not public issue copy. Missing dedicated copy
|
|
134
|
+
// means no public note row is generated for that checklist item.
|
|
135
|
+
const checklist = issues(context.outputs['checklist-gate']?.knownIssues, 'checklist').filter((issue) => typeof issue.knownIssue === 'string' && issue.knownIssue.trim()).map((issue) => ({ ...issue, title: issue.knownIssue!.trim() }));
|
|
134
136
|
const accepted = issues(context.input.acceptedRegressions, 'accepted');
|
|
135
137
|
const approved0233Batch = version === '0.2.33' && accepted.length === APPROVED_0233_INPUT.length
|
|
136
138
|
&& new Set(accepted.map((issue) => issue.id)).size === accepted.length
|