elanous 0.2.8 → 0.2.9

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.
Files changed (195) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/{8894-7317998f6cb97d8c.js → 8894-e263b332208e3957.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-f4d2ecbbae6088d6.js → page-35e2713597dd24d1.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/app/board/{page-2053e49930c82748.js → page-918b656f064577ba.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-d4b6df905f185055.js → page-f972fc1c00a62e88.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/app/bots/{page-a70ba27c33003dd0.js → page-5f30e00693527ebd.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/app/consult/{page-18166f885d831d3e.js → page-3b4edcce364062ea.js} +1 -1
  14. package/apps/pwa/out/_next/static/chunks/app/control/{page-1c9d6cfe68b121c2.js → page-c5794f484c251f44.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/app/exec/{page-147a328753d983e2.js → page-016e2bda04eecb1f.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/app/field/{page-799395a9df7d95aa.js → page-b4d6d9a3b56f2940.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/intake/{page-6a8158b71d1fe9d7.js → page-ec49a466121233ba.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/app/market/{page-c0c0d19d51342d3e.js → page-8b0402a46a749a3d.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-2e002ad8faa43291.js → page-037f83e2a1edc8e2.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/app/morning/{page-b672e02e4bec8deb.js → page-adfbd2ba9598e59a.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/app/observatory/{page-9db2226f38c542fb.js → page-0cf318e9dcee2bbf.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/app/{page-70ee65f5f7a151dc.js → page-1a8e4807292f6b17.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-092e1bcf27d751cc.js → page-de68e2205794037d.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/app/sessions/{page-eb52580c4b75b905.js → page-c71c33a573230672.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-7464c1987dd76e6d.js → page-0df30e0c7e50148a.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/setup/{page-085847b088675978.js → page-4647be5dbcbd0795.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/app/share/{page-9fe9d38c36999eb4.js → page-e025892bda74b743.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/app/term/{page-295a02b1026b8255.js → page-72cbc1c8cdd0f65d.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/app/workflows/{page-2e367075ffdbc062.js → page-7df9243ed021a4cc.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-647ed2b66c1d49f1.js → page-4498c3853f4f688d.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +1 -0
  47. package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +1 -0
  48. package/apps/pwa/out/approvals/index.html +1 -1
  49. package/apps/pwa/out/approvals/index.txt +30 -29
  50. package/apps/pwa/out/autopilot/index.html +1 -1
  51. package/apps/pwa/out/autopilot/index.txt +30 -29
  52. package/apps/pwa/out/board/index.html +1 -1
  53. package/apps/pwa/out/board/index.txt +30 -29
  54. package/apps/pwa/out/botlab/index.html +1 -1
  55. package/apps/pwa/out/botlab/index.txt +27 -26
  56. package/apps/pwa/out/bots/index.html +1 -1
  57. package/apps/pwa/out/bots/index.txt +27 -26
  58. package/apps/pwa/out/chat/index.html +1 -1
  59. package/apps/pwa/out/chat/index.txt +27 -26
  60. package/apps/pwa/out/consult/index.html +1 -1
  61. package/apps/pwa/out/consult/index.txt +30 -29
  62. package/apps/pwa/out/control/index.html +1 -1
  63. package/apps/pwa/out/control/index.txt +30 -29
  64. package/apps/pwa/out/design-check/index.html +1 -1
  65. package/apps/pwa/out/design-check/index.txt +30 -29
  66. package/apps/pwa/out/editor/index.html +1 -1
  67. package/apps/pwa/out/editor/index.txt +30 -29
  68. package/apps/pwa/out/exec/index.html +1 -1
  69. package/apps/pwa/out/exec/index.txt +30 -29
  70. package/apps/pwa/out/field/index.html +1 -1
  71. package/apps/pwa/out/field/index.txt +30 -29
  72. package/apps/pwa/out/healthz +1 -1
  73. package/apps/pwa/out/index.html +1 -1
  74. package/apps/pwa/out/index.txt +27 -26
  75. package/apps/pwa/out/intake/index.html +1 -1
  76. package/apps/pwa/out/intake/index.txt +30 -29
  77. package/apps/pwa/out/live/index.html +1 -1
  78. package/apps/pwa/out/live/index.txt +30 -29
  79. package/apps/pwa/out/market/index.html +1 -1
  80. package/apps/pwa/out/market/index.txt +27 -26
  81. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  82. package/apps/pwa/out/missions/placeholder/index.txt +27 -26
  83. package/apps/pwa/out/morning/index.html +1 -1
  84. package/apps/pwa/out/morning/index.txt +30 -29
  85. package/apps/pwa/out/observatory/index.html +1 -1
  86. package/apps/pwa/out/observatory/index.txt +30 -29
  87. package/apps/pwa/out/ops/checklist/index.html +1 -0
  88. package/apps/pwa/out/ops/checklist/index.txt +30 -0
  89. package/apps/pwa/out/ops/release/index.html +1 -0
  90. package/apps/pwa/out/ops/release/index.txt +30 -0
  91. package/apps/pwa/out/reflection/index.html +1 -1
  92. package/apps/pwa/out/reflection/index.txt +28 -27
  93. package/apps/pwa/out/scheduler/index.html +1 -1
  94. package/apps/pwa/out/scheduler/index.txt +30 -29
  95. package/apps/pwa/out/sessions/index.html +1 -1
  96. package/apps/pwa/out/sessions/index.txt +27 -26
  97. package/apps/pwa/out/settings/devices/index.html +1 -1
  98. package/apps/pwa/out/settings/devices/index.txt +30 -29
  99. package/apps/pwa/out/settings/index.html +1 -1
  100. package/apps/pwa/out/settings/index.txt +30 -29
  101. package/apps/pwa/out/setup/done/index.html +1 -1
  102. package/apps/pwa/out/setup/done/index.txt +30 -29
  103. package/apps/pwa/out/setup/index.html +1 -1
  104. package/apps/pwa/out/setup/index.txt +30 -29
  105. package/apps/pwa/out/share/index.html +1 -1
  106. package/apps/pwa/out/share/index.txt +30 -29
  107. package/apps/pwa/out/showroom/index.html +1 -1
  108. package/apps/pwa/out/showroom/index.txt +27 -26
  109. package/apps/pwa/out/tasks/index.html +1 -1
  110. package/apps/pwa/out/tasks/index.txt +30 -29
  111. package/apps/pwa/out/term/index.html +1 -1
  112. package/apps/pwa/out/term/index.txt +30 -29
  113. package/apps/pwa/out/trace/index.html +1 -1
  114. package/apps/pwa/out/trace/index.txt +30 -29
  115. package/apps/pwa/out/vault/index.html +1 -1
  116. package/apps/pwa/out/vault/index.txt +30 -29
  117. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  118. package/apps/pwa/out/workflows/chat-ui/index.txt +30 -29
  119. package/apps/pwa/out/workflows/index.html +1 -1
  120. package/apps/pwa/out/workflows/index.txt +30 -29
  121. package/apps/pwa/out/workspace/index.html +1 -1
  122. package/apps/pwa/out/workspace/index.txt +30 -29
  123. package/apps/pwa/out/worktrees/index.html +1 -1
  124. package/apps/pwa/out/worktrees/index.txt +30 -29
  125. package/graphs/release/recipes.yaml +3 -0
  126. package/graphs/release/release-loop.yaml +3 -1
  127. package/graphs/test-diet/nightly-audit.yaml +18 -0
  128. package/graphs/test-diet/recipes.yaml +3 -0
  129. package/package.json +1 -1
  130. package/plugins/doc-draft/graphs/run-step.ts +1 -1
  131. package/scripts/release-loop/cutoff.ts +20 -2
  132. package/scripts/release-loop/export-check-node.ts +85 -0
  133. package/scripts/release-loop/gate-node.ts +18 -4
  134. package/scripts/release-loop/node-verdict.ts +8 -1
  135. package/scripts/test-diet/lib.ts +1 -0
  136. package/scripts/test-diet/node.ts +56 -14
  137. package/src/auth/setup-link-tokens.fixture.ts +19 -0
  138. package/src/auth/setup-link-tokens.ts +153 -0
  139. package/src/budget/unified-usage.ts +75 -0
  140. package/src/channel-bot-token.ts +37 -10
  141. package/src/chat/index.ts +9 -9
  142. package/src/cli/op-proxy-sync.ts +83 -0
  143. package/src/cli/pr-cli.ts +6 -2
  144. package/src/cli/release-cli.ts +41 -1
  145. package/src/dashboard/dashboard-status-lines.ts +45 -0
  146. package/src/dashboard/first-screen-band.ts +35 -0
  147. package/src/dashboard/index.ts +70 -13
  148. package/src/dashboard/provider-slash-runtime.ts +28 -11
  149. package/src/dashboard/slash-runtime/dashboard-handlers.ts +10 -0
  150. package/src/dashboard/turn-stream-formatter.ts +1 -1
  151. package/src/decisions/decision-cards.ts +1 -1
  152. package/src/index.ts +16 -4
  153. package/src/maturity/feature-maturity.ts +2 -0
  154. package/src/nexus/api/http-server.ts +20 -0
  155. package/src/nexus/api/meta-api.ts +27 -0
  156. package/src/nexus/api/operator.ts +61 -0
  157. package/src/nexus/api/ops-api.ts +139 -0
  158. package/src/nexus/api/ops-seats-sources.ts +65 -0
  159. package/src/nexus/api/ops-seats.ts +114 -0
  160. package/src/nexus/api/public-routes.ts +14 -1
  161. package/src/nexus/api/setup-claim.ts +21 -0
  162. package/src/nexus/config/secrets/file-backend.ts +56 -18
  163. package/src/onboarding/first-run-doctor.ts +54 -0
  164. package/src/release-loop/checklist.ts +5 -64
  165. package/src/release-loop/feature-store.ts +327 -0
  166. package/src/release-loop/manifest.ts +59 -5
  167. package/src/seat-dispatch/ceo-commands.ts +65 -0
  168. package/src/skills/tools/usage-slash.ts +8 -7
  169. package/src/telegram-commands.ts +16 -0
  170. package/src/telegram-run.ts +83 -13
  171. package/src/thinking-line.ts +28 -20
  172. package/src/tui/chat/execution-badge.ts +1 -1
  173. package/src/ux-sim/turn-states.ts +1 -1
  174. package/src/version/packed-revision.json +1 -1
  175. package/apps/pwa/out/_next/static/chunks/4836-3084c58c1725a40b.js +0 -1
  176. package/apps/pwa/out/_next/static/chunks/9454-a3e0953307216c58.js +0 -1
  177. package/apps/pwa/out/_next/static/chunks/app/approvals/page-9aa47b0bc6d570ff.js +0 -1
  178. package/apps/pwa/out/_next/static/chunks/app/chat/page-186fc6952f027acc.js +0 -1
  179. package/apps/pwa/out/_next/static/chunks/app/design-check/page-cbbe03c0da7b081a.js +0 -1
  180. package/apps/pwa/out/_next/static/chunks/app/editor/page-c108ff1fdb665c97.js +0 -1
  181. package/apps/pwa/out/_next/static/chunks/app/layout-9567560270857531.js +0 -1
  182. package/apps/pwa/out/_next/static/chunks/app/live/page-e7ed3d010153d818.js +0 -1
  183. package/apps/pwa/out/_next/static/chunks/app/not-found-1ba4a5d857276334.js +0 -1
  184. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0bb8e43203efb23b.js +0 -1
  185. package/apps/pwa/out/_next/static/chunks/app/settings/page-e573437b0a1c728f.js +0 -1
  186. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-294300625e49e4d3.js +0 -1
  187. package/apps/pwa/out/_next/static/chunks/app/showroom/page-d8ab4d1489223459.js +0 -1
  188. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6141f67f531d8b6a.js +0 -1
  189. package/apps/pwa/out/_next/static/chunks/app/trace/page-1eb9a0e1e054209d.js +0 -1
  190. package/apps/pwa/out/_next/static/chunks/app/vault/page-82efa177a30f3741.js +0 -1
  191. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d0be51cec4f62606.js +0 -1
  192. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ba058c56e38f2792.js +0 -1
  193. package/apps/pwa/out/_next/static/css/5ef72a618a8994f3.css +0 -1
  194. package/apps/pwa/out/_next/static/lywc8m_HDzH9MKSDQhyEj/_buildManifest.js +0 -1
  195. /package/apps/pwa/out/_next/static/{lywc8m_HDzH9MKSDQhyEj → bFI5EEwg7T6aG88ibX4Zq}/_ssgManifest.js +0 -0
@@ -1,32 +1,33 @@
1
1
  1:"$Sreact.fragment"
2
- 2:I[67976,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"ServiceWorkerRegister"]
3
- 3:I[12248,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"NewBuildBanner"]
4
- 4:I[38519,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"DaemonProvider"]
5
- 5:I[8687,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"NexusClientProvider"]
6
- 6:I[94936,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"ThemeProvider"]
7
- 7:I[85039,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"TooltipProvider"]
8
- 8:I[21545,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"ToastProvider"]
9
- 9:I[85258,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"AppShell"]
10
- a:I[51411,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-a3e0953307216c58.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-9567560270857531.js"],"MaturityBanner"]
11
- b:I[57048,[],""]
12
- c:I[75854,[],""]
13
- d:I[70766,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","7990","static/chunks/7990-e12efba616f46e03.js","6416","static/chunks/6416-505ba707cacafbba.js","9454","static/chunks/9454-a3e0953307216c58.js","4345","static/chunks/app/not-found-1ba4a5d857276334.js"],"default"]
14
- e:I[79013,[],"ClientPageRoot"]
15
- f:I[81403,["920","static/chunks/920-f7dceb78f1c585ef.js","6998","static/chunks/6998-a654fe5c58271600.js","2375","static/chunks/2375-cb6debea56cce4fb.js","2975","static/chunks/app/worktrees/page-ba058c56e38f2792.js"],"default"]
16
- 12:I[78357,[],"OutletBoundary"]
17
- 14:I[70112,[],"AsyncMetadataOutlet"]
18
- 16:I[78357,[],"ViewportBoundary"]
19
- 18:I[78357,[],"MetadataBoundary"]
20
- 19:"$Sreact.suspense"
21
- 1b:I[26324,[],""]
2
+ 2:I[67976,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"ServiceWorkerRegister"]
3
+ 3:I[12248,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"NewBuildBanner"]
4
+ 4:I[38519,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"DaemonProvider"]
5
+ 5:I[77884,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"OperatorRoleDefault"]
6
+ 6:I[8687,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"NexusClientProvider"]
7
+ 7:I[94936,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"ThemeProvider"]
8
+ 8:I[85039,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"TooltipProvider"]
9
+ 9:I[21545,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"ToastProvider"]
10
+ a:I[85258,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"AppShell"]
11
+ b:I[51411,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","6062","static/chunks/6062-73e68343a9814f6a.js","7990","static/chunks/7990-e12efba616f46e03.js","6998","static/chunks/6998-a654fe5c58271600.js","1201","static/chunks/1201-09613bce624467c0.js","7032","static/chunks/7032-f4ef698518fba61c.js","8519","static/chunks/8519-5632377cce994f86.js","2375","static/chunks/2375-cb6debea56cce4fb.js","9454","static/chunks/9454-139040d37c79dbc9.js","8067","static/chunks/8067-d976b441a104ab74.js","8619","static/chunks/8619-4365e03a2862830f.js","5791","static/chunks/5791-bb82743fa6299562.js","7177","static/chunks/app/layout-f72db356744ceade.js"],"MaturityBanner"]
12
+ c:I[57048,[],""]
13
+ d:I[75854,[],""]
14
+ e:I[70766,["2977","static/chunks/2977-e38442e86289f1d3.js","920","static/chunks/920-f7dceb78f1c585ef.js","7990","static/chunks/7990-e12efba616f46e03.js","6416","static/chunks/6416-505ba707cacafbba.js","9454","static/chunks/9454-139040d37c79dbc9.js","4345","static/chunks/app/not-found-46fedff57d4bec67.js"],"default"]
15
+ f:I[79013,[],"ClientPageRoot"]
16
+ 10:I[81403,["920","static/chunks/920-f7dceb78f1c585ef.js","6998","static/chunks/6998-a654fe5c58271600.js","2375","static/chunks/2375-cb6debea56cce4fb.js","2975","static/chunks/app/worktrees/page-35bedde6d885f08f.js"],"default"]
17
+ 13:I[78357,[],"OutletBoundary"]
18
+ 15:I[70112,[],"AsyncMetadataOutlet"]
19
+ 17:I[78357,[],"ViewportBoundary"]
20
+ 19:I[78357,[],"MetadataBoundary"]
21
+ 1a:"$Sreact.suspense"
22
+ 1c:I[26324,[],""]
22
23
  :HL["/app/_next/static/media/22a5144ee8d83bca-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
23
- :HL["/app/_next/static/css/5ef72a618a8994f3.css","style"]
24
+ :HL["/app/_next/static/css/f92f63a5df0ba229.css","style"]
24
25
  :HL["/app/_next/static/css/04dabcbcc4bfa6db.css","style"]
25
- 0:{"P":null,"b":"lywc8m_HDzH9MKSDQhyEj","p":"/app","c":["","worktrees",""],"i":false,"f":[[["",{"children":["worktrees",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/app/_next/static/css/5ef72a618a8994f3.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/app/_next/static/css/04dabcbcc4bfa6db.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"ko","className":"font-sans __variable_45c93f","children":[["$","head",null,{"children":["$","link",null,{"rel":"preload","as":"font","type":"font/ttf","href":"/app/fonts/JetBrainsMonoNerdFontMono-Regular.ttf","crossOrigin":"anonymous"}]}],["$","body",null,{"className":"min-h-screen bg-background text-foreground antialiased","children":[["$","$L2",null,{}],["$","$L3",null,{}],["$","$L4",null,{"children":["$","$L5",null,{"children":["$","$L6",null,{"children":["$","$L7",null,{"children":["$","$L8",null,{"children":["$","$L9",null,{"children":[["$","$La",null,{}],["$","$Lb",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","$Ld",null,{}],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]]}]}]}]}]}]}]]}]]}]]}],{"children":["worktrees",["$","$1","c",{"children":[null,["$","$Lb",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Lc",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Le",null,{"Component":"$f","searchParams":{},"params":{},"promises":["$@10","$@11"]}],null,["$","$L12",null,{"children":["$L13",["$","$L14",null,{"promise":"$@15"}]]}]]}],{},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$L16",null,{"children":"$L17"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L18",null,{"children":["$","div",null,{"hidden":true,"children":["$","$19",null,{"fallback":null,"children":"$L1a"}]}]}]]}],false]],"m":"$undefined","G":["$1b",[]],"s":false,"S":true}
26
- 10:{}
27
- 11:"$0:f:0:1:2:children:2:children:1:props:children:0:props:params"
28
- 17:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1"}],["$","meta","2",{"name":"theme-color","content":"#1e1e2e"}]]
29
- 13:null
30
- 1c:I[48592,[],"IconMark"]
31
- 15:{"metadata":[["$","title","0",{"children":"elanous"}],["$","meta","1",{"name":"description","content":"elanous — voice · chat · intake · control · terminal."}],["$","meta","2",{"name":"application-name","content":"elanous"}],["$","link","3",{"rel":"manifest","href":"/app/manifest.webmanifest","crossOrigin":"$undefined"}],["$","link","4",{"rel":"icon","href":"/app/icons/elanous-32.png","sizes":"32x32","type":"image/png"}],["$","link","5",{"rel":"icon","href":"/app/icons/elanous-16.png","sizes":"16x16","type":"image/png"}],["$","link","6",{"rel":"apple-touch-icon","href":"/app/icons/elanous-180.png","sizes":"180x180","type":"image/png"}],["$","$L1c","7",{}]],"error":null,"digest":"$undefined"}
32
- 1a:"$15:metadata"
26
+ 0:{"P":null,"b":"bFI5EEwg7T6aG88ibX4Zq","p":"/app","c":["","worktrees",""],"i":false,"f":[[["",{"children":["worktrees",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/app/_next/static/css/f92f63a5df0ba229.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/app/_next/static/css/04dabcbcc4bfa6db.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"ko","className":"font-sans __variable_45c93f","children":[["$","head",null,{"children":["$","link",null,{"rel":"preload","as":"font","type":"font/ttf","href":"/app/fonts/JetBrainsMonoNerdFontMono-Regular.ttf","crossOrigin":"anonymous"}]}],["$","body",null,{"className":"min-h-screen bg-background text-foreground antialiased","children":[["$","$L2",null,{}],["$","$L3",null,{}],["$","$L4",null,{"children":[["$","$L5",null,{}],["$","$L6",null,{"children":["$","$L7",null,{"children":["$","$L8",null,{"children":["$","$L9",null,{"children":["$","$La",null,{"children":[["$","$Lb",null,{}],["$","$Lc",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Ld",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","$Le",null,{}],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]]}]}]}]}]}]]}]]}]]}]]}],{"children":["worktrees",["$","$1","c",{"children":[null,["$","$Lc",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$Ld",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lf",null,{"Component":"$10","searchParams":{},"params":{},"promises":["$@11","$@12"]}],null,["$","$L13",null,{"children":["$L14",["$","$L15",null,{"promise":"$@16"}]]}]]}],{},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$L17",null,{"children":"$L18"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L19",null,{"children":["$","div",null,{"hidden":true,"children":["$","$1a",null,{"fallback":null,"children":"$L1b"}]}]}]]}],false]],"m":"$undefined","G":["$1c",[]],"s":false,"S":true}
27
+ 11:{}
28
+ 12:"$0:f:0:1:2:children:2:children:1:props:children:0:props:params"
29
+ 18:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1, maximum-scale=1"}],["$","meta","2",{"name":"theme-color","content":"#1e1e2e"}]]
30
+ 14:null
31
+ 1d:I[48592,[],"IconMark"]
32
+ 16:{"metadata":[["$","title","0",{"children":"elanous"}],["$","meta","1",{"name":"description","content":"elanous — voice · chat · intake · control · terminal."}],["$","meta","2",{"name":"application-name","content":"elanous"}],["$","link","3",{"rel":"manifest","href":"/app/manifest.webmanifest","crossOrigin":"$undefined"}],["$","link","4",{"rel":"icon","href":"/app/icons/elanous-32.png","sizes":"32x32","type":"image/png"}],["$","link","5",{"rel":"icon","href":"/app/icons/elanous-16.png","sizes":"16x16","type":"image/png"}],["$","link","6",{"rel":"apple-touch-icon","href":"/app/icons/elanous-180.png","sizes":"180x180","type":"image/png"}],["$","$L1d","7",{}]],"error":null,"digest":"$undefined"}
33
+ 1b:"$16:metadata"
@@ -11,6 +11,9 @@ gate:
11
11
  command: 'bun scripts/release-loop/gate-node.ts --json'
12
12
  # 4h — the Pod gate took 2h02m on 09-30 (G1f ②) and the 0.2.5 loop was cut at exactly 2h with no verdict; K9 (≤15 min) is the real fix.
13
13
  timeout_ms: 14400000
14
+ export-check:
15
+ command: 'bun scripts/release-loop/export-check-node.ts'
16
+ timeout_ms: 1800000
14
17
  pwa:
15
18
  command: 'bun scripts/release-loop/node-verdict.ts pwa'
16
19
  timeout_ms: 1800000
@@ -15,6 +15,7 @@ nodes:
15
15
  - { node_id: cutoff, kind: judge, recipe: 'cmd:cutoff', max_visits: 1 }
16
16
  - { node_id: checklist-gate, kind: gate, recipe: 'cmd:checklist-gate', max_visits: 1 }
17
17
  - { node_id: gate, kind: gate, recipe: 'cmd:gate', max_visits: 1, notify: start }
18
+ - { node_id: export-check, kind: gate, recipe: 'cmd:export-check', max_visits: 1 }
18
19
  - { node_id: pwa, kind: gate, recipe: 'cmd:pwa', max_visits: 1, notify: start }
19
20
  - { node_id: prepare, kind: agent, recipe: 'cmd:prepare', max_visits: 1, notify: start }
20
21
  - { node_id: upgrade, kind: gate, recipe: 'cmd:upgrade', max_visits: 1 }
@@ -36,7 +37,8 @@ edges:
36
37
  - { from: version-release, on: outcome, map: { ok: cutoff, fail: failed, error: failed } }
37
38
  - { from: cutoff, on: outcome, map: { ok: checklist-gate, fail: failed, error: failed } }
38
39
  - { from: checklist-gate, on: outcome, map: { ok: gate, fail: failed, error: failed } }
39
- - { from: gate, on: outcome, map: { ok: pwa, fail: failed, error: failed } }
40
+ - { from: gate, on: outcome, map: { ok: export-check, fail: failed, error: failed } }
41
+ - { from: export-check, on: outcome, map: { ok: pwa, fail: failed, error: failed } }
40
42
  - { from: pwa, on: outcome, map: { ok: prepare, fail: failed, error: failed } }
41
43
  - { from: prepare, on: outcome, map: { ok: upgrade, fail: failed, error: failed } }
42
44
  - { from: upgrade, on: outcome, map: { ok: tui, fail: failed, error: failed } }
@@ -0,0 +1,18 @@
1
+ # TD1b — whole-repository audits run alone; record their results and draft a card on failure.
2
+ graph_id: nightly-audit
3
+ loop:
4
+ title: 야간 저장소 감사
5
+ description: 게이트에서 제외한 감사 다섯 파일을 단독으로 재고 원장과 실패 카드 초안을 남긴다
6
+ trigger:
7
+ events: [manual]
8
+ version: 1
9
+ entry_node: audit
10
+ terminal_nodes: [done, failed]
11
+ nodes:
12
+ - { node_id: audit, kind: gate, recipe: 'cmd:audit', max_visits: 1 }
13
+ - { node_id: record, kind: judge, recipe: 'cmd:record', max_visits: 1 }
14
+ - { node_id: done, kind: gate, max_visits: 1 }
15
+ - { node_id: failed, kind: gate, max_visits: 1 }
16
+ edges:
17
+ - { from: audit, on: outcome, map: { ok: record, fail: record, error: record } }
18
+ - { from: record, on: outcome, map: { ok: done, fail: failed, error: failed } }
@@ -4,6 +4,9 @@ pick:
4
4
  measure:
5
5
  command: 'bun scripts/test-diet/node.ts measure'
6
6
  timeout_ms: 14400000
7
+ audit:
8
+ command: 'bun scripts/test-diet/node.ts audit'
9
+ timeout_ms: 14400000
7
10
  record:
8
11
  command: 'bun scripts/test-diet/node.ts record'
9
12
  timeout_ms: 300000
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elanous",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Self-healing coding harness where eyes, hands, and memory all turn on one sentence — it authors its own goals, implements them in isolated worktrees, and reviews its own work.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Elanvital AI",
@@ -55,7 +55,7 @@ function validate(markdown: string, kind: Kind): string {
55
55
  if (!/^# [^\n#]+$/u.test(lines[0] ?? '') || !lines.slice(1).join('').trim()) return 'title or body missing';
56
56
  const words = wordCount(markdown);
57
57
  if (words < 15 || words > limits[kind]) return `length must be 15–${limits[kind]} words`;
58
- if (/\[[^\]]*\]|\{\{[^}]*\}\}|<[^>]+>|(?:TODO|TBD|작성 예정|내용 입력|빈칸)/iu.test(markdown)) return 'unfilled placeholder';
58
+ if (/\[[^\]]*\](?!\()|\{\{[^}]*\}\}|<[^>]+>|(?:TODO|TBD|작성 예정|내용 입력|빈칸)/iu.test(markdown)) return 'unfilled placeholder';
59
59
  if (/(?:게시|발행|발송|전송|결제)(?:\s*완료|했|됐|되었|하였)|\b(?:published|posted|sent|paid)\b/iu.test(markdown)) return 'unverified publication or transaction claim';
60
60
  if (kind === 'exec-onepager' && sections.some(section => {
61
61
  const match = new RegExp(`^## ${section}[ \\t]*\\r?\\n([\\s\\S]*?)(?=^## |$(?![\\s\\S]))`, 'mu').exec(markdown);
@@ -4,13 +4,14 @@ import { mkdirSync, realpathSync, writeFileSync } from 'node:fs';
4
4
  import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
5
5
  import { debug } from '../../src/debug/log.js';
6
6
  import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
7
- import { buildReleaseManifest, type ReleaseLanding } from '../../src/release-loop/manifest.js';
7
+ import { buildReleaseManifest, parseNextMdNotes, type NextMdNote, type ReleaseLanding } from '../../src/release-loop/manifest.js';
8
8
  import { readReleaseNotes, releaseNotesDir } from '../../src/release-loop/release-note.js';
9
9
  import { queryRunningRuns } from '../../src/self-implement/running-runs.js';
10
10
  import { loadFederatedRunLedger } from '../../src/self-implement/run-ledger.js';
11
11
 
12
12
  const SEED = 'c1cc37478';
13
13
  const CLI_DOC = 'release/public/docs/cli.md';
14
+ const NEXT_MD = 'release/next.md';
14
15
 
15
16
  function git(args: string[], optional = false): string | null {
16
17
  const result = spawnSync('git', args, { cwd: process.cwd(), encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
@@ -61,6 +62,22 @@ function landingAt(sha: string, title: string): ReleaseLanding {
61
62
  };
62
63
  }
63
64
 
65
+ /** next.md lines at the cutoff, each tied to the last landing in range whose diff added that exact line. */
66
+ function nextMdNotes(cutoff: string, landings: ReleaseLanding[]): NextMdNote[] {
67
+ const text = git(['show', `${cutoff}:${NEXT_MD}`], true);
68
+ if (!text) return [];
69
+ const addedBy = new Map<string, string>();
70
+ for (const landing of landings) {
71
+ if (!landing.changedFiles.includes(NEXT_MD)) continue;
72
+ const diff = requiredGit(['show', '-m', '--first-parent', '--format=', '-U0', landing.sha, '--', NEXT_MD]);
73
+ for (const line of diff.split('\n')) if (line.startsWith('+') && !line.startsWith('+++')) addedBy.set(line.slice(1).trim(), landing.sha);
74
+ }
75
+ return parseNextMdNotes(text).map((note) => {
76
+ const sha = note.raw ? addedBy.get(note.raw) : undefined;
77
+ return { kind: note.kind, line: note.line, ...(sha ? { sha } : {}) };
78
+ });
79
+ }
80
+
64
81
  function runningGoalPaths(): string[] {
65
82
  const repo = process.cwd();
66
83
  const paths: string[] = [];
@@ -119,10 +136,11 @@ export function main(args: string[] = process.argv.slice(2)): void {
119
136
  const notes = readReleaseNotes(releaseNotesDir(instanceRoot));
120
137
  debug.log('release.notes', 'read', { fragments: notes.size, problems: notes.problems });
121
138
  const manifest = buildReleaseManifest({
122
- version, baseline: { ref: baseline.ref, sha: baselineSha }, cutoff: { sha: cutoff }, landings, notes,
139
+ version, baseline: { ref: baseline.ref, sha: baselineSha }, cutoff: { sha: cutoff }, landings, notes, nextMd: nextMdNotes(cutoff, landings),
123
140
  runningGoalPaths: runningGoalPaths(), publicCommandsBefore: commandsAt(baselineSha), publicCommandsAfter: commandsAt(cutoff),
124
141
  });
125
142
  const output = { ...manifest, baselineSource: baseline.source };
143
+ debug.log('release-loop.notes', 'fragments', { version, ...manifest.fragments });
126
144
  const directory = join(instanceRoot, 'release', version);
127
145
  mkdirSync(directory, { recursive: true });
128
146
  writeFileSync(join(directory, 'manifest.json'), JSON.stringify(output, null, 2) + '\n');
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env bun
2
+ import { existsSync, mkdtempSync, readFileSync, realpathSync, rmSync, symlinkSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { finishNode, nodeOutput, readGraphContext, runCommand, type CommandResult, type CommandRunner } from './node-verdict.js';
6
+
7
+ export interface ExportCheckResult extends Record<string, unknown> {
8
+ outcome: 'ok' | 'fail';
9
+ verdict: 'pass' | 'fail';
10
+ summary: string;
11
+ step: 'export' | 'build';
12
+ tail: string;
13
+ }
14
+
15
+ function failed(step: ExportCheckResult['step'], message: string, result?: CommandResult): ExportCheckResult {
16
+ const tail = (result ? result.stderr || result.stdout : message).trim().slice(-300);
17
+ return { outcome: 'fail', verdict: 'fail', summary: `${step} failed: ${message}${result ? ` (rc=${result.status})` : ''}`, step, tail };
18
+ }
19
+
20
+ /** Check the same public export and PWA build as release prepare, without cloning or writing to a public remote. */
21
+ export function runExportCheck(run: CommandRunner = runCommand, repoRoot = process.cwd()): ExportCheckResult {
22
+ const context = readGraphContext();
23
+ const commit = nodeOutput(context, 'version-release', 'commit');
24
+ if (context.outputs.gate?.outcome !== 'ok') return failed('export', 'gate did not pass');
25
+ const root = resolve(repoRoot);
26
+ const out = mkdtempSync(join(tmpdir(), 'elanous-export-check-'));
27
+ const sourceDir = join(out, 'source');
28
+ let added = false;
29
+ let step: ExportCheckResult['step'] = 'export';
30
+ let result: ExportCheckResult = failed(step, 'check incomplete');
31
+ try {
32
+ const modulesRoot = dirname(realpathSync(join(root, 'node_modules')));
33
+ const add = run('git', ['worktree', 'add', '-q', '--detach', sourceDir, commit], root);
34
+ if (add.status !== 0) result = failed('export', 'git worktree add', add);
35
+ else {
36
+ added = true;
37
+ const head = run('git', ['rev-parse', 'HEAD'], sourceDir);
38
+ if (head.status !== 0 || head.stdout.trim() !== commit) result = failed('export', 'cut commit mismatch', head);
39
+ else {
40
+ const version = (JSON.parse(readFileSync(join(sourceDir, 'package.json'), 'utf8')) as { version?: string }).version;
41
+ if (version !== context.input.version) result = failed('export', `package.json version ${version} != ${context.input.version}`);
42
+ else {
43
+ symlinkSync(join(modulesRoot, 'node_modules'), join(sourceDir, 'node_modules'), 'dir');
44
+ const exported = run('bun', ['scripts/public-export.ts', '--out', join(out, 'export')], sourceDir);
45
+ if (exported.status !== 0) result = failed('export', 'public export', exported);
46
+ else {
47
+ step = 'build';
48
+ const publicDir = join(out, 'export');
49
+ symlinkSync(join(modulesRoot, 'node_modules'), join(publicDir, 'node_modules'), 'dir');
50
+ const pwaModules = join(modulesRoot, 'apps', 'pwa', 'node_modules');
51
+ if (existsSync(pwaModules) && existsSync(join(publicDir, 'apps', 'pwa'))) symlinkSync(pwaModules, join(publicDir, 'apps', 'pwa', 'node_modules'), 'dir');
52
+ const built = run('bun', ['bin/elanous.mjs', 'nexus', 'build'], publicDir);
53
+ result = built.status === 0 && existsSync(join(publicDir, 'apps', 'pwa', 'out', 'index.html'))
54
+ ? { outcome: 'ok', verdict: 'pass', summary: `public export and PWA build ${commit.slice(0, 12)}`, step: 'build', tail: '' }
55
+ : failed('build', 'PWA build or out/index.html missing', built);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ } catch (error) {
61
+ result = failed(step, error instanceof Error ? error.message : String(error));
62
+ } finally {
63
+ try {
64
+ if (added) {
65
+ const removed = run('git', ['worktree', 'remove', '--force', sourceDir], root);
66
+ if (removed.status !== 0) result = failed(step, 'git worktree remove', removed);
67
+ }
68
+ } catch (error) {
69
+ result = failed(step, `git worktree remove: ${error instanceof Error ? error.message : String(error)}`);
70
+ } finally {
71
+ rmSync(out, { recursive: true, force: true });
72
+ }
73
+ }
74
+ return result;
75
+ }
76
+
77
+ if (import.meta.main) {
78
+ let version = '';
79
+ try {
80
+ version = readGraphContext().input.version;
81
+ process.exitCode = finishNode('export-check', version, runExportCheck());
82
+ } catch (error) {
83
+ process.exitCode = finishNode('export-check', version, failed('export', error instanceof Error ? error.message : String(error)));
84
+ }
85
+ }
@@ -125,6 +125,14 @@ export const POD_MEMORY_SOURCE = 'docs/measurements/td1-whole-gate-mechanical-20
125
125
  export const POD_SHARD_FILE_CAP = 27;
126
126
 
127
127
  export const POD_SWEEP_INTEGRATION_ONLY: readonly string[] = ['scripts/install.test.ts'];
128
+ /** Whole-repository audits run alone in the nightly test-diet graph, not in release-gate shards. */
129
+ export const GATE_NIGHTLY_AUDITS: readonly string[] = [
130
+ 'test/f12-sweep.test.ts', // Sweeps the whole repository; 7.8 GB even after TD1a.
131
+ 'scripts/unwired-exports.test.ts', // Compiles and scans all exports; 9.9 GB.
132
+ 'test/guardian/dispatch-surface-contract.test.ts', // Compiles repository-wide dispatch contracts; 8.3 GB.
133
+ 'test/pwa-build-typecheck.test.ts', // Builds and typechecks the whole PWA; 4.2 GB.
134
+ 'test/user-config-mcp.test.ts', // 2.1 GB peak; keep the gate below the 2 GB audit budget.
135
+ ];
128
136
  const tail40 = (output: string) => output.trimEnd().split(/\r?\n/).slice(-40).join('\n');
129
137
  const lastStartedTestFile = (output: string, paths: string[]): string | undefined => {
130
138
  let last: string | undefined;
@@ -211,9 +219,11 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
211
219
  // CDP 시험은 `test:deterministic` 이 스스로 뺀다 — 조각에 그것만 남으면 bun «시험 없음» exit 1 을 «불완전»으로 읽었다(09-30 G1d 실측 둘).
212
220
  // bun 의 탐색은 숨은 디렉터리(`.x/`)를 안 연다 — 사람의 `bun test` 가 한 번도 안 돌리는 빈 픽스처가 조각에 혼자 남아 «Ran 0 tests» 를 «불완전»으로 읽었다(09-30 G1e 5번 조각).
213
221
  const assignable = files.filter((file) => !cdpPatterns.includes(file) && !POD_SWEEP_INTEGRATION_ONLY.includes(file)
214
- && !file.split('/').some((part) => part.startsWith('.')));
222
+ && !GATE_NIGHTLY_AUDITS.includes(file) && !file.split('/').some((part) => part.startsWith('.')));
215
223
  const integrationOnly = files.filter((file) => POD_SWEEP_INTEGRATION_ONLY.includes(file));
216
224
  if (integrationOnly.length) debug.log('release-loop.gate', 'pod-sweep-integration-only', { files: integrationOnly });
225
+ const nightlyAudits = files.filter((file) => GATE_NIGHTLY_AUDITS.includes(file));
226
+ if (nightlyAudits.length) debug.log('release-loop.gate', 'pod-sweep-nightly-audit', { files: nightlyAudits });
217
227
  if (!assignable.length) throw new Error('sweep incomplete: no tests ran');
218
228
  const durations = pod.durationSource ? readFileDurations(pod.durationSource) : new Map<string, number>();
219
229
  const memory = readFileMemory(join(tree, POD_MEMORY_SOURCE));
@@ -427,9 +437,10 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
427
437
  const outputs: string[] = [];
428
438
  let total = { pass: 0, fail: 0, errors: 0, ran: 0, files: 0 };
429
439
  for (const group of groups) {
430
- if (!group.paths.length || !files.some((f) => group.paths.some((p) => f === p || f.startsWith(`${p}/`)))) continue;
440
+ if (!group.paths.length || !files.some((f) => !GATE_NIGHTLY_AUDITS.includes(f) && group.paths.some((p) => f === p || f.startsWith(`${p}/`)))) continue;
431
441
  const start = Date.now();
432
- const groupIgnores = cdpPatterns.filter((pattern) => group.paths.some((p) => pattern === p || pattern.startsWith(`${p}/`)))
442
+ const groupIgnores = [...new Set([...cdpPatterns, ...GATE_NIGHTLY_AUDITS])]
443
+ .filter((pattern) => files.includes(pattern) && group.paths.some((p) => pattern === p || pattern.startsWith(`${p}/`)))
433
444
  .flatMap((pattern) => ['--path-ignore-patterns', pattern]);
434
445
  const run = await command('bun', ['run', 'test:deterministic', ...groupIgnores, ...group.paths.map(asPath)], tree);
435
446
  if (logDir) {
@@ -608,7 +619,10 @@ export async function judgeGate(opts: GateOptions, runner: GateRunner = createGa
608
619
  };
609
620
  let baseline: SweepFailures | undefined = trusted ? { failures: trusted.failures, errors: trusted.errors ?? [] } : undefined;
610
621
  if (!baseline) {
611
- const baseRun = await runner.sweep(await getBaseTree(), join(root, 'release', opts.version, 'gate-logs', 'baseline'));
622
+ // K9b — with no reusable ledger the baseline is swept on the same Pod pool as the cut, not on this host (0.2.6: an
623
+ // hour of local baseline after a 23-minute Pod cut).
624
+ const baseRun = await runner.sweep(await getBaseTree(), join(root, 'release', opts.version, 'gate-logs', 'baseline'),
625
+ opts.pod ? { ...opts.pod, durationSource: join(ledger, 'release', opts.baselineVersion, 'gate-logs', 'cut') } : undefined);
612
626
  baseline = failuresOf(baseRun, 'baseline sweep');
613
627
  }
614
628
  for (const id of [...baseline.failures, ...baseline.errors, ...cut.failures, ...cut.errors]) fileOf(id);
@@ -57,6 +57,11 @@ export function errorResult(error: unknown): { outcome: 'error'; verdict: 'fail'
57
57
  return { outcome: 'error', verdict: 'fail', summary: error instanceof Error ? error.message : String(error) };
58
58
  }
59
59
 
60
+ /** A cut whose notes would show users nothing fails the cutoff instead of shipping a «Plus N internal changes.» page. */
61
+ export function cutoffNotesEmpty(data: Record<string, unknown> | undefined): boolean {
62
+ return Array.isArray(data?.escalate) && (data.escalate as Array<{ kind?: string }>).some((item) => item?.kind === 'notes-empty');
63
+ }
64
+
60
65
  // Existing cutoff/PWA/TUI programs have different output conventions; normalize them at the graph boundary.
61
66
  if (import.meta.main) {
62
67
  const node = process.argv[2];
@@ -78,7 +83,9 @@ if (import.meta.main) {
78
83
  const baseline = data?.baseline as { sha?: string } | undefined;
79
84
  const outcome: NodeOutcome = node === 'cutoff' ? run.status === 0 && data?.version === version && (data?.cutoff as { sha?: string } | undefined)?.sha === commit && typeof baseline?.sha === 'string' ? 'ok' : 'error'
80
85
  : run.status === 0 && (verdict === 'pass' || verdict === 'flaky') ? 'ok' : run.status === 1 ? 'fail' : 'error';
81
- result = { ...data, outcome, verdict: outcome === 'ok' ? verdict === 'flaky' ? 'flaky' : 'pass' : 'fail',
86
+ if (node === 'cutoff' && outcome === 'ok' && cutoffNotesEmpty(data)) {
87
+ result = { ...data, outcome: 'fail', verdict: 'fail', summary: 'cutoff notes-empty — 사용자에게 보일 변경 줄이 0이다(release/next.md 와 PR 노트 조각을 확인하라)' };
88
+ } else result = { ...data, outcome, verdict: outcome === 'ok' ? verdict === 'flaky' ? 'flaky' : 'pass' : 'fail',
82
89
  summary: outcome === 'ok' ? `${node} ${verdict === 'flaky' ? 'flaky' : 'pass'}` : `${node} ${data?.error || run.stderr.trim() || data?.verdict || 'failed'} (rc=${run.status})` };
83
90
  } catch (error) { result = errorResult(error); }
84
91
  process.exitCode = finishNode(node ?? 'unknown', version, result);
@@ -51,6 +51,7 @@ export function judge(m: Measurement, caught90: number): Judged {
51
51
  }
52
52
 
53
53
  export function ledgerPath(root: string): string { return join(root, 'test-diet', 'ledger.jsonl'); }
54
+ export function nightlyAuditLedgerPath(root: string): string { return join(root, 'test-diet', 'nightly-audit.jsonl'); }
54
55
 
55
56
  export function lastLedgerLine(root: string): LedgerLine | null {
56
57
  const path = ledgerPath(root);
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env bun
2
2
  // TD2 graph nodes: pick → measure → record. Shadow only — measures alone on a remote host and drafts a card.
3
- // bun scripts/test-diet/node.ts pick|measure|record (inside `elanous graph run graphs/test-diet/test-diet.yaml`)
3
+ // bun scripts/test-diet/node.ts pick|measure|audit|record (test-diet or nightly-audit graph)
4
4
  import { spawnSync } from 'node:child_process';
5
- import { readFileSync } from 'node:fs';
5
+ import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
6
6
  import { join } from 'node:path';
7
7
  import { debug } from '../../src/debug/log.js';
8
8
  import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
9
- import { appendLedger, costTable, judge, lastLedgerLine, pickRange, writeCardDraft, type Measurement } from './lib.js';
9
+ import { GATE_NIGHTLY_AUDITS } from '../release-loop/gate-node.js';
10
+ import { appendLedger, costTable, judge, lastLedgerLine, nightlyAuditLedgerPath, pickRange, writeCardDraft, type Measurement } from './lib.js';
10
11
 
11
- type Context = { input: Record<string, unknown>; outputs: Record<string, Record<string, unknown>> };
12
+ type Context = { graphId?: string; input: Record<string, unknown>; outputs: Record<string, Record<string, unknown> | null> };
12
13
  function context(): Context {
13
14
  const at = process.env.ELANOUS_GRAPH_CONTEXT;
14
15
  if (!at) throw new Error('ELANOUS_GRAPH_CONTEXT required');
15
16
  const raw = JSON.parse(at.trimStart().startsWith('{') ? at : readFileSync(at, 'utf8')) as Partial<Context>;
16
- return { input: raw.input ?? {}, outputs: raw.outputs ?? {} };
17
+ return { graphId: raw.graphId, input: raw.input ?? {}, outputs: raw.outputs ?? {} };
17
18
  }
18
19
  function emit(result: Record<string, unknown> & { outcome: 'ok' | 'fail' | 'error'; summary: string }): number {
19
20
  console.log(JSON.stringify({ verdict: result.outcome === 'ok' ? 'pass' : 'fail', ...result }));
@@ -34,8 +35,8 @@ function pick(ctx: Context): number {
34
35
  }
35
36
 
36
37
  /** One remote run: shallow clone of the mirror, one install, each file alone with its peak memory. */
37
- function measure(ctx: Context): number {
38
- const picked = ctx.outputs.pick?.files;
38
+ function measure(ctx: Context, audit = false): number {
39
+ const picked = audit ? [...GATE_NIGHTLY_AUDITS] : ctx.outputs.pick?.files;
39
40
  if (!Array.isArray(picked) || picked.length === 0) return emit({ outcome: 'fail', summary: 'nothing picked' });
40
41
  const host = typeof ctx.input.remote === 'string' ? ctx.input.remote : 'node-b';
41
42
  const mirror = typeof ctx.input.mirror === 'string' ? ctx.input.mirror : '~/mirror/elanous-agent.git';
@@ -59,18 +60,58 @@ function measure(ctx: Context): number {
59
60
  // A failing file names its first error, so an environment gap (e.g. no Java on the host) is not read as a test defect.
60
61
  ' why=""; [ "$rc" -ne 0 ] && why=$(grep -v -E "^\\s*$|^bun test|^ *[0-9]+ \\||^error: *$" "$T/err" | grep -m1 -E "Unable to|Cannot find|not found|ENOENT|EACCES|rror" | tr "\\t" " " | cut -c1-160)',
61
62
  ' printf "M\\t%s\\t%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n" "$f" "$e" "${rss:-}" "$rc" "${pass:-}" "${fail:-}" "$why"',
62
- 'done',
63
+ "done <<'TEST_DIET_FILES'", ...picked, 'TEST_DIET_FILES',
63
64
  ].join('\n');
64
- const run = spawnSync('ssh', ['-o', 'BatchMode=yes', host, 'bash', '-s'], { input: `${script}\n${picked.join('\n')}\n`, encoding: 'utf8', timeout: 4 * 3600_000, maxBuffer: 16 * 1024 * 1024 });
65
- // The file list follows the script on stdin; `read` in the loop consumes it.
66
- if (run.status !== 0 && !String(run.stdout).includes('\nM\t')) return emit({ outcome: 'error', summary: `remote measure failed (rc=${run.status}): ${String(run.stderr).trim().slice(0, 200)}` });
67
- const commit = /^COMMIT (\w+)/m.exec(run.stdout)?.[1] ?? '?';
65
+ const run = spawnSync('ssh', ['-o', 'BatchMode=yes', host, 'bash', '-s'], { input: `${script}\n`, encoding: 'utf8', timeout: 4 * 3600_000, maxBuffer: 16 * 1024 * 1024 });
66
+ const remoteError = run.status !== 0 ? `remote measure failed (rc=${run.status ?? 'no exit'}): ${String(run.error ?? run.stderr ?? '').trim().slice(0, 200)}` : undefined;
67
+ if (!audit && remoteError && !String(run.stdout).includes('\nM\t')) return emit({ outcome: 'error', summary: remoteError });
68
+ const commit = /^COMMIT (\w+)/m.exec(String(run.stdout))?.[1] ?? '?';
68
69
  const measurements: Measurement[] = String(run.stdout).split('\n').filter((l) => l.startsWith('M\t')).map((l) => {
69
70
  const [, file, secs, rss, rc, pass, fail, why] = l.split('\t');
70
71
  const num = (v: string | undefined) => (v === undefined || v === '' ? null : Number(v));
71
72
  return { file: file!, secs: Number(secs), rssMb: num(rss), rc: num(rc), pass: num(pass), fail: num(fail), ...(why ? { reason: why } : {}) };
72
73
  });
73
- return emit({ outcome: measurements.length ? 'ok' : 'error', summary: `measured ${measurements.length}/${picked.length} on ${host} at ${commit.slice(0, 9)}`, host, commit, measurements });
74
+ const complete = measurements.length === picked.length && picked.every((file) => measurements.some((m) => m.file === file));
75
+ const summary = remoteError ?? `measured ${measurements.length}/${picked.length} on ${host} at ${commit.slice(0, 9)}`;
76
+ return emit({ outcome: audit ? complete && !remoteError ? 'ok' : 'error' : measurements.length ? 'ok' : 'error',
77
+ summary, host, commit, measurements, ...(remoteError ? { remoteError } : {}) });
78
+ }
79
+
80
+ function recordNightlyAudit(ctx: Context): number {
81
+ const m = ctx.outputs.audit;
82
+ const raw = Array.isArray(m?.measurements) ? m.measurements : [];
83
+ const measured = new Map<string, Measurement>();
84
+ for (const item of raw) {
85
+ if (!item || typeof item !== 'object' || !('file' in item) || typeof item.file !== 'string' || !GATE_NIGHTLY_AUDITS.includes(item.file)) continue;
86
+ const x = item as Partial<Measurement>;
87
+ if (measured.has(item.file) || typeof x.secs !== 'number' || !Number.isFinite(x.secs)
88
+ || (x.rssMb !== null && (typeof x.rssMb !== 'number' || !Number.isFinite(x.rssMb)))
89
+ || (x.rc !== null && (typeof x.rc !== 'number' || !Number.isInteger(x.rc)))
90
+ || (x.pass !== null && (typeof x.pass !== 'number' || !Number.isInteger(x.pass)))
91
+ || (x.fail !== null && (typeof x.fail !== 'number' || !Number.isInteger(x.fail)))) continue;
92
+ measured.set(item.file, x as Measurement);
93
+ }
94
+ const error = typeof m?.remoteError === 'string' ? m.remoteError
95
+ : m?.outcome === 'error' || m?.outcome === 'fail' || !m
96
+ ? typeof m?.summary === 'string' ? m.summary : 'audit execution produced no result' : undefined;
97
+ const results = GATE_NIGHTLY_AUDITS.map((file, index) => {
98
+ const found = measured.get(file);
99
+ const measurement: Measurement = found ?? { file, secs: 0, rssMb: null, rc: null, pass: null, fail: null,
100
+ reason: `not measured: ${typeof m?.summary === 'string' ? m.summary : error ?? 'audit result missing'}` };
101
+ // Even a complete set of file outputs cannot prove a clean audit when the remote process failed afterward.
102
+ return judge(error && measured.size === GATE_NIGHTLY_AUDITS.length && index === 0 && found
103
+ ? { ...found, rc: found.rc === 0 ? null : found.rc, reason: `${error}${found.reason ? `; ${found.reason}` : ''}` } : measurement, 1);
104
+ });
105
+ const line = { at: new Date().toISOString(), range: 'nightly-audit', start: 0, end: results.length - 1,
106
+ next: 0, total: results.length, commit: String(m?.commit ?? '?'), budgetSecs: 0, ...(error ? { error } : {}), results };
107
+ const root = effectiveInstanceRoot();
108
+ const path = nightlyAuditLedgerPath(root);
109
+ mkdirSync(join(root, 'test-diet'), { recursive: true });
110
+ appendFileSync(path, `${JSON.stringify(line)}\n`);
111
+ const card = writeCardDraft(root, line);
112
+ const failing = results.filter((r) => r.verdict === 'failing').length;
113
+ debug.log('test-diet', 'nightly-audit-recorded', { files: results.length, failing, card: card !== null });
114
+ return emit({ outcome: failing ? 'fail' : 'ok', summary: `nightly audit ${results.length} · failing ${failing}${card ? ' · card draft' : ''}`, failing, ledger: path, ...(card ? { card } : {}) });
74
115
  }
75
116
 
76
117
  function record(ctx: Context): number {
@@ -95,7 +136,8 @@ if (import.meta.main) {
95
136
  const step = process.argv[2];
96
137
  try {
97
138
  const ctx = context();
98
- process.exitCode = step === 'pick' ? pick(ctx) : step === 'measure' ? measure(ctx) : step === 'record' ? record(ctx) : emit({ outcome: 'error', summary: `unknown step: ${step}` });
139
+ process.exitCode = step === 'pick' ? pick(ctx) : step === 'measure' ? measure(ctx) : step === 'audit' ? measure(ctx, true)
140
+ : step === 'record' ? (ctx.graphId === 'nightly-audit' || Object.hasOwn(ctx.outputs, 'audit') ? recordNightlyAudit(ctx) : record(ctx)) : emit({ outcome: 'error', summary: `unknown step: ${step}` });
99
141
  } catch (error) {
100
142
  process.exitCode = emit({ outcome: 'error', summary: error instanceof Error ? error.message : String(error) });
101
143
  }
@@ -0,0 +1,19 @@
1
+ import { openSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { dlopen, FFIType } from 'bun:ffi';
4
+ import { claimSetupLinkToken } from './setup-link-tokens.js';
5
+
6
+ const [mode, dir, token, now] = process.argv.slice(2);
7
+ if (mode === 'claim') {
8
+ process.stdout.write(JSON.stringify(claimSetupLinkToken(token, { dir, now: Number(now) })));
9
+ } else if (mode === 'hold') {
10
+ const fd = openSync(join(dir, 'setup-link-tokens.json.lock'), 'r+');
11
+ const libc = dlopen(process.platform === 'darwin' ? '/usr/lib/libSystem.B.dylib' : 'libc.so.6', {
12
+ flock: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },
13
+ });
14
+ if (libc.symbols.flock(fd, 2) !== 0) throw new Error('failed to acquire lock');
15
+ process.stdout.write('locked\n');
16
+ await new Promise<void>(() => { setInterval(() => {}, 1000); });
17
+ } else {
18
+ throw new Error(`unknown fixture mode: ${mode}`);
19
+ }