elanous 0.2.21 → 0.2.23
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/NOTICE +7 -0
- package/README.md +32 -22
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-111cabe4d1fd69ae.js → page-6168a7c43e6ef8f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
- package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
- package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +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 +24 -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 +24 -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/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
- package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
- package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
- package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
- package/catalog/models/openai/gpt-6-astra.yaml +6 -0
- package/catalog/models/openai/gpt-6-luna.yaml +6 -0
- package/catalog/models/openai/gpt-6-sol.yaml +6 -0
- package/graphs/catalog/catalog.yaml +1 -1
- package/graphs/drafts/recipes.yaml +2 -2
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -0
- package/graphs/release/recipes.yaml +1 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/release-rehearsal/recipes.yaml +12 -0
- package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
- package/graphs/test-diet/recipes.yaml +3 -0
- package/graphs/test-diet/test-diet.yaml +3 -1
- package/package.json +4 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +10 -1
- package/scripts/f-session-monitor.ts +69 -0
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/hq/standby-snapshot.ts +7 -3
- package/scripts/knowledge-compress.ts +11 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/nightly-docops.ts +90 -3
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +73 -7
- package/scripts/release-loop/gate-wall.ts +208 -0
- package/scripts/release-loop/known-issues-node.ts +53 -8
- package/scripts/release-loop/publish-at.ts +14 -0
- package/scripts/release-loop/publish-node.ts +17 -2
- package/scripts/release-loop/resume-release.ts +34 -4
- package/scripts/release-loop/resume.ts +53 -0
- package/scripts/release-loop/shard-plan.ts +3 -11
- package/scripts/release-loop/tui-node-checks.ts +22 -0
- package/scripts/release-loop/unattended-release.ts +8 -1
- package/scripts/research-coo-admin-dates.ts +39 -0
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/skills/public-check.ts +7 -2
- package/scripts/smart-merge/resync-shadow.ts +5 -3
- package/scripts/test-diet/lib.ts +81 -1
- package/scripts/test-diet/node.ts +48 -2
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +8 -4
- package/scripts/verify-coo-admin-evidence.ts +83 -0
- package/src/acp/client.ts +4 -2
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +14 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-env/profile.ts +25 -5
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +27 -13
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/review-loop.ts +33 -5
- package/src/agent-mission/supervisor-metrics.ts +17 -2
- package/src/agent-substrate/acp-reviewer.ts +25 -9
- package/src/agent-substrate/pr-reviewer.ts +175 -32
- package/src/agent-substrate/review-intent.ts +106 -5
- package/src/agent-substrate/self-review-cli.ts +111 -16
- package/src/agent-substrate/shard-boundary-intent.ts +92 -26
- package/src/ask-user-question/pending-questions.ts +8 -2
- package/src/autopilot/build/llm-conflict-merge.ts +238 -20
- package/src/autopilot/codebase-grounding.ts +44 -0
- package/src/autopilot/llm-control-brain.ts +13 -1
- package/src/autopilot/mission-codebase-gate.ts +8 -77
- package/src/autopilot/pr-manager.ts +30 -11
- package/src/away/release-watch.ts +47 -8
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +123 -22
- package/src/chat/index.ts +13 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/brief-cli.ts +46 -22
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/config-classify.ts +83 -0
- package/src/cli/control-cli.ts +14 -0
- package/src/cli/decisions-cli.ts +26 -16
- package/src/cli/log-event-names.ts +3 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/logs-model-input.ts +1 -1
- package/src/cli/mcp-login.ts +111 -37
- package/src/cli/plugin-cli.ts +21 -1
- package/src/cli/pod-cli.ts +26 -0
- package/src/cli/pr-cli.ts +94 -9
- package/src/cli/pr-land-overlap-evidence.ts +131 -0
- package/src/cli/release-cli.ts +74 -15
- package/src/cli/self-update.ts +173 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +241 -28
- package/src/connectors/types.ts +6 -6
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +29 -0
- package/src/context-bus/coord-events.ts +32 -4
- package/src/context-bus/long-term-memory.ts +26 -7
- package/src/context-bus/nightly-condense.ts +170 -21
- package/src/control/control-status.ts +87 -0
- package/src/control-plane/light-member.ts +5 -3
- package/src/control-plane/member.ts +172 -7
- package/src/core-turn/run-goal-loop.ts +108 -3
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +27 -5
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -3
- package/src/dashboard/stale-install-check.ts +13 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +159 -0
- package/src/debug/log.ts +52 -17
- package/src/decisions/decision-cards.ts +20 -1
- package/src/decisions/decision-ledger.ts +11 -8
- package/src/decisions/web-push-decision-cards.ts +19 -3
- package/src/discord-self-message.ts +2 -2
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-dates.evidence.json +876 -0
- package/src/domains/coo-admin-tool.ts +75 -14
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/ops-status.ts +53 -0
- package/src/domains/outbound-alert.ts +41 -7
- package/src/domains/release-tool.ts +119 -10
- package/src/domains/schedule-registry.ts +10 -7
- package/src/domains/schedule-runner.ts +1 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/elanous-daemon.ts +3 -3
- package/src/exec-requests/planner.ts +6 -0
- package/src/execution-loop/launch-gate.ts +1 -1
- package/src/expression/i18n/messages.en.ts +5 -0
- package/src/expression/i18n/messages.ja.ts +5 -0
- package/src/expression/i18n/messages.ko.ts +5 -0
- package/src/expression/i18n/messages.zh.ts +5 -0
- package/src/expression/i18n/types.ts +8 -0
- package/src/github/pr-labels.ts +1 -0
- package/src/graph-kinds/registry.ts +6 -6
- package/src/graph-runner/graph-cli.ts +34 -2
- package/src/graph-runner/graph-run-api.ts +7 -0
- package/src/graph-runner/graph-tick.ts +73 -12
- package/src/graph-runner/runner.ts +94 -13
- package/src/graph-unify/wf-to-graph.ts +79 -0
- package/src/graph-wizard/generate.ts +34 -2
- package/src/graph-wizard/steps.ts +13 -0
- package/src/harness/dispatch-backpressure.ts +259 -0
- package/src/harness/harness-cli-command.ts +227 -50
- package/src/harness/harness-queue.ts +58 -14
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-substrate-default.ts +72 -1
- package/src/harness/launch-advice.ts +23 -0
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +114 -18
- package/src/index.ts +199 -71
- package/src/intake-plane/collect-github.ts +19 -1
- package/src/intake-plane/digest.ts +45 -20
- package/src/intake-plane/lens.ts +36 -8
- package/src/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +41 -0
- package/src/knowledge/conclusion-compress.ts +93 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/know-find.ts +9 -2
- package/src/knowledge/query.ts +20 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-provider.ts +175 -0
- package/src/llm/bedrock.ts +345 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm.ts +332 -51
- package/src/loops/budget.ts +150 -0
- package/src/loops/neighbor-runtime.ts +88 -0
- package/src/loops/orchestrator/author-depth.ts +29 -11
- package/src/loops/orchestrator/overlap.ts +7 -1
- package/src/loops/orchestrator/resync-shadow.ts +1 -1
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/tick.ts +35 -2
- package/src/loops/orchestrator/traffic.ts +6 -80
- package/src/loops/registry.ts +5 -0
- package/src/market/publish.ts +17 -1
- package/src/market/signed-index.ts +42 -0
- package/src/maturity/feature-maturity.ts +2 -1
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +48 -4
- package/src/models/prompts.ts +22 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +204 -15
- package/src/mss/logging/redaction.ts +17 -0
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/consult-requests.ts +7 -10
- package/src/nexus/api/discord-trigger-bot.ts +6 -3
- package/src/nexus/api/draft-metrics.ts +22 -8
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/graph-peer-edit.ts +77 -0
- package/src/nexus/api/graph-wizard-api.ts +9 -1
- package/src/nexus/api/graphs-api.ts +145 -7
- package/src/nexus/api/http-server.ts +101 -8
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/plugins-market.ts +24 -0
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +13 -2
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/oauth/claude-pty-maturity.ts +24 -0
- package/src/oauth/codex-account-rotation.ts +16 -18
- package/src/oauth/codex-account-store.ts +134 -5
- package/src/oauth/fallback-chain.ts +50 -15
- package/src/onboarding.ts +2 -1
- package/src/plugins/adapters/claude-package.ts +4 -12
- package/src/plugins/core/capability-policy.ts +141 -0
- package/src/plugins/core/host.ts +21 -8
- package/src/plugins/core/manifest.ts +19 -2
- package/src/plugins/core/trust-store.ts +15 -0
- package/src/plugins/core/types.ts +12 -0
- package/src/plugins/install/market-fetch.ts +68 -16
- package/src/plugins/install/plugin-install.ts +187 -16
- package/src/plugins/maker/market-bundle.ts +9 -0
- package/src/plugins/maker/plugin-maker.ts +32 -21
- package/src/plugins/maker/wizard-generate.ts +87 -9
- package/src/policy/llm-policy.ts +24 -6
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +10 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-enhance/enhance.ts +46 -5
- package/src/prompt-library/family-prompt-coverage.ts +1 -0
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
- package/src/registry/loader.ts +6 -1
- package/src/release-loop/checklist-board.ts +27 -0
- package/src/release-loop/checklist.ts +62 -9
- package/src/release-loop/feature-store.ts +3 -0
- package/src/release-loop/gate-shards.ts +48 -4
- package/src/release-loop/landed-to-green.ts +81 -0
- package/src/release-loop/light-rc.ts +11 -1
- package/src/release-loop/merged-pr-checklist.ts +10 -0
- package/src/release-loop/placement.ts +91 -22
- package/src/release-loop/rehearsal.ts +317 -0
- package/src/release-loop/release-schedule.ts +13 -1
- package/src/release-loop/rubric-types.ts +1 -0
- package/src/release-loop/rubric.ts +2 -2
- package/src/retro/daily.ts +23 -9
- package/src/seat-address/seat-address.ts +1 -0
- package/src/seat-loop/seat-loop.ts +208 -21
- package/src/seat-loop/seat-report.ts +29 -1
- package/src/seat-loop/traffic-signal.ts +44 -0
- package/src/self-dev/ask-launch-flow.ts +2 -2
- package/src/self-dev/dev-cli.ts +157 -11
- package/src/self-dev/dev-pipeline.ts +18 -1
- package/src/self-dev/draft-residue.ts +463 -0
- package/src/self-dev/draft-sweep.ts +195 -17
- package/src/self-dev/draft-triage-rules.ts +27 -1
- package/src/self-dev/launch-preflight-text.ts +549 -0
- package/src/self-dev/launch-preflight.ts +10 -545
- package/src/self-dev/orchestrate-cli.ts +57 -2
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +9 -133
- package/src/self-dev/review-provider-fallback.ts +179 -0
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +8 -23
- package/src/self-dev/run-types.ts +178 -0
- package/src/self-dev/shard-aggregate.ts +61 -13
- package/src/self-dev/shard-plan.ts +5 -1
- package/src/self-dev/shard-run.ts +23 -5
- package/src/self-dev/supervisor-verdict-edges.ts +2 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- package/src/self-implement/gate-baseline-reap.ts +157 -0
- package/src/self-implement/gate-baseline.ts +78 -16
- package/src/self-implement/gate-cli.ts +12 -2
- package/src/self-implement/gate-remote.ts +17 -6
- package/src/self-implement/goal-author.ts +24 -4
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +4 -0
- package/src/self-implement/harness-policy-gates.ts +7 -5
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/host-regate.ts +148 -43
- package/src/self-implement/l8-merge-queue.ts +147 -13
- package/src/self-implement/merge-train.ts +131 -0
- package/src/self-implement/off-diff-evidence.ts +9 -0
- package/src/self-implement/orchestrator.ts +201 -43
- package/src/self-implement/review-finding-recurrence.ts +28 -0
- package/src/self-implement/rework-policy.ts +2 -1
- package/src/self-implement/round-summary-card.ts +63 -0
- package/src/self-implement/run-ledger.ts +4 -3
- package/src/self-implement/run-step-projection.ts +147 -0
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/seams.ts +41 -6
- package/src/self-implement/self-implement-cli.ts +6 -0
- package/src/self-implement/train-gate-remote.ts +158 -0
- package/src/session-runtime/index.ts +10 -1
- package/src/session-runtime/retry-api.ts +11 -1
- package/src/shell-env-bootstrap.ts +19 -4
- package/src/skills/gift-install.ts +119 -0
- package/src/skills/runner.ts +59 -2
- package/src/skills/skill-feedback.ts +31 -1
- package/src/skills/skill-tier.ts +1 -0
- package/src/smart-wizard/capability-index.ts +231 -0
- package/src/smart-wizard/rung.ts +74 -0
- package/src/steward/launch.ts +20 -9
- package/src/steward/triage.ts +29 -10
- package/src/storage/file-lock.ts +40 -4
- package/src/task-agent/actions.ts +4 -0
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/completion-evidence.ts +31 -3
- package/src/task-agent/cover.ts +61 -0
- package/src/task-agent/judge.ts +4 -3
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +133 -0
- package/src/task-agent/live-moves.ts +222 -12
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +297 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/shadow.ts +118 -7
- package/src/task-agent/task-hand.ts +138 -11
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +203 -28
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +11 -0
- package/src/telegram-commands.ts +8 -0
- package/src/telegram-project-command.ts +6 -0
- package/src/telegram-service.ts +5 -1
- package/src/telegram.ts +17 -4
- package/src/time/format.ts +13 -4
- package/src/tool-runtime/goal-author-runtime.ts +1 -0
- package/src/tool-runtime/self-cognition-catalog.ts +23 -0
- package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
- package/src/typecheck-ratchet.ts +2 -1
- package/src/user-config.ts +167 -28
- package/src/ux-sim/slash-menu-frames.ts +168 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-terminal/preview-tap-registry.ts +5 -2
- package/src/workflow-runtime/executor.ts +24 -2
- package/src/workflow-runtime/triggers/registry.ts +27 -0
- package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
- package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +0 -1
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-be8b4615c919e36c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
- package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +0 -1
- /package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_ssgManifest.js +0 -0
|
@@ -21,7 +21,7 @@ import { POD_BUN_CACHE_HOST_PATH, parseInstallSeconds, podBunCacheVolume } from
|
|
|
21
21
|
import { PodPoolScheduler, parsePodPool, checkPodPool } from '../../src/task-orchestrator/surfaces/pod-pool.js';
|
|
22
22
|
import { POD_INSTALL_SLOTS_DEFAULT, POD_INSTALL_SLOTS_HOST_PATH, installSlotScript } from '../../src/task-orchestrator/surfaces/pod-install-slots.js';
|
|
23
23
|
import { gateDepsInstallScript, parseGateDeps } from '../../src/task-orchestrator/surfaces/pod-gate-deps.js';
|
|
24
|
-
import { gateShardsPath, writeGateShards, type GateShard } from '../../src/release-loop/gate-shards.js';
|
|
24
|
+
import { gateShardsPath, recordGateShardsVerdict, writeGateShards, type GateShard } from '../../src/release-loop/gate-shards.js';
|
|
25
25
|
import { defaultKubectl } from '../../src/task-orchestrator/surfaces/self-implement-pod.js';
|
|
26
26
|
|
|
27
27
|
interface CommandResult { rc: number; output: string; passedIds?: string[]; stalledEnv?: Array<{ file: string; reason: 'no-output' }>; timedOut?: boolean }
|
|
@@ -75,6 +75,7 @@ export interface GateResult {
|
|
|
75
75
|
knownEnv: number;
|
|
76
76
|
knownEnvCleared: string[];
|
|
77
77
|
stalledEnv: Array<{ file: string; reason: 'no-output' | 'isolated-timeout'; local: 'passed' | 'failed' | 'timeout' }>;
|
|
78
|
+
rcNonzeroNoFailures: Array<{ file: string; rc: number; pass: number; baseline: 'same' | 'clean' | 'missing' }>;
|
|
78
79
|
baselineSource?: 'ledger' | 'instance' | 'cut-logs' | 'swept';
|
|
79
80
|
/** GATE-BASELINE-CACHE — isolated baseline files answered from the ledger (hits) or run now (misses). */
|
|
80
81
|
baselineCache?: { hits: number; misses: number };
|
|
@@ -460,6 +461,47 @@ function failuresOf(run: CommandResult, label: string): SweepFailures {
|
|
|
460
461
|
return { failures, errors: [...new Set(errors)].sort() };
|
|
461
462
|
}
|
|
462
463
|
|
|
464
|
+
/**
|
|
465
|
+
* «N pass · 0 fail · rc=1» from an isolated run is read as `rc-nonzero-no-failures` only when the summary is a complete,
|
|
466
|
+
* clean, single-file summary for the requested file (`Ran N≥1 tests across 1 file` · 0 fail · 0 error · no `(fail)` ·
|
|
467
|
+
* no unhandled error · pass = N · no other test-file header). Every other run is read exactly as before (`failuresOf`,
|
|
468
|
+
* which throws on the incomplete shapes, plus a failure-count/identified-name check).
|
|
469
|
+
*/
|
|
470
|
+
export function readIsolatedRun(run: CommandResult, label: string, file: string):
|
|
471
|
+
| { kind: 'read'; failures: string[]; errors: string[] }
|
|
472
|
+
| { kind: 'rc-nonzero-no-failures'; rc: number; pass: number } {
|
|
473
|
+
const output = stripPodRepoRoot(run.output.replace(/\x1b\[[0-9;]*[A-Za-z]/g, ''));
|
|
474
|
+
const ran = lastMatch(output, /Ran (\d+) tests? across (\d+) files?/);
|
|
475
|
+
// rc 1 only: other non-zero exits with a clean summary keep the established leaked-exit reading (clean) in failuresOf.
|
|
476
|
+
const cleanNonzero = run.rc === 1 && !!ran && Number(ran[1]) >= 1 && Number(ran[2]) === 1
|
|
477
|
+
&& summaryCount(output, 'fail') === 0
|
|
478
|
+
&& (Number.isNaN(summaryCount(output, 'error')) || summaryCount(output, 'error') === 0)
|
|
479
|
+
&& parseFailures(output).length === 0 && !/\(fail\)/.test(output)
|
|
480
|
+
&& !/Unhandled error between tests/.test(output);
|
|
481
|
+
if (!cleanNonzero) {
|
|
482
|
+
const read = failuresOf(run, label);
|
|
483
|
+
// Two (fail) lines folding into one id would undercount the file's failures: unreadable, not fewer.
|
|
484
|
+
const failCount = summaryCount(output, 'fail');
|
|
485
|
+
if (Number.isFinite(failCount) && read.failures.length !== failCount)
|
|
486
|
+
throw new Error(`${label} incomplete (rc=${run.rc}; failure attribution summary=${failCount}, identified=${read.failures.length})`);
|
|
487
|
+
return { kind: 'read', ...read };
|
|
488
|
+
}
|
|
489
|
+
// Bun's file headers, when present, must identify the requested file before the result is recorded or cached.
|
|
490
|
+
// Any test-file path counts: root-level (`other.test.ts:`), nested, or absolute (outside the stripped Pod root).
|
|
491
|
+
for (const raw of output.split(/\r?\n/)) {
|
|
492
|
+
// Any characters but `:` (unicode, spaces, @, +, …) — a header is `<path ending in .test/.spec.ts>:`.
|
|
493
|
+
const header = /^(?:\.\/)?([^\s:][^:]*?\.(?:test|spec)\.[cm]?[jt]sx?):/.exec(raw.trim());
|
|
494
|
+
if (header && header[1] !== file)
|
|
495
|
+
throw new Error(`${label} incomplete (rc=${run.rc}; isolated run attributed to another file: ${header[1]})`);
|
|
496
|
+
}
|
|
497
|
+
const pass = summaryCount(output, 'pass');
|
|
498
|
+
if (pass !== Number(ran![1]))
|
|
499
|
+
throw new Error(`${label} incomplete (rc=${run.rc}; pass=${Number.isNaN(pass) ? 'missing' : pass}; Ran=${ran![1]})`);
|
|
500
|
+
// Validate the requested file as well as the summary; only this one file can own the synthetic id.
|
|
501
|
+
fileOf(`${file} > [rc-nonzero]`);
|
|
502
|
+
return { kind: 'rc-nonzero-no-failures', rc: run.rc, pass };
|
|
503
|
+
}
|
|
504
|
+
|
|
463
505
|
class StalledPodShards extends Error {
|
|
464
506
|
constructor(readonly stalledShards: NonNullable<GateResult['stalledShards']>, readonly partialSummary: NonNullable<GateResult['partialSummary']>) {
|
|
465
507
|
super(`pod sweep incomplete: stalled shards ${stalledShards.map(({ shard }) => shard).join(', ')}`);
|
|
@@ -1149,7 +1191,7 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1149
1191
|
return baselineCommit(root, version);
|
|
1150
1192
|
};
|
|
1151
1193
|
const repo = resolve(opts.repo ?? process.cwd());
|
|
1152
|
-
const result: GateResult = { outcome: 'error', commit: opts.commit, introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], durationMs: 0 };
|
|
1194
|
+
const result: GateResult = { outcome: 'error', commit: opts.commit, introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: 0 };
|
|
1153
1195
|
let work: string | undefined;
|
|
1154
1196
|
let baseSnapshot = false;
|
|
1155
1197
|
let cutFailures: SweepFailures | undefined;
|
|
@@ -1345,12 +1387,15 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1345
1387
|
result.stalledEnv.push({ file, reason: 'isolated-timeout', local: 'timeout' });
|
|
1346
1388
|
continue;
|
|
1347
1389
|
}
|
|
1348
|
-
const
|
|
1390
|
+
const cutReading = cutCheck === undefined ? undefined : readIsolatedRun(cutCheck, `cut isolated ${file}`, file);
|
|
1391
|
+
const rcOnly = cutReading?.kind === 'rc-nonzero-no-failures' ? cutReading : undefined;
|
|
1392
|
+
const rcOnlyId = `${file} > [rc-nonzero]`;
|
|
1393
|
+
const isolatedCut: SweepFailures = cutReading === undefined
|
|
1349
1394
|
? { failures: cut.failures.filter((id) => fileOf(id) === file), errors: cut.errors.filter((id) => fileOf(id) === file) }
|
|
1350
|
-
:
|
|
1395
|
+
: cutReading.kind === 'read' ? cutReading : { failures: [], errors: [rcOnlyId] };
|
|
1351
1396
|
if (cutCheck !== undefined) remember({ commit: opts.commit, file, host: cacheHost, failures: isolatedCut.failures, errors: isolatedCut.errors, missing: false });
|
|
1352
1397
|
const reproduced = new Set([...isolatedCut.failures, ...isolatedCut.errors]);
|
|
1353
|
-
let candidates = diff.newFailures.filter((id) => fileOf(id) === file && reproduced.has(id));
|
|
1398
|
+
let candidates = rcOnly ? [rcOnlyId] : diff.newFailures.filter((id) => fileOf(id) === file && reproduced.has(id));
|
|
1354
1399
|
// GATE-INTRO-RECHECK — a new failure that is only bun's «timed out» shape gets one more isolated run with a generous
|
|
1355
1400
|
// per-test limit, on the same runner (node-b when the gate is remote). Passing there = flaky under load (warning);
|
|
1356
1401
|
// an assertion failure, a failure again, or a run that cannot be read stays introduced.
|
|
@@ -1382,7 +1427,9 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1382
1427
|
}
|
|
1383
1428
|
if (candidates.length === 0) continue;
|
|
1384
1429
|
let oldFailures: Set<string>;
|
|
1430
|
+
let baselineMissing = false;
|
|
1385
1431
|
const hit = baseCache.get(`${file}\0${cacheHost}`);
|
|
1432
|
+
if (hit?.missing) baselineMissing = true;
|
|
1386
1433
|
if (hit) {
|
|
1387
1434
|
cacheStats.hits++;
|
|
1388
1435
|
oldFailures = new Set([...hit.failures, ...hit.errors]);
|
|
@@ -1399,13 +1446,22 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1399
1446
|
const lookup = await runner.command('git', ['ls-tree', '--name-only', baseSha, '--', file], opts.remote ? baselineTree : repo);
|
|
1400
1447
|
if (lookup.rc !== 0 || lookup.output.trim()) throw new Error(`baseline isolated run incomplete: ${file}`);
|
|
1401
1448
|
oldFailures = new Set();
|
|
1449
|
+
baselineMissing = true;
|
|
1402
1450
|
remember({ commit: baseSha, file, host: cacheHost, failures: [], errors: [], missing: true });
|
|
1403
1451
|
} else {
|
|
1404
|
-
const
|
|
1452
|
+
const reading = readIsolatedRun(previous, `baseline isolated ${file}`, file);
|
|
1453
|
+
const prior: SweepFailures = reading.kind === 'read' ? reading : { failures: [], errors: [rcOnlyId] };
|
|
1454
|
+
if (reading.kind === 'rc-nonzero-no-failures') debug.log('release-loop.gate', 'isolated-rc-nonzero-no-failures',
|
|
1455
|
+
{ file, label: 'baseline isolated', rc: reading.rc, pass: reading.pass, baseline: 'same' });
|
|
1405
1456
|
oldFailures = new Set([...prior.failures, ...prior.errors]);
|
|
1406
1457
|
remember({ commit: baseSha, file, host: cacheHost, failures: prior.failures, errors: prior.errors, missing: false });
|
|
1407
1458
|
}
|
|
1408
1459
|
}
|
|
1460
|
+
if (rcOnly) {
|
|
1461
|
+
const baseline = oldFailures.has(rcOnlyId) ? 'same' : baselineMissing ? 'missing' : 'clean';
|
|
1462
|
+
result.rcNonzeroNoFailures.push({ file, rc: rcOnly.rc, pass: rcOnly.pass, baseline });
|
|
1463
|
+
debug.log('release-loop.gate', 'isolated-rc-nonzero-no-failures', { file, label: 'cut isolated', rc: rcOnly.rc, pass: rcOnly.pass, baseline });
|
|
1464
|
+
}
|
|
1409
1465
|
for (const id of candidates) {
|
|
1410
1466
|
if (oldFailures.has(id)) result.preexisting++;
|
|
1411
1467
|
else result.introduced.push(id);
|
|
@@ -1456,6 +1512,15 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
|
|
|
1456
1512
|
}
|
|
1457
1513
|
}
|
|
1458
1514
|
if (result.outcome !== 'error') debug.log('release-loop.gate', 'judged', { version: opts.version, commit: opts.commit, introduced: result.introduced.length, preexisting: result.preexisting });
|
|
1515
|
+
// GATE-LIVE-OBS-RC-WORDING ⓒ — the shards board says «판정 전» until this lands; then «새 실패 N» only (UX · gate-shards.ts).
|
|
1516
|
+
// Same ledger as the board's own writes (sweep's shardsFile). A write failure is logged and never changes the verdict.
|
|
1517
|
+
if (result.outcome !== 'error' && opts.pod) {
|
|
1518
|
+
const path = opts.ledgerRoot ? gateShardsPath(opts.version, opts.ledgerRoot) : gateShardsPath(opts.version);
|
|
1519
|
+
try {
|
|
1520
|
+
const written = recordGateShardsVerdict(path, { introduced: result.introduced.length, preexisting: result.preexisting });
|
|
1521
|
+
debug.log('release-loop.gate', 'shards-verdict', { version: opts.version, path, written, introduced: result.introduced.length, preexisting: result.preexisting });
|
|
1522
|
+
} catch (error) { debug.log('release-loop.gate', 'shards-verdict-write-failed', { path, error: String(error) }); }
|
|
1523
|
+
}
|
|
1459
1524
|
return result;
|
|
1460
1525
|
}
|
|
1461
1526
|
|
|
@@ -1464,6 +1529,7 @@ export function graphGateResult(result: GateResult, graph: boolean) {
|
|
|
1464
1529
|
verdict: result.outcome === 'ok' ? 'pass' as const : 'fail' as const,
|
|
1465
1530
|
summary: (result.partial ? `부분 재검 ${result.partial.files}파일(앞 게이트 ${result.partial.priorCommit.slice(0, 9)} 결과 이음) · ` : '')
|
|
1466
1531
|
+ (result.outcome === 'ok' ? `새 회귀 ${result.introduced.length} · 기존 ${result.preexisting} · 고침 ${result.fixed ?? '못 셈(기준선 미루기)'}` : `게이트 ${result.outcome}: ${result.error ?? result.introduced.length + ' new regressions'}`) + ` · 환경 알려진 실패 ${result.knownEnv}`
|
|
1532
|
+
+ (result.rcNonzeroNoFailures.length ? ` · ⚠ 종료코드만 비영 ${result.rcNonzeroNoFailures.length}` : '')
|
|
1467
1533
|
+ (result.loadFlaky?.length ? ` · ⚠ 부하 흔들림 ${result.loadFlaky.length}(시간 초과 꼴 · ${GATE_TIMEOUT_RECHECK_MS / 1000}s 재실행 통과 · 막지 않음)` : '')
|
|
1468
1534
|
+ (result.stalledEnv.length ? ` · 환경 멈춤 ${result.stalledEnv.length} (Pod 밖 통과 ${result.stalledEnv.filter((item) => item.local === 'passed').length})` : '') };
|
|
1469
1535
|
}
|
|
@@ -1535,7 +1601,7 @@ if (import.meta.main) {
|
|
|
1535
1601
|
version = opts.version;
|
|
1536
1602
|
result = await judgeGate(opts);
|
|
1537
1603
|
} catch (error) {
|
|
1538
|
-
result = { outcome: 'error', commit: '', introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], durationMs: Date.now() - start, error: String(error) };
|
|
1604
|
+
result = { outcome: 'error', commit: '', introduced: [], preexisting: 0, fixed: 0, knownEnv: 0, knownEnvCleared: [], stalledEnv: [], rcNonzeroNoFailures: [], durationMs: Date.now() - start, error: String(error) };
|
|
1539
1605
|
}
|
|
1540
1606
|
if (result.error) console.error(result.error);
|
|
1541
1607
|
debug.log('release-loop.gate', 'result', { version, outcome: result.outcome });
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// GATE-SPEED-P2 — measure one commit's gate wall clock without folding earlier attempts into retries.
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { readJunitFileSeconds } from './gate-method.js';
|
|
5
|
+
import { resolveGateLogDir } from './gate-timing.js';
|
|
6
|
+
|
|
7
|
+
type TimedPod = { name: string; start: number; end: number; durationMs: number; root: boolean };
|
|
8
|
+
export interface GateWallAttempt {
|
|
9
|
+
commit: string;
|
|
10
|
+
records: number;
|
|
11
|
+
roots: number;
|
|
12
|
+
retries: number;
|
|
13
|
+
wallMin: number;
|
|
14
|
+
rootWallMin: number | null;
|
|
15
|
+
retryTailMin: number | null;
|
|
16
|
+
overhead: { medianMin: number | null; p90Min: number | null; unmeasuredRoots: number };
|
|
17
|
+
}
|
|
18
|
+
export interface GateWallReport {
|
|
19
|
+
dir: string;
|
|
20
|
+
targetMin: number;
|
|
21
|
+
measured: boolean;
|
|
22
|
+
commit: string | null;
|
|
23
|
+
records: number;
|
|
24
|
+
roots: number;
|
|
25
|
+
retries: number;
|
|
26
|
+
wallMin: number | null;
|
|
27
|
+
wallSource: 'pod-records' | null;
|
|
28
|
+
rootWallMin: number | null;
|
|
29
|
+
retryTailMin: number | null;
|
|
30
|
+
overhead: GateWallAttempt['overhead'];
|
|
31
|
+
retryOnlyAttempts: number;
|
|
32
|
+
attempts: GateWallAttempt[];
|
|
33
|
+
shardsWallMin: number | null;
|
|
34
|
+
disagree: boolean;
|
|
35
|
+
unreadable: string[];
|
|
36
|
+
/** ✓ only when every pod record was read; a slower verdict is already certain. */
|
|
37
|
+
verdict: 'pass' | 'fail' | 'undetermined' | null;
|
|
38
|
+
/** Why shards.json was not compared although present (it carries no attempt identity). */
|
|
39
|
+
shardsSkipped: 'not-latest-attempt' | 'outside-attempt-window' | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const POD_JSON = /^pod-.+\.json$/;
|
|
43
|
+
const ROOT = /^pod-\d+\.json$/;
|
|
44
|
+
function median(values: number[]): number {
|
|
45
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
46
|
+
const mid = Math.floor(sorted.length / 2);
|
|
47
|
+
return sorted.length % 2 ? sorted[mid]! : (sorted[mid - 1]! + sorted[mid]!) / 2;
|
|
48
|
+
}
|
|
49
|
+
function spanMin(pods: TimedPod[]): number {
|
|
50
|
+
return (Math.max(...pods.map((p) => p.end)) - Math.min(...pods.map((p) => p.start))) / 60_000;
|
|
51
|
+
}
|
|
52
|
+
function attempt(dir: string, commit: string, pods: TimedPod[]): GateWallAttempt {
|
|
53
|
+
const roots = pods.filter((p) => p.root);
|
|
54
|
+
const overhead: number[] = [];
|
|
55
|
+
let unmeasuredRoots = 0;
|
|
56
|
+
for (const pod of roots) {
|
|
57
|
+
try {
|
|
58
|
+
const xml = readFileSync(join(dir, pod.name.replace(/\.json$/, '.junit.xml')), 'utf8');
|
|
59
|
+
const seconds = [...readJunitFileSeconds(xml).values()];
|
|
60
|
+
if (!seconds.length) { unmeasuredRoots++; continue; }
|
|
61
|
+
overhead.push((pod.durationMs - seconds.reduce((sum, s) => sum + s, 0) * 1000) / 60_000);
|
|
62
|
+
} catch { unmeasuredRoots++; }
|
|
63
|
+
}
|
|
64
|
+
const wall = spanMin(pods);
|
|
65
|
+
const rootWall = roots.length ? spanMin(roots) : null;
|
|
66
|
+
const sorted = overhead.sort((a, b) => a - b);
|
|
67
|
+
return {
|
|
68
|
+
commit, records: pods.length, roots: roots.length, retries: pods.length - roots.length,
|
|
69
|
+
wallMin: wall, rootWallMin: rootWall,
|
|
70
|
+
retryTailMin: rootWall === null ? null : wall - rootWall,
|
|
71
|
+
overhead: {
|
|
72
|
+
medianMin: sorted.length ? median(sorted) : null,
|
|
73
|
+
p90Min: sorted.length ? sorted[Math.ceil(sorted.length * 0.9) - 1]! : null,
|
|
74
|
+
unmeasuredRoots,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const SHARDS_WINDOW_SLACK_MS = 5 * 60_000;
|
|
80
|
+
/**
|
|
81
|
+
* shards.json is a snapshot of the latest attempt, not an archive of every commit, and has no attempt identity.
|
|
82
|
+
* A row is attributed to the attempt only when its root id is one of the attempt's roots AND
|
|
83
|
+
* a row starts inside the attempt's pod-record window (from 5 min before its first start to its last end) — a
|
|
84
|
+
* previous attempt's snapshot reusing `pod-0` started earlier and is rejected. The end is free: a longer
|
|
85
|
+
* snapshot is exactly the disagreement this report keeps.
|
|
86
|
+
*/
|
|
87
|
+
function shardsSpan(dir: string, rootNames: Set<string>, window: { start: number; end: number }): number | 'outside-attempt-window' | null {
|
|
88
|
+
try {
|
|
89
|
+
const file: unknown = JSON.parse(readFileSync(join(dir, 'shards.json'), 'utf8'));
|
|
90
|
+
if (!file || typeof file !== 'object' || !('shards' in file) || !Array.isArray(file.shards)) return null;
|
|
91
|
+
const rows = file.shards as unknown[];
|
|
92
|
+
if (!rows.length) return null;
|
|
93
|
+
const starts: number[] = [];
|
|
94
|
+
const ends: number[] = [];
|
|
95
|
+
for (const row of rows) {
|
|
96
|
+
if (!row || typeof row !== 'object' || !('id' in row) || typeof row.id !== 'string'
|
|
97
|
+
|| !rootNames.has(`${row.id}.json`)) return null;
|
|
98
|
+
const start = 'startedAt' in row && typeof row.startedAt === 'string' ? Date.parse(row.startedAt) : NaN;
|
|
99
|
+
const end = 'endedAt' in row && typeof row.endedAt === 'string' ? Date.parse(row.endedAt) : NaN;
|
|
100
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) return null;
|
|
101
|
+
if (start < window.start - SHARDS_WINDOW_SLACK_MS || start > window.end) return 'outside-attempt-window';
|
|
102
|
+
starts.push(start);
|
|
103
|
+
ends.push(end);
|
|
104
|
+
}
|
|
105
|
+
if (Math.max(...ends) < Math.min(...starts)) return null;
|
|
106
|
+
return (Math.max(...ends) - Math.min(...starts)) / 60_000;
|
|
107
|
+
} catch { return null; }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function gateWall(dir: string, opts: { commit?: string; targetMin?: number } = {}): GateWallReport {
|
|
111
|
+
const targetMin = opts.targetMin ?? 30;
|
|
112
|
+
if (!Number.isFinite(targetMin) || targetMin <= 0) throw new Error('target-min 은 양수여야 합니다');
|
|
113
|
+
const groups = new Map<string, TimedPod[]>();
|
|
114
|
+
const unreadable: string[] = [];
|
|
115
|
+
const names = existsSync(dir) && statSync(dir).isDirectory() ? readdirSync(dir).filter((n) => POD_JSON.test(n)).sort() : [];
|
|
116
|
+
for (const name of names) {
|
|
117
|
+
try {
|
|
118
|
+
const pod: unknown = JSON.parse(readFileSync(join(dir, name), 'utf8'));
|
|
119
|
+
if (!pod || typeof pod !== 'object' || !('commit' in pod) || !('durationMs' in pod)
|
|
120
|
+
|| typeof pod.commit !== 'string' || !pod.commit.trim()
|
|
121
|
+
|| typeof pod.durationMs !== 'number' || !Number.isFinite(pod.durationMs) || pod.durationMs < 0) {
|
|
122
|
+
unreadable.push(name); continue;
|
|
123
|
+
}
|
|
124
|
+
const end = statSync(join(dir, name)).mtimeMs;
|
|
125
|
+
if (!Number.isFinite(end)) { unreadable.push(name); continue; }
|
|
126
|
+
const group = groups.get(pod.commit) ?? [];
|
|
127
|
+
group.push({ name, start: end - pod.durationMs, end, durationMs: pod.durationMs, root: ROOT.test(name) });
|
|
128
|
+
groups.set(pod.commit, group);
|
|
129
|
+
} catch { unreadable.push(name); }
|
|
130
|
+
}
|
|
131
|
+
const ordered = [...groups].sort((a, b) => Math.max(...b[1].map((p) => p.end)) - Math.max(...a[1].map((p) => p.end)));
|
|
132
|
+
const matching = opts.commit === undefined ? ordered : ordered.filter(([commit]) => commit.startsWith(opts.commit!));
|
|
133
|
+
if (opts.commit !== undefined && matching.length > 1) throw new Error(`모호한 커밋 앞자리: ${opts.commit}`);
|
|
134
|
+
const chosen = matching.find(([, pods]) => pods.some((p) => p.root));
|
|
135
|
+
const attempts = ordered.map(([commit, pods]) => attempt(dir, commit, pods));
|
|
136
|
+
const selected = chosen && attempts.find((a) => a.commit === chosen[0]);
|
|
137
|
+
// The snapshot has no commit field. Only the latest recorded attempt can own it; require its root row IDs too.
|
|
138
|
+
const latest = chosen !== undefined && ordered[0]?.[0] === chosen[0];
|
|
139
|
+
const span = chosen && latest
|
|
140
|
+
? shardsSpan(dir, new Set(chosen[1].filter((p) => p.root).map((p) => p.name)),
|
|
141
|
+
{ start: Math.min(...chosen[1].map((p) => p.start)), end: Math.max(...chosen[1].map((p) => p.end)) }) : null;
|
|
142
|
+
const snapshot = typeof span === 'number' ? span : null;
|
|
143
|
+
const shardsWallMin = snapshot;
|
|
144
|
+
const hasShards = existsSync(join(dir, 'shards.json'));
|
|
145
|
+
const shardsSkipped = !hasShards || !chosen ? null : !latest ? 'not-latest-attempt' as const : span === 'outside-attempt-window' ? span : null;
|
|
146
|
+
const wallMin = selected?.wallMin ?? null;
|
|
147
|
+
const verdict = wallMin === null ? null : wallMin > targetMin ? 'fail' as const : unreadable.length ? 'undetermined' as const : 'pass' as const;
|
|
148
|
+
return {
|
|
149
|
+
dir, targetMin, measured: selected !== undefined, commit: selected?.commit ?? null,
|
|
150
|
+
records: selected?.records ?? 0, roots: selected?.roots ?? 0, retries: selected?.retries ?? 0,
|
|
151
|
+
wallMin: selected?.wallMin ?? null, wallSource: selected ? 'pod-records' : null,
|
|
152
|
+
rootWallMin: selected?.rootWallMin ?? null, retryTailMin: selected?.retryTailMin ?? null,
|
|
153
|
+
overhead: selected?.overhead ?? { medianMin: null, p90Min: null, unmeasuredRoots: 0 },
|
|
154
|
+
retryOnlyAttempts: attempts.filter((a) => a.roots === 0).length,
|
|
155
|
+
attempts, shardsWallMin,
|
|
156
|
+
disagree: snapshot !== null && chosen !== undefined && Math.abs(snapshot - spanMin(chosen[1])) > 5,
|
|
157
|
+
unreadable, verdict, shardsSkipped,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function formatGateWall(report: GateWallReport): string {
|
|
162
|
+
const number = (value: number | null) => value === null ? '못 잼' : `${value.toFixed(1)}분`;
|
|
163
|
+
if (!report.measured) return `게이트 벽시계 못 잼 · 목표 ≤${report.targetMin}분 판정 못 잼 · 루트 못 잼 · 재시도 꼬리 못 잼 · 조각 준비 중앙 못 잼`;
|
|
164
|
+
return [
|
|
165
|
+
`게이트 벽시계 ${number(report.wallMin)}(pod-records · 커밋 ${report.commit!.slice(0, 8)}) · 목표 ≤${report.targetMin}분 ${report.verdict === 'pass' ? '✓' : report.verdict === 'fail' ? '✗' : `판정 보류(못 읽은 기록 ${report.unreadable.length})`} · 루트 ${number(report.rootWallMin)} · 재시도 꼬리 ${number(report.retryTailMin)} · 조각 준비 중앙 ${number(report.overhead.medianMin)}`,
|
|
166
|
+
`커밋 ${report.commit} · 기록 ${report.records} · 루트 ${report.roots} · 재시도 ${report.retries} · 루트 없는 시도 ${report.retryOnlyAttempts} · 준비 p90 ${number(report.overhead.p90Min)} · 준비 못 잰 루트 ${report.overhead.unmeasuredRoots}`,
|
|
167
|
+
...(report.shardsWallMin === null ? [] : [`shards.json 벽시계 ${number(report.shardsWallMin)} · 기록 추정 ${number(report.wallMin)}${report.disagree ? ' · ⚠ 5분 초과 불일치' : ''}`]),
|
|
168
|
+
...(report.shardsSkipped ? [`shards.json 대조 생략 — 이 시도의 것인지 확인 못 함(${report.shardsSkipped})`] : []),
|
|
169
|
+
...(report.unreadable.length ? [`⚠ 못 읽은 기록 ${report.unreadable.length}: ${report.unreadable.slice(0, 3).join(', ')}`] : []),
|
|
170
|
+
].join('\n');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const GATE_WALL_USAGE = '사용법: bun scripts/release-loop/gate-wall.ts <version|dir> [--commit <sha>] [--target-min <n>] [--json]';
|
|
174
|
+
|
|
175
|
+
if (import.meta.main) {
|
|
176
|
+
const args = process.argv.slice(2);
|
|
177
|
+
let target: string | undefined;
|
|
178
|
+
let commit: string | undefined;
|
|
179
|
+
let targetMin: number | undefined;
|
|
180
|
+
let json = false;
|
|
181
|
+
let error: string | undefined;
|
|
182
|
+
for (let i = 0; i < args.length; i++) {
|
|
183
|
+
const arg = args[i]!;
|
|
184
|
+
if (arg === '--json') { json = true; continue; }
|
|
185
|
+
if (arg === '--commit' || arg === '--target-min') {
|
|
186
|
+
const value = args[++i];
|
|
187
|
+
if (!value || value.startsWith('-')) { error = `값이 없는 옵션: ${arg}`; break; }
|
|
188
|
+
if (arg === '--commit') commit = value;
|
|
189
|
+
else {
|
|
190
|
+
targetMin = Number(value);
|
|
191
|
+
if (!Number.isFinite(targetMin) || targetMin <= 0) { error = `잘못된 목표 분: ${value}`; break; }
|
|
192
|
+
}
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (arg.startsWith('-')) { error = `알 수 없는 옵션: ${arg}`; break; }
|
|
196
|
+
if (target) { error = `예상치 못한 인자: ${arg}`; break; }
|
|
197
|
+
target = arg;
|
|
198
|
+
}
|
|
199
|
+
if (error || !target) { console.error(`${error ?? '대상 경로 또는 버전이 필요합니다'}\n${GATE_WALL_USAGE}`); process.exit(2); }
|
|
200
|
+
try {
|
|
201
|
+
const report = gateWall(resolveGateLogDir(target), { commit, targetMin });
|
|
202
|
+
console.log(json ? JSON.stringify(report, null, 2) : formatGateWall(report));
|
|
203
|
+
if (!report.measured) process.exitCode = 1;
|
|
204
|
+
} catch (e) {
|
|
205
|
+
console.error(`${e instanceof Error ? e.message : String(e)}\n${GATE_WALL_USAGE}`);
|
|
206
|
+
process.exitCode = 2;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
|
|
4
|
+
import type { GraphRunState } from '../../src/graph-runner/runner.js';
|
|
3
5
|
import { join } from 'node:path';
|
|
4
6
|
import { emitNodeResult, readGraphContext, runCommand, type CommandRunner, type GraphContext } from './node-verdict.js';
|
|
5
7
|
|
|
@@ -64,6 +66,37 @@ function cleanBullet(text: string): string | null {
|
|
|
64
66
|
return line;
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
/** A waiver is copied verbatim into public notes, so reject internal or resolved claims before resuming. */
|
|
70
|
+
export function publicWaiverReason(text: string): string {
|
|
71
|
+
const bullet = cleanBullet(text);
|
|
72
|
+
if (!bullet || resolved.test(bullet) || !/[a-z]{3}/i.test(bullet)) throw new Error('unsafe public waiver reason');
|
|
73
|
+
return bullet;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function recordedWaivers(context: GraphContext, accepted: Issue[]): Issue[] {
|
|
77
|
+
const contextPath = process.env.ELANOUS_GRAPH_CONTEXT;
|
|
78
|
+
if (!contextPath || !/\.json\.contexts\/[1-9]\d*\.json$/.test(contextPath)) return [];
|
|
79
|
+
const raw = JSON.parse(readFileSync(contextPath, 'utf8')) as { graphId?: string; runId?: string; nodeId?: string };
|
|
80
|
+
if (raw.graphId !== 'release-loop' || raw.nodeId !== 'known-issues' || !raw.runId || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(raw.runId)) return [];
|
|
81
|
+
const statePath = join(effectiveInstanceRoot(), 'graph-runs', 'release-loop', `${raw.runId}.json`);
|
|
82
|
+
const visit = Number(contextPath.slice(contextPath.lastIndexOf('/') + 1, -'.json'.length));
|
|
83
|
+
if (contextPath !== join(`${statePath}.contexts`, `${visit}.json`)) return [];
|
|
84
|
+
const state = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
|
|
85
|
+
if (state.graphId !== 'release-loop' || state.runId !== raw.runId || state.path[visit - 1] !== 'known-issues' ||
|
|
86
|
+
JSON.stringify((state.input as { acceptedRegressions?: unknown })?.acceptedRegressions ?? []) !== JSON.stringify(context.input.acceptedRegressions ?? [])) return [];
|
|
87
|
+
return accepted.filter((issue) => {
|
|
88
|
+
if (!issue.id.startsWith('waive:')) return false;
|
|
89
|
+
const node = issue.id.slice('waive:'.length);
|
|
90
|
+
const index = state.path.indexOf(node);
|
|
91
|
+
const record = state.nodes[index];
|
|
92
|
+
const waiver = record?.waiver;
|
|
93
|
+
return index >= 0 && index < visit - 1 && record?.nodeId === node && waiver !== undefined && waiver.reason === issue.note &&
|
|
94
|
+
// The runner writes a waiver only over a failed executed node (releaseResumeWaiver); its exit may be 0 (outcome fail) or null (timeout).
|
|
95
|
+
record.ok === true && record.executed === false &&
|
|
96
|
+
context.outputs[node]?.verdict === 'waived' && context.outputs[node]?.reason === issue.note;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
67
100
|
function command(run: CommandRunner, program: string, args: string[], cwd?: string): string {
|
|
68
101
|
const result = run(program, args, cwd);
|
|
69
102
|
if (result.status !== 0) throw new Error(`${program} ${args[0]} failed: ${result.stderr || result.stdout}`);
|
|
@@ -85,13 +118,18 @@ export function runKnownIssues(context: GraphContext = readGraphContext(), run:
|
|
|
85
118
|
let bullets: string[];
|
|
86
119
|
let fallbackUsed = false;
|
|
87
120
|
const allIssues = [...checklist, ...accepted];
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
121
|
+
// The persisted failed-node waiver, not a claimed output or an ID prefix, is the public-note provenance.
|
|
122
|
+
const waiverIssues = recordedWaivers(context, accepted);
|
|
123
|
+
const modelIssues = allIssues.filter((issue) => !waiverIssues.includes(issue));
|
|
124
|
+
const sourceIds = modelIssues.map((issue) => issue.id);
|
|
125
|
+
const prompt = `Write public English release-note bullets for these known issues. Describe only user-visible impact; include a one-line workaround when available. No internal names, test paths, track names, PR numbers, or people. Each bullet must have at most two sentences. Return ONLY a JSON array with exactly one object {"id":"input ID","bullet":"English public sentence"} for each input, using each input ID exactly once. Do not include IDs in bullet text. Input: ${JSON.stringify({ checklist, acceptedRegressions: accepted.filter((issue) => !waiverIssues.includes(issue)) })}`;
|
|
126
|
+
let response: ReturnType<CommandRunner> = { status: 0, stdout: JSON.stringify({ reply: '[]' }), stderr: '' };
|
|
127
|
+
if (modelIssues.length) {
|
|
128
|
+
try {
|
|
129
|
+
response = run('elanous', ['--test', 'ask', '--json', prompt]);
|
|
130
|
+
} catch {
|
|
131
|
+
response = { status: 1, stdout: '', stderr: '' };
|
|
132
|
+
}
|
|
95
133
|
}
|
|
96
134
|
if (response.status !== 0) {
|
|
97
135
|
bullets = [FALLBACK];
|
|
@@ -105,7 +143,7 @@ export function runKnownIssues(context: GraphContext = readGraphContext(), run:
|
|
|
105
143
|
return FALLBACK;
|
|
106
144
|
}
|
|
107
145
|
if (resolved.test(safe)) throw new Error(`bullet for ${sourceIds[index]} claims the issue is resolved`);
|
|
108
|
-
if (!coversIssue(safe,
|
|
146
|
+
if (!coversIssue(safe, modelIssues[index]!, modelIssues.filter((_, otherIndex) => otherIndex !== index))) {
|
|
109
147
|
throw new Error(`bullet does not identify input ${sourceIds[index]}`);
|
|
110
148
|
}
|
|
111
149
|
return safe;
|
|
@@ -118,6 +156,13 @@ export function runKnownIssues(context: GraphContext = readGraphContext(), run:
|
|
|
118
156
|
throw new Error(`known issues coverage not verified: ${error instanceof Error ? error.message : String(error)}`);
|
|
119
157
|
}
|
|
120
158
|
}
|
|
159
|
+
// A waiver's supplied public impact must survive even when the model omits it or is unavailable.
|
|
160
|
+
for (const issue of waiverIssues) {
|
|
161
|
+
const bullet = cleanBullet(issue.note ?? '');
|
|
162
|
+
if (!bullet || resolved.test(bullet)) throw new Error(`unsafe public waiver reason for ${issue.id}`);
|
|
163
|
+
const publicBullet = /[.!?]$/.test(bullet) ? bullet : `${bullet}.`;
|
|
164
|
+
if (!bullets.includes(publicBullet)) bullets.push(publicBullet);
|
|
165
|
+
}
|
|
121
166
|
const original = readFileSync(notes, 'utf8');
|
|
122
167
|
const heading = /^## Known issues\s*$/m;
|
|
123
168
|
const match = heading.exec(original);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// RELEASE-PUBLISH-AT — the one validator for a promised publish time (CLI entry and the publish node share it).
|
|
2
|
+
|
|
3
|
+
/** `--publish-at` must be an offset-bearing ISO datetime; returns the refusal message, or null when valid. */
|
|
4
|
+
export function publishAtError(value: string): string | null {
|
|
5
|
+
const refused = '--publish-at requires an offset-bearing ISO datetime on a real calendar date';
|
|
6
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?(?:Z|[+-](\d{2}):(\d{2}))$/.exec(value);
|
|
7
|
+
if (!m || !Number.isFinite(Date.parse(value))) return refused;
|
|
8
|
+
const [y, mo, d, h, mi, sec = '0', oh = '0', om = '0'] = m.slice(1) as string[];
|
|
9
|
+
// Date.parse rolls 02-30 over into March; a promised publish day must be the day that was written.
|
|
10
|
+
const day = new Date(Date.UTC(Number(y), Number(mo) - 1, Number(d)));
|
|
11
|
+
if (day.getUTCFullYear() !== Number(y) || day.getUTCMonth() !== Number(mo) - 1 || day.getUTCDate() !== Number(d)) return refused;
|
|
12
|
+
if (Number(h) > 23 || Number(mi) > 59 || Number(sec) > 59 || Number(oh) > 23 || Number(om) > 59) return refused;
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
@@ -6,6 +6,7 @@ import { WARNING_ONLY } from './auto-approve-node.js';
|
|
|
6
6
|
import { beginLandingMerge, landingFreezeMessage } from '../../src/release-loop/landing-freeze.js';
|
|
7
7
|
import { debug } from '../../src/debug/log.js';
|
|
8
8
|
import { prereleaseKind } from './release-version.js';
|
|
9
|
+
import { publishAtError } from './publish-at.js';
|
|
9
10
|
import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandRunner } from './node-verdict.js';
|
|
10
11
|
|
|
11
12
|
export function publicNotes(markdown: string, pages: { pages: Array<{ id: string; slug?: string; source?: string }> }): string {
|
|
@@ -43,7 +44,8 @@ export function waitForAssets(run: CommandRunner, repo: string, tag: string, nam
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: string
|
|
47
|
+
export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: string,
|
|
48
|
+
clock: { now: () => number; sleep: (ms: number) => void } = { now: Date.now, sleep: Bun.sleepSync }) {
|
|
47
49
|
const context = readGraphContext();
|
|
48
50
|
const version = context.input.version;
|
|
49
51
|
// A measured automatic decision or the existing human approval must authorize publication.
|
|
@@ -69,6 +71,17 @@ export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: str
|
|
|
69
71
|
if (doc.status !== 0 || registry.status !== 0) throw new Error(`docs branch missing notes or pages: ${branch}`);
|
|
70
72
|
if (!doc.stdout.startsWith(`# ${version}\n`)) throw new Error('release notes version mismatch');
|
|
71
73
|
const body = labelPrerelease(version, publicNotes(doc.stdout, JSON.parse(registry.stdout)));
|
|
74
|
+
if (context.input.publishAt !== undefined) {
|
|
75
|
+
const at = context.input.publishAt;
|
|
76
|
+
if (typeof at !== 'string' || publishAtError(at) !== null) {
|
|
77
|
+
throw new Error('invalid publishAt in release run input');
|
|
78
|
+
}
|
|
79
|
+
const deadline = Date.parse(at);
|
|
80
|
+
while (clock.now() < deadline) {
|
|
81
|
+
const remaining = deadline - clock.now();
|
|
82
|
+
clock.sleep(Math.min(remaining, 60_000));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
72
85
|
const dir = mkdtempSync(join(tmpdir(), 'release-publish-notes-'));
|
|
73
86
|
try {
|
|
74
87
|
const file = join(dir, 'notes.md');
|
|
@@ -83,7 +96,9 @@ export function runPublish(run: CommandRunner = runCommand, prodFreezeRoot?: str
|
|
|
83
96
|
if (context.input.forceFreeze !== true) return { outcome: 'fail' as const, verdict: 'fail' as const, summary: `publish blocked: ${landingFreezeMessage(frozen)}` };
|
|
84
97
|
}
|
|
85
98
|
let published: ReturnType<typeof run>;
|
|
86
|
-
|
|
99
|
+
// The graph recipe no longer bounds this node (it may wait for publishAt), so the irreversible publication itself
|
|
100
|
+
// keeps the former 30-minute bound on every run — with or without publishAt.
|
|
101
|
+
try { published = run('bun', ['bin/elanous.mjs', 'release', 'publish', '--dir', out, '--notes-file', file, '--yes', '--json'], undefined, 1_800_000); }
|
|
87
102
|
finally { landing.end(); }
|
|
88
103
|
if (published.stderr) process.stderr.write(published.stderr);
|
|
89
104
|
const result = lastResult(published);
|
|
@@ -10,6 +10,7 @@ import { lastJsonObject, runGraph, type GraphRunState } from '../../src/graph-ru
|
|
|
10
10
|
import { releaseRunUniverse } from './release-universe.js';
|
|
11
11
|
import { isReleaseVersion } from './release-version.js';
|
|
12
12
|
import { changedFilesBetween, clearPartialPlan, planPartialRegate, writePartialPlan } from './gate-partial.js';
|
|
13
|
+
import { releaseResumeAcceptedRegressions, releaseResumeWaiver, type AcceptedRegression } from './resume.js';
|
|
13
14
|
|
|
14
15
|
const GRAPH = join(import.meta.dir, '../../graphs/release/release-loop.yaml');
|
|
15
16
|
|
|
@@ -55,7 +56,7 @@ function safeRunId(runId: string): string {
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
/** Point the saved version-release output at the current release/<v> tip (fast-forward of the recorded commit only). */
|
|
58
|
-
export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps = {}, from?: string): TipRefresh {
|
|
59
|
+
export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps = {}, from?: string, waiverCommit?: string): TipRefresh {
|
|
59
60
|
const root = deps.root ?? effectiveInstanceRoot();
|
|
60
61
|
const statePath = join(root, 'graph-runs', 'release-loop', `${safeRunId(runId)}.json`);
|
|
61
62
|
const state = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
|
|
@@ -81,6 +82,9 @@ export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps =
|
|
|
81
82
|
if (!/^[0-9a-f]{40}$/i.test(advertised)) throw new Error(`${branch} is not on origin — this run was not cut as a release branch`);
|
|
82
83
|
git(['fetch', 'origin', `+refs/heads/${branch}:refs/remotes/origin/${branch}`]);
|
|
83
84
|
const to = git(['rev-parse', '--verify', `refs/remotes/origin/${branch}^{commit}`]);
|
|
85
|
+
if (waiverCommit && (recorded.toLowerCase() !== waiverCommit.toLowerCase() || to.toLowerCase() !== waiverCommit.toLowerCase() || advertised.toLowerCase() !== waiverCommit.toLowerCase())) {
|
|
86
|
+
throw new Error('release branch moved — re-gate the new tip before waiving a node');
|
|
87
|
+
}
|
|
84
88
|
if (to !== advertised) throw new Error(`${branch} moved while it was read (${advertised} → ${to})`);
|
|
85
89
|
if (to === recorded) {
|
|
86
90
|
debug.log('release-loop.resume', 'tip-unchanged', { runId, version, commit: to });
|
|
@@ -164,14 +168,40 @@ function savedGraphPath(statePath: string): string | undefined {
|
|
|
164
168
|
}
|
|
165
169
|
|
|
166
170
|
/** Refresh the branch tip, then restart the failed run at `from` with the saved graph snapshot. */
|
|
167
|
-
export async function resumeReleaseRun(opts: { runId: string; from: string; partial?: boolean }, deps: ResumeReleaseDeps = {}): Promise<{ tip: TipRefresh; partial: PartialOutcome; state: GraphRunState }> {
|
|
171
|
+
export async function resumeReleaseRun(opts: { runId: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[] }, deps: ResumeReleaseDeps = {}): Promise<{ tip: TipRefresh; partial: PartialOutcome; state: GraphRunState }> {
|
|
168
172
|
if (opts.from === 'version-release') throw new Error('--from version-release would cut again — resume at a later node');
|
|
169
173
|
// RELEASE-LEDGER-UNIVERSE: decide the universe once; the run lookup and every resumed node use it.
|
|
170
174
|
deps = { ...deps, root: releaseRunUniverse({ root: deps.root }) };
|
|
171
|
-
const
|
|
175
|
+
const statePath = join(deps.root!, 'graph-runs', 'release-loop', `${safeRunId(opts.runId)}.json`);
|
|
176
|
+
let waiverCommit: string | undefined;
|
|
177
|
+
const original = opts.waive !== undefined || opts.reason !== undefined || opts.acceptedRegressions !== undefined
|
|
178
|
+
? JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState : undefined;
|
|
179
|
+
const waiver = original && (opts.waive !== undefined || opts.reason !== undefined)
|
|
180
|
+
? releaseResumeWaiver(original, opts) : undefined;
|
|
181
|
+
const acceptedRegressions = original && opts.acceptedRegressions !== undefined && !waiver
|
|
182
|
+
? releaseResumeAcceptedRegressions(original, opts.acceptedRegressions, opts.from) : undefined;
|
|
183
|
+
// A waived verdict may reuse its original commit. A moved tip still requires a full re-gate.
|
|
184
|
+
if (waiver) {
|
|
185
|
+
const saved = JSON.parse(readFileSync(statePath, 'utf8')) as GraphRunState;
|
|
186
|
+
const versionRecord = saved.nodes.find((node) => node.nodeId === 'version-release');
|
|
187
|
+
const output = lastJsonObject(versionRecord?.output);
|
|
188
|
+
const version = output?.version;
|
|
189
|
+
const recorded = output?.commit;
|
|
190
|
+
if (typeof version !== 'string' || typeof recorded !== 'string' || !isReleaseVersion(version) || !/^[0-9a-f]{40}$/i.test(recorded)) throw new Error('release waiver requires a recorded release commit');
|
|
191
|
+
const git = deps.git ?? gitRunner(deps.repo ?? process.cwd());
|
|
192
|
+
const branch = `release/${version}`;
|
|
193
|
+
const advertised = git(['ls-remote', '--heads', 'origin', `refs/heads/${branch}`]).split(/\s+/)[0];
|
|
194
|
+
if (advertised?.toLowerCase() !== recorded.toLowerCase()) throw new Error('release branch moved — re-gate the new tip before waiving a node');
|
|
195
|
+
waiverCommit = recorded;
|
|
196
|
+
}
|
|
197
|
+
// Check the refreshed tip before refresh writes a new version-release record or backup.
|
|
198
|
+
const tip = refreshReleaseBranchTip(opts.runId, deps, opts.from, waiverCommit);
|
|
172
199
|
const partial = preparePartial(tip, opts, deps);
|
|
173
200
|
// Resume the graph at the path it was started from (its snapshot is used); only tests inject another path.
|
|
174
201
|
const graphPath = deps.graphPath ?? savedGraphPath(tip.statePath) ?? GRAPH;
|
|
175
|
-
const state = await (deps.graph ?? runGraph)(graphPath, { resumeRunId: opts.runId, fromNodeId: opts.from, pinChildUniverse: true,
|
|
202
|
+
const state = await (deps.graph ?? runGraph)(graphPath, { resumeRunId: opts.runId, fromNodeId: opts.from, pinChildUniverse: true,
|
|
203
|
+
...(waiver ? { releaseWaiver: { ...waiver, requestedRegressions: opts.acceptedRegressions ?? [] } } : {}),
|
|
204
|
+
...(acceptedRegressions ? { releaseAcceptedRegressions: { requested: opts.acceptedRegressions!, acceptedRegressions } } : {}),
|
|
205
|
+
deps: { root: deps.root, ...(deps.runBash ? { runBash: deps.runBash } : {}) } });
|
|
176
206
|
return { tip, partial, state };
|
|
177
207
|
}
|