elanous 0.2.40 → 0.2.41
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/README.md +7 -7
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{HjeK7zONHfR7op1hKXp4k → GiOLWmt4MqDZePubBjA4Q}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +36 -0
- package/apps/pwa/out/_next/static/chunks/{9184.45afbf44fec87574.js → 1178.1aa9cad0e7695427.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2829-734fe8bf2eee7347.js → 1197-54da59d250a6e476.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6749.0744ce6eb08d40e9.js → 1219.7e17964e0e7cd8e5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +287 -0
- package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +90 -0
- package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{2226.2cf61ec781827219.js → 1800.f7ff51dc4978a958.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9175.2de5209a5ce6f68a.js → 2073.689dcb2680113d76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +1 -0
- package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5383.bdfa5d886e39a826.js → 2263.e09b6edea33bad2d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9069.657590a84afb8fac.js → 2743.5d3f76948be32b34.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{6624.981ef7caeb680560.js → 2773.0e80b9d325fb5635.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4864a2ca.1c1c280a7772c5e5.js → 2fdf2931.b431eee4fb468bc3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9189505a.980427ac048c8c60.js → 2fe2c302.41b517f88d6fe502.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9992.07ce73c10bd5e6a1.js → 3097.864e92bdaa2f4d15.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +1 -0
- package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +74 -0
- package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b84cad00.594027ebe0531fe2.js → 385e4574.e9886ab32759eda3.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8086.1ab9103c41be884f.js → 4156.ba4de4a3664f04b4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +148 -0
- package/apps/pwa/out/_next/static/chunks/{1281.d81877e35b9068f4.js → 4527.a69f2894d1bc9f4a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{8357.1aaa713b052a78b1.js → 4667.97e31aa38c95c475.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/{5436.fdf6fa8ae3e9588d.js → 4702.4a4adc1f16d7c93b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +94 -0
- package/apps/pwa/out/_next/static/chunks/{4769.9fd582071301f382.js → 5159.115f1c2ca471386c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/530.d26346e18089640a.js +115 -0
- package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{d8de0de2-dd0f4ac8e5ab1832.js → 53aeb4ee-51c92f8d683f5220.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6257.c0037b8949239f5e.js → 5471.1e611302ed3a7c53.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2566.beaffc3a5e1fcd2e.js → 5574.f35accf4f132b29d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{2066.a77257c8c350770a.js → 5744.b9415e18ad623100.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4351.0f37a6db2b34d50b.js → 5937.c2df9e3447e1f667.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +286 -0
- package/apps/pwa/out/_next/static/chunks/{6051-0ae955eedb10adb9.js → 5947-135e26537d80a6b9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/{3746-f80a78f220bf37b5.js → 5964-7e21164a8f2cf0ce.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +27 -0
- package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +62 -0
- package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +24 -0
- package/apps/pwa/out/_next/static/chunks/{2047.8f23e210995d4548.js → 6874.d5cf7eb8edb2cabe.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +122 -0
- package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7191.fdc955f7d96064a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8272-025653884f9645d2.js → 8050-9b364bdef8f71927.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{2281-b8cede695c6c650e.js → 8464-e24f10451b658aac.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5622.94893f5aea7185d0.js → 8880.64c445592f04acaf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1452.162bb2d9d699e82a.js → 8981.c706964c8ba27aff.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{470.51a72a2348306455.js → 9048.212083de42d25be3.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2177.df8547f9d7215c4e.js → 9507.7026657a2f47eb64.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +93 -0
- package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7515.1ad6efe157fa4448.js → 9579.4a8169600fff2058.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +34 -0
- package/apps/pwa/out/_next/static/chunks/{2499.02fbfd18126c10c0.js → 9834.63ab2bbc3153172e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{409c787b.e48c5bec8ec10456.js → a0a01613.6d1cca322238d7fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6cc1d1d6.9a98dd4622f1afc6.js → addc2b32.8c4ff8f0aefe987d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ba957ff875a026a0.js → page-14949db884bfa672.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{c696986b.5dc8bb1143af16d1.js → b2271e54.c1de3347976e90b0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{ca3702f8.2913182e73889fa2.js → c0c1a699.0ba79f97005965d4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/bin/elanous.mjs +6 -1
- package/catalog/models/openai/gpt-6.1-sol.yaml +16 -0
- package/catalog/models/openai/gpt-6.1-terra.yaml +16 -0
- package/graphs/demo/persona-teacher/lesson-pack.yaml +16 -0
- package/graphs/demo/persona-teacher/recipes.yaml +17 -0
- package/graphs/demo/persona-teacher/weekly-lesson.yaml +36 -0
- package/graphs/overlays/stop-heal-ladder.yaml +23 -2
- package/graphs/release/release-loop.yaml +3 -1
- package/graphs/units/gate/gate.yaml +20 -0
- package/graphs/units/git/git.yaml +26 -0
- package/graphs/units/implement/implement.yaml +19 -0
- package/graphs/units/landing/landing.yaml +18 -0
- package/graphs/units/review/review.yaml +20 -0
- package/graphs/units/verbs/recipes.yaml +3 -0
- package/graphs/units/verbs/research.yaml +20 -0
- package/graphs/work/research-report.yaml +11 -1
- package/package.json +1 -1
- package/scripts/disk-steward.ts +46 -0
- package/scripts/fleet/node-setup.sh +50 -0
- package/scripts/graph-units/verbs/research.ts +55 -0
- package/scripts/llm-cost-ledger.ts +179 -8
- package/scripts/measure-nl-routing-corpus.ts +10 -2
- package/scripts/persona-teacher/weekly-lesson-node.ts +172 -0
- package/scripts/public-copy-lint.ts +163 -19
- package/scripts/ratchets/train-side-invariants.sh +0 -1
- package/scripts/release-loop/gate-autoheal.ts +117 -0
- package/scripts/release-loop/gate-baseline-receipt.ts +8 -1
- package/scripts/release-loop/gate-diff.ts +22 -3
- package/scripts/release-loop/gate-node.ts +205 -17
- package/scripts/release-loop/gate-shard-load-flaky.ts +256 -0
- package/scripts/release-loop/gate-triage-node.ts +70 -10
- package/scripts/release-loop/resume-release.ts +247 -15
- package/scripts/release-loop/traffic-node.ts +6 -3
- package/scripts/release-loop/unattended-release.ts +4 -2
- package/scripts/shadow-authoring-probe.ts +20 -0
- package/scripts/ux-sim.ts +19 -2
- package/src/acp/core-turn-bridge.ts +86 -4
- package/src/agent-substrate/self-review-cli.ts +91 -29
- package/src/auto-research/research-turn.ts +10 -1
- package/src/autopilot/discovery/wiki-claim-proposer.ts +22 -1
- package/src/boot/daemon-tools/self-implement.ts +46 -9
- package/src/budget/shadow-arms.ts +52 -0
- package/src/chat/pickers/state.ts +7 -1
- package/src/cli/log-event-names.ts +5 -0
- package/src/cli/mcp-login.ts +8 -18
- package/src/cli/msg-cli.ts +57 -1
- package/src/cli/pr-land-heavy-remote.ts +15 -9
- package/src/cli/release-cli.ts +27 -1
- package/src/cli/sim-cli.ts +7 -1
- package/src/cli/tasks-cli.ts +5 -4
- package/src/codex/models.ts +30 -15
- package/src/core-turn/run-core-turn.ts +3 -0
- package/src/core-turn/run-goal-loop.ts +88 -2
- package/src/dashboard/acp-boot.ts +72 -3
- package/src/dashboard/index.ts +6 -0
- package/src/dashboard/turn-preamble.ts +12 -1
- package/src/disk-steward/judge.ts +73 -0
- package/src/disk-steward/ledger.ts +122 -0
- package/src/disk-steward/steward.ts +373 -0
- package/src/domains/guardian-tick.ts +191 -2
- package/src/graph-runner/graph-cli.ts +21 -0
- package/src/graph-runner/in-process-registry.ts +37 -0
- package/src/graph-runner/runner.ts +33 -3
- package/src/grounding/ref-index.ts +19 -0
- package/src/grounding/sources-cli.ts +9 -1
- package/src/harness/harness-cli-command.ts +267 -14
- package/src/harness/harness-incidents.ts +312 -7
- package/src/harness/harness-space.ts +15 -1
- package/src/harness/progress-worker-entry.ts +59 -0
- package/src/harness/progress-worker-runtime.ts +11 -0
- package/src/index.ts +18 -2
- package/src/instance/dev-project.ts +25 -0
- package/src/intelligence-map/model-alias.ts +6 -5
- package/src/intelligence-map/model-catalog.ts +59 -2
- package/src/llm/model-defaults.ts +4 -4
- package/src/llm.ts +42 -11
- package/src/loops/orchestrator/tick.ts +48 -0
- package/src/mcp/mcp-oauth.ts +3 -1
- package/src/model-tier/llm-tier-map.ts +9 -9
- package/src/model-tier/turn-tier.ts +1 -1
- package/src/msg/msg-mirror-github.ts +80 -0
- package/src/msg/msg-mirror-policy.ts +61 -0
- package/src/msg/msg-mirror-runner.ts +219 -0
- package/src/msg/msg-mirror-state.ts +33 -0
- package/src/msg/msg-store.ts +11 -0
- package/src/output-truncation.ts +41 -12
- package/src/project/project-store.ts +48 -1
- package/src/release-loop/gate-host-reservation.ts +144 -0
- package/src/release-loop/release-schedule.ts +90 -1
- package/src/research/bloom-exemplars.ts +135 -0
- package/src/self-dev/ask-launch-flow.ts +39 -25
- package/src/self-dev/dev-cli.ts +17 -17
- package/src/self-dev/graph-front-nodes.ts +23 -0
- package/src/self-dev/launch-preflight.ts +9 -4
- package/src/self-dev/orchestrate.ts +15 -0
- package/src/self-dev/run-supervisor.ts +185 -3
- package/src/self-dev/run-types.ts +3 -0
- package/src/self-implement/gate-artifacts.ts +13 -0
- package/src/self-implement/gate-cli.ts +54 -24
- package/src/self-implement/gate-remote.ts +23 -5
- package/src/self-implement/goal-author-clarification.ts +31 -12
- package/src/self-implement/goal-author.ts +77 -5
- package/src/self-implement/graph-stage-units.ts +172 -0
- package/src/self-implement/graph-templates.ts +162 -1
- package/src/self-implement/graph-variant.ts +37 -4
- package/src/self-implement/host-regate.ts +4 -4
- package/src/self-implement/knowhow-pack.ts +38 -0
- package/src/self-implement/orchestrator.ts +235 -21
- package/src/self-implement/run-ledger.ts +64 -6
- package/src/self-implement/run-stop.ts +21 -2
- package/src/self-implement/running-runs.ts +35 -12
- package/src/self-implement/self-implement-cli.ts +36 -4
- package/src/self-implement/stop-autoheal-operational.ts +43 -0
- package/src/self-implement/stop-autoheal.ts +15 -6
- package/src/session/chat.ts +31 -54
- package/src/session/request-size-guard.ts +123 -0
- package/src/sidetab-core/model.ts +136 -0
- package/src/task-agent/parent-host.ts +14 -1
- package/src/task-agent/task-hand.ts +4 -1
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +43 -0
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +29 -4
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +116 -16
- package/src/task-orchestrator/surfaces/self-implement.ts +18 -0
- package/src/tui/entry.ts +10 -3
- package/src/tui/sidetab/list.ts +45 -0
- package/src/tui/sidetab/nl-tool.ts +2 -136
- package/src/tui/sidetab/peek.ts +52 -0
- package/src/tui-client/dashboard-session.ts +3 -0
- package/src/user-config.ts +11 -5
- package/src/ux-sim/fault-needs-human-reason-repair.ts +107 -0
- package/src/ux-sim/fault-pod-child-result.ts +42 -0
- package/src/ux-sim/release-sim-rig.ts +262 -0
- package/src/ux-sim/seminar-rehearsal.ts +109 -0
- package/src/ux-sim/subagent-tools-device.ts +2 -2
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/1060.014f1f01a17aec26.js +0 -115
- package/apps/pwa/out/_next/static/chunks/1350.59f40e39e02d91b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +0 -286
- package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +0 -90
- package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +0 -104
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2522.f2766b76d22c8bdf.js +0 -34
- package/apps/pwa/out/_next/static/chunks/261.0d471e8aded799f3.js +0 -226
- package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +0 -27
- package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2774-719820e3f5b2a3eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3330.7443183b7e6fdbdf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +0 -24
- package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +0 -77
- package/apps/pwa/out/_next/static/chunks/3b355b3d.6f73c98bf6f9c749.js +0 -122
- package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +0 -36
- package/apps/pwa/out/_next/static/chunks/413-24c8284bda08241d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +0 -287
- package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +0 -1
- package/apps/pwa/out/_next/static/chunks/483.725e4a61be922788.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +0 -8
- package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +0 -62
- package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +0 -94
- package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6908.06008c67f6380ea9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +0 -93
- package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8639-92c11d069792429e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-4edb8df90f4537ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-fca2e59a81744d9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-139d722de1dcd6c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-ccde99f07aaf71f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +0 -1
- package/apps/pwa/out/_next/static/chunks/d5d3cefc-373c4eb722ed848b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-002b472a66935d31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +0 -1
- package/scripts/ratchets/next-tui-entry-budget.ts +0 -124
- /package/apps/pwa/out/_next/static/{HjeK7zONHfR7op1hKXp4k → GiOLWmt4MqDZePubBjA4Q}/_ssgManifest.js +0 -0
|
@@ -208,6 +208,12 @@ function expectationsMet(expects: readonly NlRoutingToolExpectation[], breakdown
|
|
|
208
208
|
return expects.every((expectation) => (breakdown[expectation.tool] ?? 0) >= (expectation.minCount ?? 1));
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
/**
|
|
212
|
+
* v5 채점의 최소 실행 턴 — 코퍼스 예산(CORPUS_BUDGETS) 과 «독립»인 채점 턴 정책 상수.
|
|
213
|
+
* 낮은 예산에서 복합 발화가 예산 부족만으로 거짓 실패하지 않게 한다.
|
|
214
|
+
*/
|
|
215
|
+
export const NL_ROUTING_V5_MIN_SCORING_TURNS = 6;
|
|
216
|
+
|
|
211
217
|
/** v5 28문항을 «생산 runEvalPrompt seam» 으로 그대로 돌려 경로·복합 처리를 채점한다. */
|
|
212
218
|
export async function scoreNlRoutingV5(opts: {
|
|
213
219
|
runPrompt: typeof runEvalPrompt;
|
|
@@ -215,7 +221,7 @@ export async function scoreNlRoutingV5(opts: {
|
|
|
215
221
|
cwd: string;
|
|
216
222
|
maxTurns?: number;
|
|
217
223
|
}): Promise<NlRoutingV5Score> {
|
|
218
|
-
const maxTurns = opts.maxTurns ??
|
|
224
|
+
const maxTurns = opts.maxTurns ?? NL_ROUTING_V5_MIN_SCORING_TURNS;
|
|
219
225
|
const matched = new Set<string>();
|
|
220
226
|
const failed: string[] = [];
|
|
221
227
|
const patternMismatches: string[] = [];
|
|
@@ -401,7 +407,9 @@ export async function main(
|
|
|
401
407
|
// (다른 자로 재면 판정선과 비교 불가 · 형태 F3). 임계 미달은 «조용한 0» 이 아니라 거부다.
|
|
402
408
|
let v5: NlRoutingV5Score | undefined;
|
|
403
409
|
if (process.env.CORPUS_V5 === '1') {
|
|
404
|
-
|
|
410
|
+
// ⛔ 채점 턴 정책은 코퍼스 예산과 «독립»이다 — 예산은 코퍼스 생성 실행 횟수만 제어하고
|
|
411
|
+
// 채점 maxTurns 는 NL_ROUTING_V5_MIN_SCORING_TURNS 기본(또는 명시적 opts)에서만 온다.
|
|
412
|
+
v5 = await scoreNlRoutingV5({ runPrompt, surface, cwd: corpusCwd });
|
|
405
413
|
console.log(`[v5] patterns ${v5.patterns} (path ${v5.pathPatterns} · compound ${v5.compoundPatterns}) · 문항 ${v5.questions} (path ${v5.pathQuestions} · compound ${v5.compoundQuestions}) · 채점 ${v5.scored} · 통과 ${v5.passed} · 실패 ${v5.failed.length ? v5.failed.join(',') : '(없음)'} · 실행 실패 ${v5.failedRuns} · masking-leak ${v5.maskingLeaks.length} ${v5.maskingLeaks.length ? v5.maskingLeaks.join(',') : '(없음)'} · pattern-mismatch ${v5.patternMismatches.length ? v5.patternMismatches.join(',') : '(없음)'} · 판정 ${v5.verdict}`);
|
|
406
414
|
if (!v5.thresholdsMet) {
|
|
407
415
|
throw new Error(
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SW-PERSONA-TEACHER-WEEKLY-FU (GoalId d68f0e7e17725cef) — weekly lesson node commands.
|
|
3
|
+
*
|
|
4
|
+
* 각 명령은 runner 가 심는 `ELANOUS_GRAPH_CONTEXT`(이번 노드의 input + 앞 노드들의 구조 산출)를 읽고
|
|
5
|
+
* 마지막 한 줄 JSON 으로 다음 간선의 `outcome` 을 낸다. 진도는 새 저장소를 만들지 않는다 —
|
|
6
|
+
* 첫 실행의 `record-progress` 산출이 그래프 런 원장(`graph-runs/weekly-lesson/<runId>.json`)에 남고,
|
|
7
|
+
* 다음 실행의 `read-progress` 가 그 원장을 그대로 읽어 다음 단원을 고른다.
|
|
8
|
+
*/
|
|
9
|
+
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { join, resolve } from 'node:path';
|
|
11
|
+
|
|
12
|
+
const SYLLABUS = ['unit-1', 'unit-2', 'unit-3', 'unit-4', 'unit-5'] as const;
|
|
13
|
+
const WEEKLY_TIMEZONE = 'Asia/Seoul';
|
|
14
|
+
const WEEKLY_CRON_WEEKDAY = 'Sun';
|
|
15
|
+
const WEEKLY_CRON_HOUR = 20;
|
|
16
|
+
|
|
17
|
+
type Lesson = (typeof SYLLABUS)[number] | string;
|
|
18
|
+
|
|
19
|
+
interface StepOutput {
|
|
20
|
+
outcome?: string;
|
|
21
|
+
lesson?: string;
|
|
22
|
+
completed?: string[];
|
|
23
|
+
nextLesson?: string | null;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface GraphContext {
|
|
28
|
+
graphId?: string;
|
|
29
|
+
runId?: string;
|
|
30
|
+
nodeId?: string;
|
|
31
|
+
input?: unknown;
|
|
32
|
+
outputs?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function emit(value: Record<string, unknown>): void {
|
|
36
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function asObject(value: unknown): Record<string, unknown> {
|
|
40
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseStepOutput(value: unknown): StepOutput {
|
|
44
|
+
if (typeof value === 'string') {
|
|
45
|
+
const last = value.split('\n').map((line) => line.trim()).filter(Boolean).at(-1);
|
|
46
|
+
if (!last?.startsWith('{')) throw new Error('step output must end with a JSON object');
|
|
47
|
+
try { return JSON.parse(last) as StepOutput; }
|
|
48
|
+
catch (error) { throw new Error('step output ended with invalid JSON', { cause: error }); }
|
|
49
|
+
}
|
|
50
|
+
return asObject(value) as StepOutput;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function context(): { value: GraphContext; root: string } {
|
|
54
|
+
const path = process.env.ELANOUS_GRAPH_CONTEXT;
|
|
55
|
+
if (!path) throw new Error('ELANOUS_GRAPH_CONTEXT is required');
|
|
56
|
+
const stateRoot = process.env.ELANOUS_STATE_DIR;
|
|
57
|
+
if (!stateRoot) throw new Error('ELANOUS_STATE_DIR is required');
|
|
58
|
+
return { value: JSON.parse(readFileSync(path, 'utf8')) as GraphContext, root: resolve(stateRoot) };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 일요일 20:00 Asia/Seoul 인가 — 스케줄러가 주입한 tick 시각을 그 자리에서 검증한다. */
|
|
62
|
+
function isWeeklySlot(scheduledAt: unknown): boolean {
|
|
63
|
+
if (typeof scheduledAt !== 'string' || !Number.isFinite(Date.parse(scheduledAt))) return false;
|
|
64
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
65
|
+
timeZone: WEEKLY_TIMEZONE, weekday: 'short', hour: '2-digit', minute: '2-digit', hour12: false,
|
|
66
|
+
}).formatToParts(new Date(scheduledAt));
|
|
67
|
+
const get = (type: string): string => parts.find((part) => part.type === type)?.value ?? '';
|
|
68
|
+
return get('weekday') === WEEKLY_CRON_WEEKDAY && Number(get('hour')) === WEEKLY_CRON_HOUR && Number(get('minute')) === 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** 저장된 진도 = 앞선 런 원장의 성공한 `record-progress` 산출(lesson·completed). */
|
|
72
|
+
function completedLessons(root: string): { completed: Lesson[]; runs: number } {
|
|
73
|
+
const dir = join(root, 'graph-runs', 'weekly-lesson');
|
|
74
|
+
let files: string[];
|
|
75
|
+
try { files = readdirSync(dir).filter((file) => file.endsWith('.json') && !file.endsWith('.decision.json')); }
|
|
76
|
+
catch { return { completed: [], runs: 0 }; }
|
|
77
|
+
const completed: Lesson[] = [];
|
|
78
|
+
let runs = 0;
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
let state: { nodes?: Array<{ nodeId?: string; ok?: boolean; output?: unknown }> };
|
|
81
|
+
try { state = JSON.parse(readFileSync(join(dir, file), 'utf8')) as typeof state; }
|
|
82
|
+
catch { continue; }
|
|
83
|
+
runs += 1;
|
|
84
|
+
for (const node of state.nodes ?? []) {
|
|
85
|
+
if (node.nodeId !== 'record-progress' || node.ok !== true) continue;
|
|
86
|
+
const recorded = parseStepOutput(node.output);
|
|
87
|
+
for (const lesson of recorded.completed ?? []) if (typeof lesson === 'string' && !completed.includes(lesson)) completed.push(lesson);
|
|
88
|
+
if (typeof recorded.lesson === 'string' && !completed.includes(recorded.lesson)) completed.push(recorded.lesson);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { completed, runs };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function nextLesson(completed: readonly string[]): Lesson | undefined {
|
|
95
|
+
return SYLLABUS.find((lesson) => !completed.includes(lesson));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readProgress(): void {
|
|
99
|
+
const { value, root } = context();
|
|
100
|
+
const input = asObject(value.input);
|
|
101
|
+
if (!isWeeklySlot(input.scheduledAt)) {
|
|
102
|
+
emit({ outcome: 'fail', error: 'off-schedule: weekly ticks run Sunday 20:00 Asia/Seoul', scheduledAt: input.scheduledAt ?? null });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const { completed, runs } = completedLessons(root);
|
|
106
|
+
emit({ outcome: 'ok', scheduledAt: input.scheduledAt, completed, nextLesson: nextLesson(completed) ?? null,
|
|
107
|
+
ledgerRuns: runs, source: runs === 0 ? 'empty-ledger' : 'run-ledger' });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function selectNext(): void {
|
|
111
|
+
const { value } = context();
|
|
112
|
+
const prior = parseStepOutput(value.outputs?.['read-progress']);
|
|
113
|
+
const completed = (prior.completed ?? []).filter((lesson): lesson is string => typeof lesson === 'string');
|
|
114
|
+
const lesson = typeof prior.nextLesson === 'string' ? prior.nextLesson : nextLesson(completed);
|
|
115
|
+
if (!lesson) {
|
|
116
|
+
emit({ outcome: 'fail', error: 'syllabus-complete', completed });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
emit({ outcome: completed.length === 0 ? 'baseline' : 'next', lesson, completed, scheduledAt: prior.scheduledAt ?? null,
|
|
120
|
+
requestedBy: { graphId: value.graphId ?? null, runId: value.runId ?? null } });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function packLesson(): void {
|
|
124
|
+
const { value, root } = context();
|
|
125
|
+
const selected = parseStepOutput(asObject(value.input)['select-next']);
|
|
126
|
+
if (typeof selected.lesson !== 'string') {
|
|
127
|
+
emit({ outcome: 'fail', error: 'lesson-pack requires a selected lesson' });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!(SYLLABUS as readonly string[]).includes(selected.lesson)) {
|
|
131
|
+
emit({ outcome: 'fail', error: `lesson-pack received an unknown lesson: ${selected.lesson}` });
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const dir = join(root, 'lesson-pack', 'inbox');
|
|
135
|
+
mkdirSync(dir, { recursive: true });
|
|
136
|
+
writeFileSync(join(dir, `${selected.lesson}.json`), `${JSON.stringify({
|
|
137
|
+
lesson: selected.lesson, scheduledAt: selected.scheduledAt ?? null,
|
|
138
|
+
requestedBy: asObject(selected.requestedBy), packedBy: { graphId: value.graphId ?? null, runId: value.runId ?? null },
|
|
139
|
+
}, null, 2)}\n`);
|
|
140
|
+
emit({ outcome: 'ok', lesson: selected.lesson, completed: selected.completed ?? [] });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function recordProgress(): void {
|
|
144
|
+
const { value } = context();
|
|
145
|
+
const selected = parseStepOutput(value.outputs?.['select-next']);
|
|
146
|
+
const packed = parseStepOutput(value.outputs?.['lesson-pack']);
|
|
147
|
+
const lesson = typeof packed.lesson === 'string' ? packed.lesson : typeof selected.lesson === 'string' ? selected.lesson : undefined;
|
|
148
|
+
if (!lesson) {
|
|
149
|
+
emit({ outcome: 'fail', error: 'record-progress requires the delivered lesson' });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const completed = (selected.completed ?? []).filter((item): item is string => typeof item === 'string');
|
|
153
|
+
if (!completed.includes(lesson)) completed.push(lesson);
|
|
154
|
+
emit({ outcome: 'ok', lesson, completed, recordedAt: asObject(value.input).scheduledAt ?? null });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const commands: Record<string, () => void> = {
|
|
158
|
+
'read-progress': readProgress,
|
|
159
|
+
'select-next': selectNext,
|
|
160
|
+
pack: packLesson,
|
|
161
|
+
'record-progress': recordProgress,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (import.meta.main) {
|
|
165
|
+
const command = process.argv[2] ?? '';
|
|
166
|
+
const run = commands[command];
|
|
167
|
+
if (!run) {
|
|
168
|
+
console.error(`unknown weekly-lesson command: ${command} (expected ${Object.keys(commands).join('|')})`);
|
|
169
|
+
process.exit(2);
|
|
170
|
+
}
|
|
171
|
+
run();
|
|
172
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/** Warning-only public-copy shadow scan. It never edits source or exposes private candidate text. */
|
|
3
|
-
import {
|
|
4
|
-
import { extname, normalize, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
4
|
+
import { extname, join, normalize, relative, resolve, sep } from 'node:path';
|
|
5
5
|
import { PatentLedger } from '../src/patents/ledger.js';
|
|
6
6
|
import { checkBrandText } from './brand/check.js';
|
|
7
7
|
|
|
@@ -10,7 +10,8 @@ export type PublicCopyFinding = { source: string; line: number; rule: string };
|
|
|
10
10
|
export type PatentLineMatcher = (text: string) => number[];
|
|
11
11
|
export type PublicCopyScan = {
|
|
12
12
|
findings: PublicCopyFinding[];
|
|
13
|
-
excludedSources: Array<{ source: string; reason: 'internal-goal-document' }>;
|
|
13
|
+
excludedSources: Array<{ source: string; reason: 'internal-goal-document' | 'internal-marketing-source' | 'asset-manifest' }>;
|
|
14
|
+
documents: Array<{ source: string; findings: number; companyNameMentions: number; placeholderMentions: number }>;
|
|
14
15
|
brandRulesAvailable: boolean;
|
|
15
16
|
patentLedgerAvailable: boolean;
|
|
16
17
|
};
|
|
@@ -23,9 +24,113 @@ function normalizedLabel(label: string): string | undefined {
|
|
|
23
24
|
return normalized;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
function publicCopyExclusion(normalized: string): PublicCopyScan['excludedSources'][number]['reason'] | undefined {
|
|
28
|
+
if (normalized.startsWith('docs/goals/')) return 'internal-goal-document';
|
|
29
|
+
if (!normalized.startsWith('docs/marketing/')) return undefined;
|
|
30
|
+
const relativePath = normalized.slice('docs/marketing/'.length);
|
|
31
|
+
const basename = relativePath.split('/').at(-1) ?? '';
|
|
32
|
+
// These files are published records or release-specific source notes, not
|
|
33
|
+
// current copy candidates. Preserve their exact product names and evidence.
|
|
34
|
+
if (/^(?:BLOG-02-the-agent-drives-the-agent-|BLOG-03-it-drives-the-terminal-itself-|DRAFT-0\.2\.(?:7|8)-announcement-|DRAFT-0\.2\.7-known-issues-public-wording-|DRAFT-0\.2\.10-announcement-|PRFAQ-release-0\.2\.4-|SCRIPT-ax-demo-1008-|VO-teaser-v2-)/i.test(basename)
|
|
35
|
+
|| /^docs\/marketing\/launch\/(?:0\.2\.8-loop-final\/|0\.2\.8-rehearsal\/PRFAQ-generated\.md$|0\.2\.11-cut-)/i.test(normalized)) {
|
|
36
|
+
return 'internal-marketing-source';
|
|
37
|
+
}
|
|
38
|
+
if (normalized.startsWith('docs/marketing/') && /^(?:BRIEF-|DOCS-|EVENT-|GUIDE-|MANUAL-|MAP-|MATURITY-|PLAN-|RESEARCH-|RFC-|SCENARIO-|STORYBOARD-|STORYLINE-|STRATEGY-|SOURCES-)/i.test(basename)) {
|
|
39
|
+
return 'internal-marketing-source';
|
|
40
|
+
}
|
|
41
|
+
if (normalized.startsWith('docs/marketing/') && /^DRAFT-persona-/i.test(basename)) return 'internal-marketing-source';
|
|
42
|
+
if (/^docs\/marketing\/teaser-v\d+\/MANIFEST\.md$/i.test(normalized) || normalized === 'docs/marketing/decks/media/README.md') {
|
|
43
|
+
return 'asset-manifest';
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isRequestedPublicCopyPath(normalized: string): boolean {
|
|
49
|
+
return normalized === 'README.md' || normalized.startsWith('docs/marketing/');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function maskSpan(text: string, start: number, end: number): string {
|
|
53
|
+
return text.slice(start, end).replace(/[^\r\n]/g, ' ');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Keep line offsets while limiting brand checks to visible prose, not code, comments, metadata, or link targets. */
|
|
57
|
+
function visibleMarkdownProse(text: string): string {
|
|
58
|
+
let visible = text;
|
|
59
|
+
const masks: RegExp[] = [
|
|
60
|
+
/^---\r?\n[\s\S]*?\r?\n---\s*$/gm,
|
|
61
|
+
/<!--[\s\S]*?-->/g,
|
|
62
|
+
/^\s*(```|~~~)[^\r\n]*\r?\n[\s\S]*?^\s*\1\s*$/gm,
|
|
63
|
+
/`[^`\r\n]*`/g,
|
|
64
|
+
/\]\((?:\\.|[^)])*\)/g,
|
|
65
|
+
/^>\s*🧾\s*\*\*공개 전 할 일\*\*[\s\S]*?(?=^[^>\r\n]|$(?![\s\S]))/gm,
|
|
66
|
+
/^##\s*(?:\d+\.\s*)?(?:칸|출처 목록|sources|evidence|게시 직전 다시 잴 것|기준선|올리기 전 확인)(?:\s|$)[\s\S]*?(?=^##\s|$(?![\s\S]))/gim,
|
|
67
|
+
/^>\s*✏️\s*\*\*착지·실측된 것만\.[^\r\n]*$/gm,
|
|
68
|
+
/https?:\/\/[^\s)>]+/gi,
|
|
69
|
+
/\b(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,}(?:\/[^\s)>]*)?/g,
|
|
70
|
+
];
|
|
71
|
+
for (const pattern of masks) {
|
|
72
|
+
const matches = [...visible.matchAll(pattern)].map((match) => ({ start: match.index!, end: match.index! + match[0].length }));
|
|
73
|
+
for (const match of matches.reverse()) visible = visible.slice(0, match.start) + maskSpan(visible, match.start, match.end) + visible.slice(match.end);
|
|
74
|
+
}
|
|
75
|
+
return visible;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const PUBLIC_COMPANY_NAMES = /\b(?:OpenAI|ChatGPT|Codex|Claude(?:\s+Code)?|Anthropic|Gemini|Google|Grok|xAI|Devin|Cognition|OpenHands|Replit(?:\s+Agent(?:\s+\d+)?)?|Factory(?:\s+AI)?|Hermes|OpenClaw|Manus)\b/gi;
|
|
79
|
+
const PUBLIC_PLACEHOLDER = /\b(?:another coding agent|another agent platform)\b/gi;
|
|
80
|
+
const PUBLIC_PLACEHOLDER_LIST = /\ba coding tool\s*[,·]\s*the coding CLI\s*[,·]\s*an AI model\s*[,·]\s*a model provider\b/gi;
|
|
81
|
+
const UNSUPPORTED_COMPARISON = /\b(?:better|faster|cheaper|safer|worse|superior|inferior)\s+than\b|\b(?:vs\.?|versus|compared\s+(?:with|to))\b|(?:보다\s*(?:낫|빠르|저렴|좋|강력|안전|우수))/i;
|
|
82
|
+
|
|
83
|
+
function companyNameMentions(text: string): number {
|
|
84
|
+
return [...text.matchAll(PUBLIC_COMPANY_NAMES)].length;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function placeholderMentions(text: string): number {
|
|
88
|
+
return [...text.matchAll(PUBLIC_PLACEHOLDER)].length + [...text.matchAll(PUBLIC_PLACEHOLDER_LIST)].length;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hasSupportedComparisonEvidence(text: string): boolean {
|
|
92
|
+
const hasSource = /\b(?:source|citation)\b|출처/i.test(text);
|
|
93
|
+
const hasMeasurement = /\b(?:measur|benchmark|tested|test conditions?)\w*\b|실측|측정|측정 조건/i.test(text);
|
|
94
|
+
return hasSource && hasMeasurement;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function measuredScopeMatchesClaim(claim: string): boolean {
|
|
98
|
+
const quantity = String.raw`(\d+(?:\.\d+)?)`;
|
|
99
|
+
const unit = String.raw`(jobs?|tasks?|workflows?|items?|건|개|작업)`;
|
|
100
|
+
const claimScope = new RegExp(String.raw`(?:completes?|processes?|handles?|완료|처리)\s*${quantity}\s*${unit}`, 'i').exec(claim);
|
|
101
|
+
const measuredScope = new RegExp(String.raw`(?:measured|measurement|실측|측정).*?(?:scope|range|범위).*?(?:limited to|only|한정|범위 내)\s*${quantity}\s*${unit}`, 'i').exec(claim);
|
|
102
|
+
if (!claimScope || !measuredScope) return false;
|
|
103
|
+
const normalizeUnit = (value: string): string => {
|
|
104
|
+
const normalized = value.toLowerCase();
|
|
105
|
+
if (normalized === 'job' || normalized === 'jobs' || normalized === 'task' || normalized === 'tasks' || normalized === 'workflow' || normalized === 'workflows' || normalized === 'item' || normalized === 'items') return normalized.replace(/s$/, '');
|
|
106
|
+
return normalized;
|
|
107
|
+
};
|
|
108
|
+
return claimScope[1] === measuredScope[1] && normalizeUnit(claimScope[2]!) === normalizeUnit(measuredScope[2]!);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function oneClickFindings(text: string, source: string): PublicCopyFinding[] {
|
|
112
|
+
const lines = text.split(/\r?\n/);
|
|
113
|
+
const findings: PublicCopyFinding[] = [];
|
|
114
|
+
for (let index = 0; index < lines.length; index++) {
|
|
115
|
+
const claims = lines[index]!.split(/(?<=[.!?。!?;;])\s*/).filter((segment) => /\bone[ -]click\b|원\s*클릭/i.test(segment));
|
|
116
|
+
for (const claim of claims) {
|
|
117
|
+
const hasLimitedClaimScope = !/(?:every|all|entire|unlimited|모든|전체|무제한)/i.test(claim)
|
|
118
|
+
&& /(?:completes?|processes?|handles?|완료|처리)/i.test(claim)
|
|
119
|
+
&& /\b\d+(?:\.\d+)?\s+(?:jobs?|tasks?|workflows?|items?)\b|\d+(?:\.\d+)?\s*(?:건|개|작업)/i.test(claim);
|
|
120
|
+
const hasMeasuredScope = hasLimitedClaimScope
|
|
121
|
+
&& measuredScopeMatchesClaim(claim)
|
|
122
|
+
&& !/(?:no|not|without|unmeasured|측정되지 않|범위 없음|범위가 없|한정되지 않)/i.test(claim);
|
|
123
|
+
if (!hasMeasuredScope) findings.push({ source, line: index + 1, rule: 'ONE-CLICK-MEASURED-SCOPE' });
|
|
124
|
+
const hasPublicationApprovalStatus = /(?:approved for publication|publication approved|publication approval pending|publication not approved|not approved for publication|unapproved|pending|게시\s*승인(?:됨|완료)?|게시\s*미승인|게시\s*승인\s*보류|게시\s*승인\s*상태\s*:\s*(?:승인|미승인|보류)|승인되지 않)/i.test(claim);
|
|
125
|
+
if (!hasPublicationApprovalStatus) findings.push({ source, line: index + 1, rule: 'ONE-CLICK-APPROVAL-STATUS' });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return findings;
|
|
129
|
+
}
|
|
130
|
+
|
|
26
131
|
function allowedNormalizedLabel(normalized: string | undefined): boolean {
|
|
27
132
|
if (!normalized) return false;
|
|
28
|
-
if (normalized === 'PR-BODY') return true;
|
|
133
|
+
if (normalized === 'PR-BODY' || normalized === 'README.md') return true;
|
|
29
134
|
if (normalized.split('/').some((part) => part === '..' || part === '')) return false;
|
|
30
135
|
if (!['.md', '.mdx', '.txt', '.html', '.htm'].includes(extname(normalized).toLowerCase())) return false;
|
|
31
136
|
return ['docs/', 'release/public/docs/', 'blog/', 'posts/', 'content/blog/', 'content/posts/']
|
|
@@ -36,30 +141,49 @@ function allowedNormalizedLabel(normalized: string | undefined): boolean {
|
|
|
36
141
|
export function scanPublicCopy(inputs: readonly PublicCopyInput[], matchPrivateCandidate: PatentLineMatcher, rulesPath?: string): PublicCopyScan {
|
|
37
142
|
const findings: PublicCopyFinding[] = [];
|
|
38
143
|
const excludedSources: PublicCopyScan['excludedSources'] = [];
|
|
144
|
+
const documents: PublicCopyScan['documents'] = [];
|
|
39
145
|
let brandRulesAvailable = true;
|
|
40
146
|
let patentLedgerAvailable = true;
|
|
41
147
|
for (const input of inputs) {
|
|
42
148
|
const label = normalizedLabel(input.label);
|
|
43
149
|
if (!allowedNormalizedLabel(label)) throw new Error(`공개 문면 입력 경로가 허용 목록 밖입니다: ${input.label}`);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (label?.startsWith('docs/goals/')) {
|
|
48
|
-
excludedSources.push({ source: input.label, reason: 'internal-goal-document' });
|
|
150
|
+
const excludedReason = label ? publicCopyExclusion(label) : undefined;
|
|
151
|
+
if (excludedReason) {
|
|
152
|
+
excludedSources.push({ source: input.label, reason: excludedReason });
|
|
49
153
|
continue;
|
|
50
154
|
}
|
|
155
|
+
const before = findings.length;
|
|
156
|
+
const prose = visibleMarkdownProse(input.text);
|
|
157
|
+
if (label && isRequestedPublicCopyPath(label)) findings.push(...oneClickFindings(prose, input.label));
|
|
51
158
|
try {
|
|
52
|
-
const brandFindings = checkBrandText(
|
|
159
|
+
const brandFindings = checkBrandText(prose, input.label, 'public-docs', rulesPath)
|
|
160
|
+
.filter((hit) => hit.id !== 'BRAND-COMPETITOR-NAME');
|
|
53
161
|
// Publication-specific promise/measurement rules apply to this explicit
|
|
54
162
|
// shadow scan without changing the existing generic brand-check scopes.
|
|
55
|
-
const publicationFindings = checkBrandText(
|
|
163
|
+
const publicationFindings = checkBrandText(prose, input.label, 'release-notes', rulesPath)
|
|
56
164
|
.filter((hit) => hit.id === 'BRAND-SOON' || hit.id === 'B4-NUMBER-SOURCE');
|
|
57
|
-
|
|
58
|
-
|
|
165
|
+
const brandLines = new Set([...brandFindings, ...publicationFindings].map((hit) => `${hit.line}:${hit.id}`));
|
|
166
|
+
for (const line of prose.split(/\r?\n/).map((text, index) => ({ text, line: index + 1 }))) {
|
|
167
|
+
if (UNSUPPORTED_COMPARISON.test(line.text) && PUBLIC_COMPANY_NAMES.test(line.text)
|
|
168
|
+
&& !hasSupportedComparisonEvidence(line.text)) {
|
|
169
|
+
brandLines.add(`${line.line}:BRAND-UNSUPPORTED-COMPARISON`);
|
|
170
|
+
}
|
|
171
|
+
PUBLIC_COMPANY_NAMES.lastIndex = 0;
|
|
172
|
+
UNSUPPORTED_COMPARISON.lastIndex = 0;
|
|
173
|
+
if (PUBLIC_PLACEHOLDER.test(line.text) || PUBLIC_PLACEHOLDER_LIST.test(line.text)) {
|
|
174
|
+
brandLines.add(`${line.line}:PUBLIC-COPY-PLACEHOLDER`);
|
|
175
|
+
}
|
|
176
|
+
PUBLIC_PLACEHOLDER.lastIndex = 0;
|
|
177
|
+
PUBLIC_PLACEHOLDER_LIST.lastIndex = 0;
|
|
178
|
+
}
|
|
179
|
+
for (const key of brandLines) {
|
|
180
|
+
const [line, rule] = key.split(':');
|
|
181
|
+
findings.push({ source: input.label, line: Number(line), rule: rule! });
|
|
59
182
|
}
|
|
60
183
|
} catch { brandRulesAvailable = false; }
|
|
61
184
|
try { for (const line of matchPrivateCandidate(input.text)) findings.push({ source: input.label, line, rule: 'PRIVATE-PATENT-CANDIDATE' }); }
|
|
62
185
|
catch { patentLedgerAvailable = false; }
|
|
186
|
+
documents.push({ source: input.label, findings: findings.length - before, companyNameMentions: companyNameMentions(prose), placeholderMentions: placeholderMentions(prose) });
|
|
63
187
|
}
|
|
64
188
|
if (inputs.length === 0 || excludedSources.length === inputs.length) {
|
|
65
189
|
// No scanner ran, so availability must not claim a successful measurement.
|
|
@@ -69,6 +193,7 @@ export function scanPublicCopy(inputs: readonly PublicCopyInput[], matchPrivateC
|
|
|
69
193
|
return {
|
|
70
194
|
findings: findings.sort((a, b) => a.source.localeCompare(b.source) || a.line - b.line || a.rule.localeCompare(b.rule)),
|
|
71
195
|
excludedSources,
|
|
196
|
+
documents,
|
|
72
197
|
brandRulesAvailable, patentLedgerAvailable,
|
|
73
198
|
};
|
|
74
199
|
}
|
|
@@ -77,6 +202,26 @@ export function lintPublicCopy(inputs: readonly PublicCopyInput[], matchPrivateC
|
|
|
77
202
|
return scanPublicCopy(inputs, matchPrivateCandidate).findings;
|
|
78
203
|
}
|
|
79
204
|
|
|
205
|
+
function collectPublicCopyFiles(paths: readonly string[], root: string): string[] {
|
|
206
|
+
const collected = new Set<string>();
|
|
207
|
+
const visit = (path: string): void => {
|
|
208
|
+
const absolute = resolve(root, path);
|
|
209
|
+
const stat = statSync(absolute);
|
|
210
|
+
if (stat.isDirectory()) {
|
|
211
|
+
for (const entry of readdirSync(absolute, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
212
|
+
if (entry.isDirectory()) visit(relative(root, join(absolute, entry.name)));
|
|
213
|
+
else if (entry.isFile() && ['.md', '.mdx', '.txt', '.html', '.htm'].includes(extname(entry.name).toLowerCase())) {
|
|
214
|
+
collected.add(relative(root, join(absolute, entry.name)));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
collected.add(relative(root, absolute));
|
|
220
|
+
};
|
|
221
|
+
for (const path of paths) visit(path);
|
|
222
|
+
return [...collected].sort();
|
|
223
|
+
}
|
|
224
|
+
|
|
80
225
|
export function run(argv: readonly string[], root = process.cwd(), ledger = new PatentLedger()): number {
|
|
81
226
|
const files: string[] = [];
|
|
82
227
|
let bodyFile: string | undefined;
|
|
@@ -97,15 +242,14 @@ export function run(argv: readonly string[], root = process.cwd(), ledger = new
|
|
|
97
242
|
} else throw new Error(`알 수 없는 옵션: ${arg}`);
|
|
98
243
|
}
|
|
99
244
|
if (!files.length && !bodyFile) throw new Error('usage: bun scripts/public-copy-lint.ts [--files <docs...>] [--pr-body-file <file> [--pr-body-label <repo-relative-label>]] [--json]');
|
|
100
|
-
const inputs: PublicCopyInput[] = files.map((file) => ({
|
|
101
|
-
label:
|
|
245
|
+
const inputs: PublicCopyInput[] = collectPublicCopyFiles(files, root).map((file) => ({
|
|
246
|
+
label: file.split(sep).join('/'), text: readFileSync(resolve(root, file), 'utf8'),
|
|
102
247
|
}));
|
|
103
248
|
if (bodyFile) inputs.push({ label: bodyLabel, text: readFileSync(resolve(root, bodyFile), 'utf8') });
|
|
104
|
-
const matchPrivateCandidate: PatentLineMatcher = (text) =>
|
|
105
|
-
|
|
106
|
-
};
|
|
249
|
+
const matchPrivateCandidate: PatentLineMatcher = (text) => ledger.unapprovedCandidateLineNumbers(text);
|
|
250
|
+
// The CLI caller uses the same scope-aware production scanner covered by focused tests.
|
|
107
251
|
const scan = scanPublicCopy(inputs, matchPrivateCandidate);
|
|
108
|
-
if (json) console.log(JSON.stringify({ mode: 'warning-only', ...scan }));
|
|
252
|
+
if (json) console.log(JSON.stringify({ mode: 'warning-only', documentsScanned: scan.documents.length, ...scan }));
|
|
109
253
|
else {
|
|
110
254
|
for (const finding of scan.findings) console.log(`${finding.source}:${finding.line}:WARN:${finding.rule}`);
|
|
111
255
|
for (const excluded of scan.excludedSources) console.log(`${excluded.source}:SKIP:${excluded.reason}`);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { acquireLockSync } from '../../src/storage/file-lock.js';
|
|
4
|
+
|
|
5
|
+
/** Deterministic recovery policy for release gate incidents. Side effects are supplied by callers. */
|
|
6
|
+
export type GateAutohealCause = 'shard-pod-death' | 'timeout' | 'host-down' | 'interference' | 'true-regression' | 'environment';
|
|
7
|
+
export type GateAutohealAction = 'reroute-shard' | 'retry-shard' | 'partial-resume' | 'host-switch' | 'hitl';
|
|
8
|
+
|
|
9
|
+
export interface GateAutohealInput {
|
|
10
|
+
cause: GateAutohealCause;
|
|
11
|
+
signature: string;
|
|
12
|
+
shardElapsedMs: number;
|
|
13
|
+
overallElapsedMs: number;
|
|
14
|
+
priorSameSignatureCount?: number;
|
|
15
|
+
shardKeys?: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface GateAutohealDecision {
|
|
19
|
+
action: GateAutohealAction;
|
|
20
|
+
cause: GateAutohealCause;
|
|
21
|
+
signature: string;
|
|
22
|
+
reason: string;
|
|
23
|
+
shardElapsedMs: number;
|
|
24
|
+
overallElapsedMs: number;
|
|
25
|
+
shardKey?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface GateResultForAutoheal {
|
|
29
|
+
outcome: 'ok' | 'regression' | 'error';
|
|
30
|
+
introduced?: readonly string[];
|
|
31
|
+
error?: string;
|
|
32
|
+
durationMs: number;
|
|
33
|
+
stalledShards?: readonly { shard: number; files: readonly string[]; reason: string; detail?: string; stall?: { sinceCheckoutMs: number } }[];
|
|
34
|
+
interferenceErrors?: readonly string[];
|
|
35
|
+
loadFlaky?: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface GateAutohealLedger {
|
|
39
|
+
schema: 1;
|
|
40
|
+
overallElapsedMs: number;
|
|
41
|
+
shards: Record<string, number>;
|
|
42
|
+
signatures: Record<string, number>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const emptyLedger = (): GateAutohealLedger => ({ schema: 1, overallElapsedMs: 0, shards: {}, signatures: {} });
|
|
46
|
+
|
|
47
|
+
/** Persist the incident budget across graph-node process restarts, keyed by release version and run id. */
|
|
48
|
+
export function decideAndRecordGateAutoheal(input: GateAutohealInput & { version: string; runId: string; shardKey: string; storeRoot: string }): GateAutohealDecision {
|
|
49
|
+
const path = join(input.storeRoot, 'release', input.version, 'gate-autoheal', `${input.runId.replace(/[^a-zA-Z0-9_.-]/g, '_')}.json`);
|
|
50
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
51
|
+
const unlock = acquireLockSync(`${path}.lock`, { breakDeadHolder: true });
|
|
52
|
+
try {
|
|
53
|
+
let ledger = emptyLedger();
|
|
54
|
+
if (existsSync(path)) {
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8')) as GateAutohealLedger;
|
|
57
|
+
if (parsed.schema !== 1 || !Number.isFinite(parsed.overallElapsedMs) || !parsed.shards || !parsed.signatures) throw new Error('invalid ledger');
|
|
58
|
+
ledger = parsed;
|
|
59
|
+
} catch {
|
|
60
|
+
return { action: 'hitl', cause: input.cause, signature: input.signature, reason: 'autoheal history unreadable; refusing another automatic action', shardElapsedMs: 0, overallElapsedMs: 0, shardKey: input.shardKey };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const shardKeys = [...new Set(input.shardKeys?.length ? input.shardKeys : [input.shardKey])];
|
|
64
|
+
const signatureKey = `${input.shardKey}:${input.signature}`;
|
|
65
|
+
const priorSameSignatureCount = ledger.signatures[signatureKey] ?? 0;
|
|
66
|
+
const elapsed = Math.max(0, input.shardElapsedMs);
|
|
67
|
+
const shards = { ...ledger.shards };
|
|
68
|
+
for (const key of shardKeys) shards[key] = (shards[key] ?? 0) + elapsed;
|
|
69
|
+
const shardElapsedMs = Math.max(0, ...shardKeys.map((key) => shards[key] ?? 0));
|
|
70
|
+
const overallElapsedMs = ledger.overallElapsedMs + Math.max(0, input.overallElapsedMs);
|
|
71
|
+
const decision = decideGateAutoheal({ ...input, shardElapsedMs, overallElapsedMs, priorSameSignatureCount });
|
|
72
|
+
ledger = { schema: 1, overallElapsedMs, shards,
|
|
73
|
+
signatures: { ...ledger.signatures, [signatureKey]: priorSameSignatureCount + 1 } };
|
|
74
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
75
|
+
writeFileSync(temp, `${JSON.stringify(ledger, null, 2)}\n`, { mode: 0o600 });
|
|
76
|
+
renameSync(temp, path);
|
|
77
|
+
return { ...decision, shardKey: input.shardKey };
|
|
78
|
+
} finally { unlock(); }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const GATE_AUTOHEAL_SHARD_CAP_MS = 60 * 60 * 1000;
|
|
82
|
+
export const GATE_AUTOHEAL_OVERALL_CAP_MS = 90 * 60 * 1000;
|
|
83
|
+
|
|
84
|
+
/** One signature may be acted on once; seeing it again, or crossing either timebox, stops in HITL. */
|
|
85
|
+
export function decideGateAutoheal(input: GateAutohealInput): GateAutohealDecision {
|
|
86
|
+
const shardElapsedMs = Math.max(0, input.shardElapsedMs);
|
|
87
|
+
const overallElapsedMs = Math.max(0, input.overallElapsedMs);
|
|
88
|
+
let action: GateAutohealAction;
|
|
89
|
+
let reason: string;
|
|
90
|
+
if (shardElapsedMs >= GATE_AUTOHEAL_SHARD_CAP_MS) {
|
|
91
|
+
action = 'hitl'; reason = 'per-shard timebox exceeded';
|
|
92
|
+
} else if (overallElapsedMs >= GATE_AUTOHEAL_OVERALL_CAP_MS) {
|
|
93
|
+
action = 'hitl'; reason = 'overall timebox exceeded';
|
|
94
|
+
} else if ((input.priorSameSignatureCount ?? 0) >= 1) {
|
|
95
|
+
action = 'hitl'; reason = 'same incident signature repeated';
|
|
96
|
+
} else {
|
|
97
|
+
switch (input.cause) {
|
|
98
|
+
case 'shard-pod-death': action = 'reroute-shard'; reason = 'replace failed shard Pod'; break;
|
|
99
|
+
case 'timeout': action = 'retry-shard'; reason = 'retry the timed-out shard within its budget'; break;
|
|
100
|
+
case 'host-down': action = 'host-switch'; reason = 'move the gate to a healthy host'; break;
|
|
101
|
+
case 'interference': action = 'partial-resume'; reason = 'resume only the unmeasured or affected work'; break;
|
|
102
|
+
case 'true-regression': action = 'hitl'; reason = 'measured regression requires a human decision'; break;
|
|
103
|
+
case 'environment': action = 'hitl'; reason = 'environment cause is not safe to repair automatically'; break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { action, cause: input.cause, signature: input.signature, reason, shardElapsedMs, overallElapsedMs };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function gateAutohealCause(result: GateResultForAutoheal): GateAutohealCause | undefined {
|
|
110
|
+
if (result.outcome === 'ok') return undefined;
|
|
111
|
+
if (result.outcome === 'regression' && (result.introduced?.length ?? 0) > 0) return 'true-regression';
|
|
112
|
+
if (/host.*(?:down|unreachable)|(?:down|unreachable).*host|ssh.*(?:failed|timeout)/i.test(result.error ?? '')) return 'host-down';
|
|
113
|
+
if (result.stalledShards?.some((shard) => /timeout/.test(shard.reason))) return 'timeout';
|
|
114
|
+
if ((result.interferenceErrors?.length ?? 0) > 0 || (result.loadFlaky?.length ?? 0) > 0) return 'interference';
|
|
115
|
+
if (result.stalledShards?.some((shard) => /pod.*(?:deleted|evicted|terminated|lost|not found)|(?:pod-dead|pod-evicted|pod-deleted)/i.test(`${shard.reason} ${shard.detail ?? ''}`))) return 'shard-pod-death';
|
|
116
|
+
return 'environment';
|
|
117
|
+
}
|
|
@@ -35,6 +35,7 @@ export interface GateBaselineReceipt {
|
|
|
35
35
|
imageDigest: string | null;
|
|
36
36
|
files: number;
|
|
37
37
|
shards: number;
|
|
38
|
+
attributionRecheck?: { summary: number; observed: number; identified: number; baselineResult: string; targetFiles: string[] };
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
/** A direct hard rehearsal has no graph run state. Pin the graph and recipe bytes at its Git SHA. */
|
|
@@ -83,11 +84,17 @@ export function gateGraphPins(root: string, runId: string | undefined): { graphS
|
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
export function gateBaselineReceipt(input: { root: string; version: string; commit: string; fullSweep: boolean;
|
|
86
|
-
graphPins: { graphSha: string; recipeSha: string } | null; envFingerprint: string
|
|
87
|
+
graphPins: { graphSha: string; recipeSha: string } | null; envFingerprint: string;
|
|
88
|
+
attributionRecheck?: { summary: number; observed: number; identified: number; baselineResult: string; targetFiles: string[] } }): GateBaselineReceipt {
|
|
87
89
|
const { root, version, commit, graphPins, envFingerprint } = input;
|
|
88
90
|
const base = { schema: 1 as const, version, commit, graphSha: graphPins?.graphSha ?? null,
|
|
89
91
|
recipeSha: graphPins?.recipeSha ?? null, envFingerprint, imageDigest: null as string | null, files: 0, shards: 0 };
|
|
90
92
|
const invalid = (reason: string): GateBaselineReceipt => ({ ...base, valid: false, reason });
|
|
93
|
+
if (input.attributionRecheck) {
|
|
94
|
+
const evidence = input.attributionRecheck;
|
|
95
|
+
return { ...invalid(`failure attribution unresolved after baseline recheck (${evidence.baselineResult}): summary=${evidence.summary}, observed=${evidence.observed}, identified=${evidence.identified}`),
|
|
96
|
+
attributionRecheck: { ...evidence, targetFiles: [...evidence.targetFiles].sort() } };
|
|
97
|
+
}
|
|
91
98
|
if (!input.fullSweep) return invalid('gate was not a complete clean full sweep');
|
|
92
99
|
if (!graphPins) return invalid('pinned graph or recipe SHA absent');
|
|
93
100
|
if (!SHA256.test(envFingerprint)) return invalid('gate environment fingerprint absent');
|
|
@@ -4,9 +4,28 @@ export interface FailureDiff {
|
|
|
4
4
|
common: string[];
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
/** One failure identity may be printed more than once when a host retries or concatenates a test run. */
|
|
8
|
+
export function collapseGateFailureAttempts(ids: readonly string[]): { failures: string[]; observed: number; collapsed: number } {
|
|
9
|
+
const failures = [...new Set(ids)].sort();
|
|
10
|
+
return { failures, observed: ids.length, collapsed: ids.length - failures.length };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class GateFailureAttributionMismatch extends Error {
|
|
14
|
+
constructor(readonly label: string, readonly summary: number, readonly observed: number,
|
|
15
|
+
readonly identified: number, readonly collapsed: number, readonly failures: readonly string[]) {
|
|
16
|
+
super(`${label} incomplete (failure attribution mismatch: summary=${summary}, observed=${observed}, identified=${identified})`);
|
|
17
|
+
this.name = 'GateFailureAttributionMismatch';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
7
21
|
/** Bun's file header followed by `(fail) name` lines is the identity source. */
|
|
8
22
|
export function parseFailures(output: string): string[] {
|
|
9
|
-
|
|
23
|
+
return [...new Set(parseFailureAttempts(output))].sort();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Raw reporter rows, retaining repeated identities so gate attribution can distinguish retries from missing names. */
|
|
27
|
+
export function parseFailureAttempts(output: string): string[] {
|
|
28
|
+
const failures: string[] = [];
|
|
10
29
|
let file: string | undefined;
|
|
11
30
|
for (const raw of output.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '').split(/\r?\n/)) {
|
|
12
31
|
const line = raw.trim();
|
|
@@ -14,9 +33,9 @@ export function parseFailures(output: string): string[] {
|
|
|
14
33
|
if (header) { file = header[1]; continue; }
|
|
15
34
|
// Line-start only: a title/body `(fail)` is not a reporter row. Trailing CR is still a real Bun fail row.
|
|
16
35
|
const failed = /^\(fail\)[ \t]+(.+?)(?:[ \t]+\[[\d.]+(?:ms|s)\])?[ \t]*\r?$/.exec(raw);
|
|
17
|
-
if (failed && file) failures.
|
|
36
|
+
if (failed && file) failures.push(`${file} > ${failed[1]!.trim()}`);
|
|
18
37
|
}
|
|
19
|
-
return
|
|
38
|
+
return failures;
|
|
20
39
|
}
|
|
21
40
|
|
|
22
41
|
/** GATE-INTRO-RECHECK (0.2.19) — the failures that are bun's «timed out» shape: a `(fail) name` line whose next line is
|