elanous 0.2.41 → 0.2.42

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 (589) 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/{GiOLWmt4MqDZePubBjA4Q → X1ucLw10Cds_h614NoEnh}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/{5159.115f1c2ca471386c.js → 1063.2fb8a9dc55c731f2.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +36 -0
  7. package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/{9048.212083de42d25be3.js → 1262.e804feb8fd1acb8c.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/{4527.a69f2894d1bc9f4a.js → 1487.2f67b79444062da6.js} +1 -1
  13. package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +32 -0
  15. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +286 -0
  21. package/apps/pwa/out/_next/static/chunks/2160.a097e7b138ae1c55.js +23 -0
  22. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +34 -0
  25. package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{530.d26346e18089640a.js → 2690.0521c738b7749931.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/{4702.4a4adc1f16d7c93b.js → 2974.595d1e29d040cb6a.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/{2263.e09b6edea33bad2d.js → 3207.a756c95e9ec8c3c8.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/{9541.eb8e2f8480c7feca.js → 3285.89ee2f298682f5e5.js} +2 -2
  34. package/apps/pwa/out/_next/static/chunks/{9507.7026657a2f47eb64.js → 3347.f846266b5e5f3ede.js} +16 -16
  35. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +41 -0
  36. package/apps/pwa/out/_next/static/chunks/{1178.1aa9cad0e7695427.js → 3482.a9ae9d2ad6a5bd97.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/3507.97e1977bc4d5fb0a.js +2 -0
  38. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +24 -0
  40. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{1661.0dd330f3d89f73f3.js → 3837.a210d7d0db8d8abd.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/{2fdf2931.b431eee4fb468bc3.js → 3d0154af.5331fec737ffe8c3.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4043.6b91203436c9c86b.js +309 -0
  47. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +77 -0
  48. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +148 -0
  54. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +74 -0
  55. package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +122 -0
  56. package/apps/pwa/out/_next/static/chunks/{1115.434ae2ecb0ad986d.js → 5112.4b9f300124fab7b3.js} +3 -3
  57. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +27 -0
  59. package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5885.0a3e52c8faccec98.js +287 -0
  69. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +226 -0
  72. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +90 -0
  73. package/apps/pwa/out/_next/static/chunks/{2073.689dcb2680113d76.js → 6377.bc7df239edbff244.js} +1 -1
  74. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/{1800.f7ff51dc4978a958.js → 6632.0eac1c554f8f2ef3.js} +1 -1
  77. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +104 -0
  81. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +94 -0
  82. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/{2527-5c636a43c7cc5dde.js → 7279-c199ea83f34338fa.js} +1 -1
  85. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{385e4574.e9886ab32759eda3.js → 73d2eb0e.4966ad55293c801a.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{5471.1e611302ed3a7c53.js → 7411.9b4b8b747dc7b802.js} +2 -2
  90. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +24 -0
  91. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{2fe2c302.41b517f88d6fe502.js → 7a98bc80.fa935989e829f9c2.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8138.6c10b2a356d52fca.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{5574.f35accf4f132b29d.js → 8262.ddc03e06b733f184.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +8 -0
  102. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +79 -0
  104. package/apps/pwa/out/_next/static/chunks/{8050-9b364bdef8f71927.js → 8546-6f03f8ea34dd61d9.js} +1 -1
  105. package/apps/pwa/out/_next/static/chunks/{5947-135e26537d80a6b9.js → 8673-bab689a55f7e13b9.js} +3 -3
  106. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{5937.c2df9e3447e1f667.js → 9249.976f1e69a9d80754.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{1971-7efb628c471dc5a0.js → 9353-12bfff0c130104cf.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/{7191.fdc955f7d96064a4.js → 9415.69e4a21c60c7d2db.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/{1219.7e17964e0e7cd8e5.js → 9427.96aa912ddb5801e0.js} +16 -16
  118. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{5964-7e21164a8f2cf0ce.js → 9656-374232558fd528d0.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{6552.a3840aa7da35ad68.js → 9832.f4a98c878ecf2c0a.js} +1 -1
  123. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/9a852a62-6192a6ea9346ced3.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/{a0a01613.6d1cca322238d7fe.js → b450776b.3db34d8d965f82d3.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/{c0c1a699.0ba79f97005965d4.js → e8543907.5b040a5f22a0b0e5.js} +7 -7
  178. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b9d8151e48998417.css → 62c858ad53854f47.css} +1 -1
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +22 -22
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +22 -22
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +22 -22
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +21 -21
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +21 -21
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +22 -22
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +21 -21
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +22 -22
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +22 -22
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +21 -21
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +22 -22
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -24
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +22 -22
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +22 -22
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +21 -21
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +22 -22
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +23 -24
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -24
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +21 -21
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +21 -21
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +22 -22
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +22 -22
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +21 -21
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +21 -21
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +21 -21
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +22 -22
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +22 -22
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +21 -21
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +22 -22
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +22 -22
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +22 -22
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +22 -22
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +22 -22
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +21 -21
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +22 -22
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +22 -22
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +22 -22
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +22 -22
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +22 -22
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +22 -22
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +22 -22
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +22 -22
  278. package/docs/goal-context/04-mock-scenarios.md +13 -0
  279. package/graphs/catalog/catalog.yaml +1 -1
  280. package/graphs/heal/heal-loop.yaml +1 -0
  281. package/graphs/overlays/stop-heal-ladder.yaml +113 -0
  282. package/graphs/units/verbs/recipes.yaml +11 -11
  283. package/graphs/work/research-report.yaml +10 -2
  284. package/package.json +1 -1
  285. package/scripts/heal/run-role.ts +99 -5
  286. package/scripts/land-global-checks.ts +6 -1
  287. package/scripts/lib/decompose-ab.ts +1 -0
  288. package/scripts/lib/fixtures/tui-regress/help-insufficient-commands.txt +15 -0
  289. package/scripts/lib/fixtures/tui-regress/help-live.txt +42 -0
  290. package/scripts/lib/fixtures/tui-regress/help-missing-keys.txt +21 -0
  291. package/scripts/lib/fixtures/tui-regress/help-original.txt +51 -0
  292. package/scripts/lib/fixtures/tui-regress/help-shifted-input.txt +26 -0
  293. package/scripts/lib/tui-regress-checks.ts +33 -13
  294. package/scripts/release-loop/gate-baseline-receipt.ts +47 -9
  295. package/scripts/release-loop/gate-image-pin.ts +81 -0
  296. package/scripts/release-loop/gate-node-sim.ts +207 -0
  297. package/scripts/release-loop/gate-node.ts +285 -46
  298. package/scripts/release-loop/gate-pod-image-sticky-plan.ts +99 -0
  299. package/scripts/release-loop/gate-radius-live.ts +97 -13
  300. package/scripts/release-loop/gate-shard-dispatch.ts +43 -0
  301. package/scripts/release-loop/gate-train-receipts.ts +122 -0
  302. package/scripts/release-loop/resume-release.ts +83 -8
  303. package/scripts/ux-sim.ts +18 -1
  304. package/scripts/warm-pool-provider-config.ts +263 -0
  305. package/skills/omni-crawl/SKILL.md +5 -2
  306. package/skills/omni-crawl/scripts/main.ts +84 -23
  307. package/src/acp/core-turn-bridge.ts +13 -0
  308. package/src/agent/registry.ts +2 -0
  309. package/src/agent/task-notification.ts +25 -5
  310. package/src/agent/types.ts +6 -0
  311. package/src/agent-mission/mission-cli.ts +24 -0
  312. package/src/agent-mission/mission-out.ts +595 -0
  313. package/src/agent-mission/tool-install.ts +88 -2
  314. package/src/agent-substrate/context-strategy.ts +4 -4
  315. package/src/agent-substrate/self-review-cli.ts +178 -13
  316. package/src/auto-research/research-turn.ts +123 -50
  317. package/src/autopilot/pr-manager.ts +38 -7
  318. package/src/autopilot/pty-control-loop.ts +2 -0
  319. package/src/capture/tui-self-report.ts +22 -6
  320. package/src/chat/index.ts +1 -1
  321. package/src/cli/fixtures/review-loop-breaker/opwaiver-32646-1694ccc7a170.json +1 -0
  322. package/src/cli/fixtures/review-loop-breaker/opwaiver-32853-bd8f73595c83.json +1 -0
  323. package/src/cli/fixtures/review-loop-breaker/opwaiver-33097-1cc85900413c.json +1 -0
  324. package/src/cli/fixtures/review-loop-breaker/opwaiver-33106-972f31e4a3ca.json +1 -0
  325. package/src/cli/fixtures/review-loop-breaker/opwaiver-33113-3ab51f05968f.json +1 -0
  326. package/src/cli/fixtures/review-loop-breaker/pr-33097-1cc85900413c.json +1 -0
  327. package/src/cli/pr-land-heavy-remote.ts +32 -0
  328. package/src/cli/pr-land-overlap-evidence.ts +100 -1
  329. package/src/cli/pr-land-pod-shadow-job.ts +60 -0
  330. package/src/cli/release-checklist-read-cli.ts +20 -10
  331. package/src/cli/research-cli.ts +4 -5
  332. package/src/cli/tasks-cli.ts +7 -0
  333. package/src/compact/auto.ts +8 -1
  334. package/src/control-plane/ledger.ts +52 -2
  335. package/src/control-plane/server.ts +16 -2
  336. package/src/core-turn/run-core-turn.ts +311 -90
  337. package/src/core-turn/run-goal-loop.ts +18 -0
  338. package/src/core-turn/types.ts +2 -0
  339. package/src/dashboard/classic-sidetab-mission-job.ts +58 -0
  340. package/src/dashboard/classic-sidetab-mission.ts +185 -0
  341. package/src/dashboard/index.ts +149 -15
  342. package/src/dashboard/input/agent-wake.ts +23 -1
  343. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +9 -0
  344. package/src/dashboard/mission-cli-consumer.ts +153 -0
  345. package/src/dashboard/seat-boot-preamble.ts +171 -1
  346. package/src/dashboard/side-basic-runtime.ts +54 -1
  347. package/src/dashboard/sidetab-runtime.ts +90 -1
  348. package/src/dashboard/skill-catalog-preamble.ts +101 -0
  349. package/src/dashboard/skill-detection-runtime.ts +55 -15
  350. package/src/dashboard/slash-runtime/dashboard-handlers.ts +15 -0
  351. package/src/dashboard/turn-preamble.ts +53 -15
  352. package/src/dashboard/turn-prompt-runtime.ts +4 -2
  353. package/src/graph-runner/graph-cli.ts +23 -7
  354. package/src/graph-runner/graph-tick.ts +10 -2
  355. package/src/graph-runner/runner.ts +1 -1
  356. package/src/grok/agent-search.ts +14 -4
  357. package/src/grok/credential.ts +28 -11
  358. package/src/harness/harness-pod-dispatch.ts +81 -15
  359. package/src/harness/harness-stop.ts +155 -11
  360. package/src/index.ts +34 -5
  361. package/src/instance/spawn-elanous.ts +6 -4
  362. package/src/llm.ts +166 -8
  363. package/src/loops/orchestrator/coordinator-shadow.ts +226 -0
  364. package/src/loops/orchestrator/tick.ts +13 -0
  365. package/src/maturity/feature-maturity.ts +1 -1
  366. package/src/native-tool-catalog.ts +2 -2
  367. package/src/nexus/api/harness-traversal.ts +11 -0
  368. package/src/pr-tool/census.ts +3 -2
  369. package/src/pty-shell/tui-run-state.ts +188 -2
  370. package/src/release-loop/checklist-target-path-hint.ts +13 -0
  371. package/src/release-loop/checklist.ts +9 -1
  372. package/src/repl/index.ts +43 -2
  373. package/src/research/axis-fanout.ts +121 -16
  374. package/src/research/bloom-exemplars.ts +3 -1
  375. package/src/research/gap-followup.ts +13 -1
  376. package/src/research/plugin-discovery.ts +36 -14
  377. package/src/research-bridge/invoke.ts +22 -5
  378. package/src/research-bridge/types.ts +2 -0
  379. package/src/self-dev/decompose.ts +119 -5
  380. package/src/self-dev/launch-preflight-text.ts +5 -6
  381. package/src/self-dev/orchestrate.ts +12 -2
  382. package/src/self-dev/review-provider-fallback.ts +9 -2
  383. package/src/self-dev/run-supervisor.ts +42 -4
  384. package/src/self-dev/run-types.ts +4 -0
  385. package/src/self-implement/doctor-visit.ts +88 -0
  386. package/src/self-implement/goal-author.ts +326 -3
  387. package/src/self-implement/graph-overlay-yaml.ts +7 -0
  388. package/src/self-implement/headless-elanous-driver.ts +31 -2
  389. package/src/self-implement/heal-intake.ts +112 -4
  390. package/src/self-implement/heal-triage.ts +20 -0
  391. package/src/self-implement/host-regate.ts +27 -4
  392. package/src/self-implement/merge-train.ts +5 -0
  393. package/src/self-implement/orchestrator.ts +126 -11
  394. package/src/self-implement/regate-detail.ts +38 -1
  395. package/src/self-implement/rework-child-provider.ts +25 -0
  396. package/src/self-implement/run-chart.ts +119 -0
  397. package/src/self-implement/run-ledger.ts +112 -11
  398. package/src/self-implement/run-stop.ts +188 -4
  399. package/src/self-implement/stop-autoheal.ts +13 -0
  400. package/src/session/chat.ts +38 -4
  401. package/src/session-runtime/index.ts +98 -4
  402. package/src/session-runtime/tier-flip.ts +3 -3
  403. package/src/sidetab-core/model.ts +19 -5
  404. package/src/sidetab-core/visible-agent-mission.ts +186 -0
  405. package/src/skills/name-match.ts +20 -0
  406. package/src/skills/tools/agent.ts +30 -2
  407. package/src/skills/tools/omni-search.ts +67 -5
  408. package/src/task-agent/pod-distributor-entry.ts +3 -0
  409. package/src/task-agent/task-hand.ts +27 -0
  410. package/src/task-orchestrator/surfaces/pod-distributor.ts +48 -0
  411. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +38 -1
  412. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +33 -6
  413. package/src/task-orchestrator/surfaces/pod-source-bundle.ts +45 -9
  414. package/src/task-orchestrator/surfaces/pod-source-receive.ts +163 -13
  415. package/src/task-orchestrator/surfaces/pod-source-spec.ts +3 -3
  416. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +209 -39
  417. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +80 -3
  418. package/src/task-orchestrator/surfaces/self-implement-pod.ts +165 -45
  419. package/src/tokens.ts +35 -2
  420. package/src/tool-runtime/agent-runtime.ts +1 -0
  421. package/src/tool-runtime/elanous-skills-list-runtime.ts +5 -1
  422. package/src/tool-runtime/skill-exec-runtime.ts +33 -13
  423. package/src/tool-runtime/types.ts +1 -0
  424. package/src/tui/entry.ts +14 -4
  425. package/src/tui/sidetab/attach.ts +47 -0
  426. package/src/tui-client/local-chat-turn.ts +26 -13
  427. package/src/tui.ts +22 -0
  428. package/src/ux-sim/fake-kubectl.ts +37 -3
  429. package/src/ux-sim/fault-pool-cap.ts +11 -6
  430. package/src/ux-sim/mock-scenario-catalog.json +41 -0
  431. package/src/ux-sim/mock-scenario-catalog.ts +156 -0
  432. package/src/ux-sim/scenario.ts +116 -23
  433. package/src/version/packed-revision.json +1 -1
  434. package/src/voice/voice-tts-singleton.ts +18 -3
  435. package/src/web-search/grok.ts +5 -9
  436. package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +0 -36
  437. package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +0 -287
  439. package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +0 -90
  443. package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +0 -77
  445. package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/2743.5d3f76948be32b34.js +0 -41
  453. package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +0 -32
  454. package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +0 -79
  456. package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/3230-49298c3b73ef2268.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +0 -74
  461. package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/4133.2056bb4d78f621af.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +0 -148
  472. package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +0 -226
  473. package/apps/pwa/out/_next/static/chunks/4667.97e31aa38c95c475.js +0 -309
  474. package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +0 -94
  481. package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +0 -8
  483. package/apps/pwa/out/_next/static/chunks/53aeb4ee-51c92f8d683f5220.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +0 -24
  487. package/apps/pwa/out/_next/static/chunks/5744.b9415e18ad623100.js +0 -23
  488. package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +0 -286
  490. package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +0 -27
  494. package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +0 -24
  496. package/apps/pwa/out/_next/static/chunks/6874.d5cf7eb8edb2cabe.js +0 -2
  497. package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +0 -122
  499. package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/83184dcd-0ee6247ff41eb3f2.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +0 -104
  510. package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +0 -34
  527. package/apps/pwa/out/_next/static/chunks/9834.63ab2bbc3153172e.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/addc2b32.8c4ff8f0aefe987d.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/botlab/page-14949db884bfa672.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-40f9e19149024298.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a142dfb0331a05f5.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/b2271e54.c1de3347976e90b0.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +0 -1
  588. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +0 -1
  589. /package/apps/pwa/out/_next/static/{GiOLWmt4MqDZePubBjA4Q → X1ucLw10Cds_h614NoEnh}/_ssgManifest.js +0 -0
@@ -27,33 +27,46 @@ const HINT = /한 번 더 누르면 나갑니다/;
27
27
  const ok = (reason: string): Verdict => ({ ok: true, reason });
28
28
  const no = (reason: string): Verdict => ({ ok: false, reason });
29
29
 
30
- /** The input row: the last screen line that starts with the prompt marker. */
30
+ /** The TUI draws panels with box/block borders (box drawing and block elements, U+2500–U+259F) — a judge must read
31
+ * the same «content lines» whether a screen renders a plain list or a bordered panel (0.2.41 incident:
32
+ * R6 warned on the healthy «│Keys …│» screen). Border characters become spaces, so a line keeps its
33
+ * own indentation, and a line left with nothing but whitespace was the frame itself and is dropped. */
34
+ export function contentLines(screen: string): string[] {
35
+ return screen
36
+ .split('\n')
37
+ .map((line) => line.replace(/[\u2500-\u259F]/g, ' '))
38
+ .filter((line) => line.trim().length > 0);
39
+ }
40
+
41
+ /** The input row: the last content line that starts with the prompt marker. */
31
42
  export function inputRow(screen: string): string | undefined {
32
- return screen.split('\n').filter((line) => line.trimStart().startsWith('❯')).at(-1);
43
+ return contentLines(screen).filter((line) => line.trimStart().startsWith('❯')).at(-1);
33
44
  }
34
45
 
35
- /** Palette entries visible after typing a slash prefix (lines other than the input row that show `/name`). */
46
+ /** Palette entries visible after typing a slash prefix (content lines other than the input row that show `/name`). */
36
47
  export function paletteHas(screen: string, name: string): boolean {
48
+ const lines = contentLines(screen);
37
49
  const row = inputRow(screen);
38
- return screen.split('\n').some((line) => line !== row && line.includes(`/${name}`));
50
+ return lines.some((line) => line !== row && line.includes(`/${name}`));
39
51
  }
40
52
 
41
53
  export function judgeFirstScreen(screen: string): Verdict {
42
- if (/Step 1/.test(screen)) return no('«Step 1» 마법사가 떴다');
54
+ const lines = contentLines(screen);
55
+ if (lines.some((line) => /Step 1/.test(line))) return no('«Step 1» 마법사가 떴다');
43
56
  if (!inputRow(screen)) return no('입력칸 «❯» 가 없다');
44
57
  return ok('입력칸이 보이고 «Step 1» 이 없다');
45
58
  }
46
59
 
47
60
  export function judgeHintAppearsThenClears(armed: string, later: string): Verdict {
48
- if (!HINT.test(armed)) return no('빈 입력 Ctrl+C 뒤 안내가 안 보인다');
49
- if (HINT.test(later)) return no('2.6초 뒤에도 안내가 남아 있다');
61
+ if (!contentLines(armed).some((line) => HINT.test(line))) return no('빈 입력 Ctrl+C 뒤 안내가 안 보인다');
62
+ if (contentLines(later).some((line) => HINT.test(line))) return no('2.6초 뒤에도 안내가 남아 있다');
50
63
  return ok('안내가 떴다가 2초 뒤 사라졌다');
51
64
  }
52
65
 
53
66
  export function judgeCtrlCClearsText(typed: string, after: string, text: string): Verdict {
54
67
  if (!(inputRow(typed) ?? '').includes(text)) return no('친 글이 입력칸에 안 보인다(준비 실패)');
55
68
  if ((inputRow(after) ?? '').includes(text)) return no('Ctrl+C 뒤에도 글이 남아 있다');
56
- if (HINT.test(after)) return no('글을 지우는 Ctrl+C 에 나가기 안내가 떴다');
69
+ if (contentLines(after).some((line) => HINT.test(line))) return no('글을 지우는 Ctrl+C 에 나가기 안내가 떴다');
57
70
  return ok('글이 지워지고 안내는 없다');
58
71
  }
59
72
 
@@ -67,11 +80,18 @@ export function judgePalette(screens: Record<string, string>, expectations: Reco
67
80
  }
68
81
 
69
82
  /** U1b — the help is drawn (key section ⊕ a run of command rows) and the prompt survives below it.
70
- * Not «the whole grid fits»: an owner sees 60+ commands, which exceed a 50-row screen and scroll (PgUp). */
83
+ * Not «the whole grid fits»: an owner sees 60+ commands, which exceed a 50-row screen and scroll (PgUp).
84
+ * Border-agnostic (0.2.41 R6 오탐): judged on content lines, so the bordered «│Keys …│» panel reads
85
+ * like the plain list. */
71
86
  export function judgeHelpShown(screen: string): Verdict {
72
- const lines = screen.split('\n');
73
- const commandRows = lines.filter((line) => /^\s+\/[a-z][a-z-]*/.test(line)).length;
74
- if (!lines.some((line) => /^\s*Keys\s*$/.test(line))) return no('/help 의 Keys 절이 안 보인다');
87
+ const lines = contentLines(screen);
88
+ const commandsAt = lines.findIndex((line) => /^\s*Commands\s*$/.test(line));
89
+ const keysAt = lines.findIndex((line) => /^\s*Keys\s*$/.test(line));
90
+ if (commandsAt < 0) return no('/help 의 Commands 절이 안 보인다');
91
+ if (keysAt <= commandsAt) return no('/help 의 Keys 절이 안 보인다');
92
+ // Count command-bearing rows only within the panel section; commands may be in either column.
93
+ const commandRows = lines.slice(commandsAt + 1, keysAt)
94
+ .filter((line) => /(?:^|\s)\/[a-z][a-z-]*(?=\s|$)/.test(line)).length;
75
95
  if (commandRows < 10) return no(`명령 줄이 ${commandRows}개뿐이다`);
76
96
  if (!inputRow(screen)) return no('도움말을 연 뒤 입력칸이 화면 밖으로 밀렸다');
77
97
  return ok(`도움말이 그려졌다(명령 줄 ${commandRows} · Keys 절 · 입력칸 유지)`);
@@ -79,7 +99,7 @@ export function judgeHelpShown(screen: string): Verdict {
79
99
 
80
100
  /** U1c2 — lines typed while a reply streams show up as «my» lines, in order, each above its own answer. */
81
101
  export function judgeQueuedEcho(screen: string): Verdict {
82
- const lines = screen.split('\n');
102
+ const lines = contentLines(screen);
83
103
  const at = (re: RegExp, after = -1) => lines.findIndex((line, i) => i > after && re.test(line));
84
104
  const u2 = at(/Q2MARK 라고만/);
85
105
  if (u2 < 0) return no('줄 서 있던 «Q2MARK 라고만» 이 내 말로 안 보인다');
@@ -24,7 +24,7 @@ export function gateAssignableTestsAtCommit(repo: string, commit: string): strin
24
24
  }
25
25
 
26
26
  export interface GateBaselineReceipt {
27
- schema: 1;
27
+ schema: 2;
28
28
  valid: boolean;
29
29
  reason: string;
30
30
  version: string;
@@ -33,11 +33,37 @@ export interface GateBaselineReceipt {
33
33
  recipeSha: string | null;
34
34
  envFingerprint: string;
35
35
  imageDigest: string | null;
36
+ executionIdentity: GatePodRuntimeIdentity | null;
36
37
  files: number;
37
38
  shards: number;
38
39
  attributionRecheck?: { summary: number; observed: number; identified: number; baselineResult: string; targetFiles: string[] };
39
40
  }
40
41
 
42
+ export interface GatePodRuntimeIdentity {
43
+ bunVersion: string;
44
+ platform: string;
45
+ architecture: string;
46
+ envFingerprint: string;
47
+ }
48
+
49
+ const validRuntimeIdentity = (value: unknown): value is GatePodRuntimeIdentity => {
50
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
51
+ const row = value as Partial<GatePodRuntimeIdentity>;
52
+ return Object.keys(value).sort().join(',') === 'architecture,bunVersion,envFingerprint,platform'
53
+ && typeof row.bunVersion === 'string' && /^\d+\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(row.bunVersion)
54
+ && typeof row.platform === 'string' && /^[a-z0-9_-]{1,32}$/.test(row.platform)
55
+ && typeof row.architecture === 'string' && /^[a-z0-9_-]{1,32}$/.test(row.architecture)
56
+ && typeof row.envFingerprint === 'string' && SHA256.test(row.envFingerprint);
57
+ };
58
+
59
+ /** Parse runtime facts written by the gate Pod before its tests start. */
60
+ export function parseGatePodRuntimeIdentity(text: string): GatePodRuntimeIdentity | null {
61
+ try {
62
+ const value: unknown = JSON.parse(text);
63
+ return validRuntimeIdentity(value) ? value : null;
64
+ } catch { return null; }
65
+ }
66
+
41
67
  /** A direct hard rehearsal has no graph run state. Pin the graph and recipe bytes at its Git SHA. */
42
68
  export function gateSourcePins(repo: string, commit: string): { graphSha: string; recipeSha: string } | null {
43
69
  if (!/^[0-9a-f]{40}$/i.test(commit)) return null;
@@ -87,8 +113,9 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
87
113
  graphPins: { graphSha: string; recipeSha: string } | null; envFingerprint: string;
88
114
  attributionRecheck?: { summary: number; observed: number; identified: number; baselineResult: string; targetFiles: string[] } }): GateBaselineReceipt {
89
115
  const { root, version, commit, graphPins, envFingerprint } = input;
90
- const base = { schema: 1 as const, version, commit, graphSha: graphPins?.graphSha ?? null,
91
- recipeSha: graphPins?.recipeSha ?? null, envFingerprint, imageDigest: null as string | null, files: 0, shards: 0 };
116
+ const base = { schema: 2 as const, version, commit, graphSha: graphPins?.graphSha ?? null,
117
+ recipeSha: graphPins?.recipeSha ?? null, envFingerprint, imageDigest: null as string | null,
118
+ executionIdentity: null as GatePodRuntimeIdentity | null, files: 0, shards: 0 };
92
119
  const invalid = (reason: string): GateBaselineReceipt => ({ ...base, valid: false, reason });
93
120
  if (input.attributionRecheck) {
94
121
  const evidence = input.attributionRecheck;
@@ -102,12 +129,14 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
102
129
  const dir = join(root, 'release', version, 'gate-logs', 'cut');
103
130
  if (!existsSync(dir)) return invalid('cut Pod logs absent');
104
131
  const names = readdirSync(dir).filter((name) => /^pod-\d+(?:-[\w-]+)?\.json$/.test(name));
105
- const roots = new Map<number, { files: string[]; shardCount: number; sweepId: string; attemptId: string }>();
106
- const descendants: Array<{ name: string; commit?: string; imageDigest?: string; sweepId?: string; parentAttempt?: string; attemptId?: string }> = [];
132
+ const roots = new Map<number, { files: string[]; shardCount: number; sweepId: string; attemptId: string; runtimeIdentity?: GatePodRuntimeIdentity }>();
133
+ const descendants: Array<{ name: string; commit?: string; imageDigest?: string; sweepId?: string; parentAttempt?: string; attemptId?: string; runtimeIdentity?: GatePodRuntimeIdentity }> = [];
107
134
  const images = new Set<string>();
135
+ const identities = new Map<string, GatePodRuntimeIdentity>();
108
136
  for (const name of names) {
109
137
  const row = JSON.parse(readFileSync(join(dir, name), 'utf8')) as
110
- { commit?: string; files?: unknown; shardCount?: number; sweepId?: string; imageDigest?: string; parentAttempt?: string; attemptId?: string };
138
+ { commit?: string; files?: unknown; shardCount?: number; sweepId?: string; imageDigest?: string; parentAttempt?: string; attemptId?: string; runtimeIdentity?: unknown };
139
+ const runtimeIdentity = validRuntimeIdentity(row.runtimeIdentity) ? row.runtimeIdentity : undefined;
111
140
  const match = /^pod-(\d+)\.json$/.exec(name);
112
141
  if (match) {
113
142
  if (row.commit !== commit) return invalid(`root cut Pod ${name} belongs to another commit`);
@@ -115,12 +144,16 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
115
144
  return invalid(`root cut Pod ${name} has no file list`);
116
145
  if (!row.attemptId) return invalid(`root cut Pod ${name} has no attempt`);
117
146
  if (!row.sweepId) return invalid(`root cut Pod ${name} has no sweep identity`);
118
- roots.set(Number(match[1]), { files: row.files as string[], shardCount: row.shardCount ?? 0, sweepId: row.sweepId, attemptId: row.attemptId });
147
+ roots.set(Number(match[1]), { files: row.files as string[], shardCount: row.shardCount ?? 0,
148
+ sweepId: row.sweepId, attemptId: row.attemptId, runtimeIdentity });
119
149
  } else descendants.push({ name, commit: row.commit, imageDigest: row.imageDigest, sweepId: row.sweepId,
120
- parentAttempt: row.parentAttempt, attemptId: row.attemptId });
150
+ parentAttempt: row.parentAttempt, attemptId: row.attemptId, runtimeIdentity });
121
151
  if (match) {
122
152
  if (!row.imageDigest || !IMAGE_DIGEST.test(row.imageDigest)) return invalid(`actual Pod image digest absent: ${name}`);
153
+ if (!runtimeIdentity) return invalid(`actual Pod runtime identity absent: ${name}`);
154
+ if (runtimeIdentity.envFingerprint !== envFingerprint) return invalid(`actual Pod environment differs: ${name}`);
123
155
  images.add(row.imageDigest.toLowerCase());
156
+ identities.set(JSON.stringify(runtimeIdentity), runtimeIdentity);
124
157
  }
125
158
  }
126
159
  if (!roots.size) return invalid('root cut shards absent');
@@ -144,7 +177,10 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
144
177
  if (row.sweepId !== sweepId) return invalid(`cut Pod ${row.name} belongs to another sweep`);
145
178
  if (!row.imageDigest || !IMAGE_DIGEST.test(row.imageDigest)) return invalid(`actual Pod image digest absent: ${row.name}`);
146
179
  if (!row.attemptId) return invalid(`cut Pod ${row.name} has no attempt`);
180
+ if (!row.runtimeIdentity) return invalid(`actual Pod runtime identity absent: ${row.name}`);
181
+ if (row.runtimeIdentity.envFingerprint !== envFingerprint) return invalid(`actual Pod environment differs: ${row.name}`);
147
182
  images.add(row.imageDigest.toLowerCase());
183
+ identities.set(JSON.stringify(row.runtimeIdentity), row.runtimeIdentity);
148
184
  attempts.add(row.attemptId);
149
185
  }
150
186
  pending = next;
@@ -157,6 +193,8 @@ export function gateBaselineReceipt(input: { root: string; version: string; comm
157
193
  if (row.commit === commit && !row.sweepId) return invalid(`cut Pod ${row.name} has no sweep identity`);
158
194
  }
159
195
  if (images.size !== 1) return invalid('cut Pods used different image digests');
160
- return { ...base, valid: true, reason: 'complete clean full sweep', imageDigest: [...images][0]!, files: files.length, shards: count };
196
+ if (identities.size !== 1) return invalid('cut Pods used different runtime identities');
197
+ return { ...base, valid: true, reason: 'complete clean full sweep', imageDigest: [...images][0]!,
198
+ executionIdentity: identities.values().next().value!, files: files.length, shards: count };
161
199
  } catch (error) { return invalid(`cut Pod evidence unreadable: ${String(error)}`); }
162
200
  }
@@ -0,0 +1,81 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+
4
+ /** A gate run may execute only against one immutable image identity and its exact source tag. */
5
+ export interface GateImagePin { runId: string; digest: string; image: string; commit: string }
6
+
7
+ export type GateImagePinResolution =
8
+ | { ok: true; digest: string; eligiblePools: string[] }
9
+ | { ok: false; reason: 'saved-image-digest-invalid' | 'initial-image-digest-invalid' | 'initial-image-digest-missing' | 'pinned-image-unavailable' };
10
+
11
+ export interface ResolveGateImagePinOptions {
12
+ /** Persisted at the run boundary; takes precedence over any newly probed default. */
13
+ savedDigest?: string | null;
14
+ /** Used only to create the pin for a new run. */
15
+ initialDigest?: string | null;
16
+ /** Exact immutable digest selected by the gate image probe in each pool. */
17
+ poolImages: ReadonlyMap<string, readonly string[]>;
18
+ }
19
+
20
+ function normalizeGateImageDigest(value: unknown): string | null {
21
+ if (typeof value !== 'string' || !/^sha256:[a-f0-9]{64}$/i.test(value.trim())) return null;
22
+ return value.trim().toLowerCase();
23
+ }
24
+
25
+ /**
26
+ * Resolve the durable run pin and fail closed unless at least one pool can prove it has that exact image.
27
+ * Callers must filter placement to `eligiblePools`; a mutable tag is never a substitute.
28
+ */
29
+ export function resolveGateImagePin(options: ResolveGateImagePinOptions): GateImagePinResolution {
30
+ const hasSaved = options.savedDigest !== undefined && options.savedDigest !== null;
31
+ const rawDigest = hasSaved ? options.savedDigest : options.initialDigest;
32
+ if (!hasSaved && (rawDigest === undefined || rawDigest === null || rawDigest.trim() === '')) {
33
+ return { ok: false, reason: 'initial-image-digest-missing' };
34
+ }
35
+ const digest = normalizeGateImageDigest(rawDigest);
36
+ if (!digest) return { ok: false, reason: hasSaved ? 'saved-image-digest-invalid' : 'initial-image-digest-invalid' };
37
+ const eligiblePools = [...options.poolImages]
38
+ .filter(([, images]) => images.some((image) => normalizeGateImageDigest(image) === digest))
39
+ .map(([pool]) => pool);
40
+ if (!eligiblePools.length) return { ok: false, reason: 'pinned-image-unavailable' };
41
+ return { ok: true, digest, eligiblePools };
42
+ }
43
+
44
+ /** The pin is immutable for one graph gate run; absence on resume is a hard refusal. */
45
+ export function readGateImagePin(path: string, expectedRunId: string, expectedImage: string, expectedCommit: string): GateImagePin | null {
46
+ if (!existsSync(path)) return null;
47
+ const parsed = JSON.parse(readFileSync(path, 'utf8')) as { version?: unknown; runId?: unknown; digest?: unknown; image?: unknown; commit?: unknown };
48
+ const normalizedCommit = expectedCommit.toLowerCase();
49
+ if (parsed.version !== 2 || parsed.runId !== expectedRunId || parsed.image !== expectedImage || parsed.commit !== normalizedCommit
50
+ || !normalizeGateImageDigest(parsed.digest))
51
+ throw new Error(`invalid gate image pin: ${path}`);
52
+ return { runId: expectedRunId, digest: normalizeGateImageDigest(parsed.digest)!, image: expectedImage, commit: normalizedCommit };
53
+ }
54
+
55
+ export function writeGateImagePin(path: string, runId: string, digest: string, image: string, commit: string): void {
56
+ const normalized = normalizeGateImageDigest(digest);
57
+ if (!runId || !normalized || !image.trim() || !/^[0-9a-f]{40}$/i.test(commit)) throw new Error('invalid gate image pin identity');
58
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
59
+ const value = JSON.stringify({ version: 2, runId, digest: normalized, image, commit: commit.toLowerCase() });
60
+ if (existsSync(path)) {
61
+ const prior = JSON.parse(readFileSync(path, 'utf8')) as { runId?: unknown; digest?: unknown; image?: unknown; commit?: unknown };
62
+ if (prior.runId !== runId || normalizeGateImageDigest(prior.digest) !== normalized || prior.image !== image
63
+ || prior.commit !== commit.toLowerCase())
64
+ throw new Error(`gate image pin is immutable: ${path}`);
65
+ return;
66
+ }
67
+ try { writeFileSync(path, `${value}\n`, { mode: 0o600, flag: 'wx' }); }
68
+ catch (error) {
69
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
70
+ const prior = JSON.parse(readFileSync(path, 'utf8')) as { runId?: unknown; digest?: unknown; image?: unknown; commit?: unknown };
71
+ if (prior.runId === runId && normalizeGateImageDigest(prior.digest) === normalized && prior.image === image
72
+ && prior.commit === commit.toLowerCase()) return;
73
+ throw new Error(`gate image pin is immutable: ${path}`);
74
+ }
75
+ }
76
+
77
+ export function gateImagePinPath(root: string, version: string, runId: string): string {
78
+ if (!/^\d+\.\d+\.\d+(?:-rc\.\d+)?$/.test(version) || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(runId))
79
+ throw new Error('invalid gate image pin path identity');
80
+ return `${root.replace(/\/$/, '')}/release/${version}/gate-image-pin-${runId}.json`;
81
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * GATE-MOCK-EVENT-SCENARIOS — deterministic event catalogue and gate-node driver.
3
+ *
4
+ * Outcomes are injected at GateRunner.sweep (the judgement boundary); judgeGate remains the production
5
+ * classifier. Dispatch/partial rows additionally call the production planners that select reuse,
6
+ * remeasurement, or a fail-closed full/HOLD path. Retry rows use the production shard-artifact reader
7
+ * with distinct first-attempt and retry artifacts. Inputs describe test data, not real Pod lifecycle events.
8
+ */
9
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
10
+ import { tmpdir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import { createGateRunner, judgeGate, readShardArtifacts, type GateRunner, type GateTools } from './gate-node.js';
13
+ import { planStalledShardRecheck } from './gate-partial.js';
14
+ import { planGateShardDispatch, type GateShardReceipt } from './gate-shard-dispatch.js';
15
+ import { createFakeKubectl } from '../../src/ux-sim/fake-kubectl.js';
16
+ import { createFakeGh } from '../../src/ux-sim/fake-gh.js';
17
+ import { planPartialRegate } from './gate-partial.js';
18
+
19
+ export type GateScenarioAction = 'reuse' | 'remeasure' | 'full sweep' | 'HOLD';
20
+ export type GateScenario = {
21
+ id: string;
22
+ injectedInput: string;
23
+ gateInjection: 'pass' | 'regression' | 'hold' | 'malformed';
24
+ retryResult?: 'pass' | 'fail';
25
+ expectedOutcome: 'ok' | 'regression' | 'error';
26
+ expectedError?: string;
27
+ action: GateScenarioAction;
28
+ planner?: 'dispatch' | 'partial';
29
+ expectedDispatchKinds?: Array<'reuse' | 'run' | 'unmeasured'>;
30
+ expectedPartialFiles?: string[];
31
+ dispatchInput?: { head40?: string; receipts: 'complete' | 'absent' | 'identity-mismatch'; minihAvailable: boolean;
32
+ msb1Available?: boolean; receiptHosts?: Record<string, string>; rerouteShard?: string };
33
+ partialInput?: { kind: 'stalled'; stalledFiles: string[] } | { kind: 'changed-head'; priorCommit: string; forCommit: string; changedFiles: string[] };
34
+ };
35
+
36
+ const H = 'a'.repeat(40);
37
+ const B = 'b'.repeat(40);
38
+ const FILE = 'src/example.test.ts';
39
+ const FAILURE = `${FILE} > simulated failure`;
40
+ const ENV = 'gate-env-v1';
41
+ const EVIDENCE = 'c'.repeat(64);
42
+
43
+ /**
44
+ * Kept as data so the emitted E4 table and focused tests have the same inventory.
45
+ * Action vocabulary is the operator-facing disposition after judgeGate and the relevant planner run.
46
+ */
47
+ export const GATE_NODE_SIM_SCENARIOS: readonly GateScenario[] = [
48
+ { id: 'injected-hold', injectedInput: 'injected sweep HOLD', gateInjection: 'hold', expectedOutcome: 'error', expectedError: 'simulated HOLD: injected sweep HOLD', action: 'HOLD' },
49
+ { id: 'retry-pass', injectedInput: 'first-attempt failure artifact plus a distinct clean retry artifact', gateInjection: 'pass', retryResult: 'pass', expectedOutcome: 'ok', action: 'reuse' },
50
+ { id: 'retry-fail', injectedInput: 'first-attempt failure artifact plus a distinct failing retry artifact', gateInjection: 'pass', retryResult: 'fail', expectedOutcome: 'regression', action: 'HOLD' },
51
+ { id: 'host-down-reroute', injectedInput: 'host down; reroute only the affected shard', gateInjection: 'pass', expectedOutcome: 'ok', action: 'remeasure', planner: 'dispatch', dispatchInput: { receipts: 'complete', minihAvailable: false, receiptHosts: { 'pod-1': 'node-b' }, rerouteShard: 'pod-0' }, expectedDispatchKinds: ['run', 'reuse'] },
52
+ { id: 'all-hosts-down', injectedInput: 'no eligible host; preserve an unmeasured HOLD', gateInjection: 'hold', expectedOutcome: 'error', expectedError: 'simulated HOLD: no eligible host; preserve an unmeasured HOLD', action: 'HOLD', planner: 'dispatch', dispatchInput: { receipts: 'absent', minihAvailable: false, msb1Available: false }, expectedDispatchKinds: ['unmeasured', 'unmeasured'] },
53
+ { id: 'partial-resume', injectedInput: 'resume only the stopped shard', gateInjection: 'pass', expectedOutcome: 'ok', action: 'remeasure', planner: 'partial', partialInput: { kind: 'stalled', stalledFiles: ['src/stopped.test.ts'] }, expectedPartialFiles: ['src/stopped.test.ts'] },
54
+ { id: 'same-head-receipt', injectedInput: 'complete receipt at the same head and base with matching shard inventory', gateInjection: 'pass', expectedOutcome: 'ok', action: 'reuse', planner: 'dispatch', dispatchInput: { receipts: 'complete', minihAvailable: true }, expectedDispatchKinds: ['reuse', 'reuse'] },
55
+ { id: 'changed-head-outside-radius', injectedInput: 'changed head outside permitted radius', gateInjection: 'pass', expectedOutcome: 'ok', action: 'full sweep', planner: 'dispatch', dispatchInput: { head40: 'd'.repeat(40), receipts: 'complete', minihAvailable: true }, expectedDispatchKinds: ['run', 'run'] },
56
+ { id: 'changed-head-inside-radius', injectedInput: 'changed head inside permitted radius', gateInjection: 'pass', expectedOutcome: 'ok', action: 'remeasure', planner: 'partial', partialInput: { kind: 'changed-head', priorCommit: B, forCommit: H, changedFiles: [FILE] }, expectedPartialFiles: [FILE] },
57
+ { id: 'receipt-identity-mismatch', injectedInput: 'receipt identity differs from expected shard', gateInjection: 'pass', expectedOutcome: 'ok', action: 'remeasure', planner: 'dispatch', dispatchInput: { receipts: 'identity-mismatch', minihAvailable: true }, expectedDispatchKinds: ['run', 'reuse'] },
58
+ { id: 'receipt-absent', injectedInput: 'receipt absent', gateInjection: 'pass', expectedOutcome: 'ok', action: 'full sweep', planner: 'dispatch', dispatchInput: { receipts: 'absent', minihAvailable: true }, expectedDispatchKinds: ['run', 'run'] },
59
+ { id: 'sweep-summary-malformed', injectedInput: 'sweep returns an unparseable summary', gateInjection: 'malformed', expectedOutcome: 'error', action: 'HOLD' },
60
+ { id: 'reuse-planner-gate-error', injectedInput: 'same-head planner proposes receipt reuse while the gate summary is malformed', gateInjection: 'malformed', expectedOutcome: 'error', action: 'HOLD', planner: 'dispatch', dispatchInput: { receipts: 'complete', minihAvailable: true }, expectedDispatchKinds: ['reuse', 'reuse'] },
61
+ { id: 'reroute-planner-gate-regression', injectedInput: 'host reroute planner proposes a shard run while the gate reports a regression', gateInjection: 'regression', expectedOutcome: 'regression', action: 'HOLD', planner: 'dispatch', dispatchInput: { receipts: 'complete', minihAvailable: false, receiptHosts: { 'pod-1': 'node-b' }, rerouteShard: 'pod-0' }, expectedDispatchKinds: ['run', 'reuse'] },
62
+ { id: 'partial-planner-gate-error', injectedInput: 'partial planner proposes remeasurement while the gate summary is malformed', gateInjection: 'malformed', expectedOutcome: 'error', action: 'HOLD', planner: 'partial', partialInput: { kind: 'stalled', stalledFiles: ['src/stopped.test.ts'] }, expectedPartialFiles: ['src/stopped.test.ts'] },
63
+ { id: 'partial-planner-gate-regression', injectedInput: 'partial planner proposes remeasurement while the gate reports a regression', gateInjection: 'regression', expectedOutcome: 'regression', action: 'HOLD', planner: 'partial', partialInput: { kind: 'stalled', stalledFiles: ['src/stopped.test.ts'] }, expectedPartialFiles: ['src/stopped.test.ts'] },
64
+ ];
65
+
66
+ function makeReceipt(id: string, files: string[], host: string): GateShardReceipt {
67
+ return { id, files, head40: H, base40: B, host, envKey: ENV, status: 'complete',
68
+ failureIds: [], errorIds: [], evidencePath: '/sim/pod-0.json', evidenceSha256: EVIDENCE,
69
+ measuredAt: '2026-10-29T00:00:00.000Z', attempt: 1 };
70
+ }
71
+ type PlannerEvidence =
72
+ | { kind: 'dispatch'; actions: ReturnType<typeof planGateShardDispatch> }
73
+ | { kind: 'partial'; ok: true; files: string[] }
74
+ | { kind: 'none' };
75
+
76
+ function plannerDecision(scenario: GateScenario, devices: { head40: string; minihAvailable: boolean; msb1Available: boolean }): { action: GateScenarioAction; evidence: PlannerEvidence } {
77
+ if (scenario.planner === 'dispatch') {
78
+ const input = scenario.dispatchInput ?? { receipts: 'complete' as const, minihAvailable: true };
79
+ const shards = [{ id: 'pod-0', files: [FILE] }, { id: 'pod-1', files: ['src/second.test.ts'] }];
80
+ const receipts = input.receipts === 'absent' ? [] : shards.map((shard) => makeReceipt(shard.id,
81
+ input.receipts === 'identity-mismatch' && shard.id === 'pod-0' ? ['src/other.test.ts'] : shard.files,
82
+ input.receiptHosts?.[shard.id] ?? 'node-c'));
83
+ const plan = planGateShardDispatch({ head40: devices.head40, base40: B,
84
+ shards, receipts,
85
+ hosts: [{ id: 'node-c', platform: 'linux', available: devices.minihAvailable, reserved: false },
86
+ { id: 'node-b', platform: 'linux', available: devices.msb1Available, reserved: false }],
87
+ ...(input.rerouteShard ? { rerouteShard: input.rerouteShard } : {}),
88
+ });
89
+ const dispositions = plan.map((item) => {
90
+ switch (item.kind) {
91
+ case 'reuse': return 'reuse' as const;
92
+ case 'run': return 'remeasure' as const;
93
+ case 'unmeasured': return 'HOLD' as const;
94
+ default: {
95
+ const exhaustive: never = item;
96
+ throw new Error(`unhandled shard action: ${String(exhaustive)}`);
97
+ }
98
+ }
99
+ });
100
+ const action = dispositions.every((kind) => kind === 'reuse') ? 'reuse'
101
+ : dispositions.every((kind) => kind === 'remeasure') ? 'full sweep'
102
+ : dispositions.includes('HOLD') ? 'HOLD' : 'remeasure';
103
+ return { action, evidence: { kind: 'dispatch', actions: plan } };
104
+ }
105
+ if (scenario.planner === 'partial') {
106
+ if (scenario.partialInput?.kind === 'changed-head') {
107
+ const partial = planPartialRegate({ version: '0.2.42', priorCommit: scenario.partialInput.priorCommit, forCommit: scenario.partialInput.forCommit,
108
+ changedFiles: scenario.partialInput.changedFiles, priorFailures: [], priorErrors: [],
109
+ existsAtTip: () => true });
110
+ return { action: partial.ok ? 'remeasure' : 'full sweep', evidence: partial.ok
111
+ ? { kind: 'partial', ok: true, files: partial.plan.files } : { kind: 'none' } };
112
+ }
113
+ if (scenario.partialInput?.kind !== 'stalled') return { action: 'full sweep', evidence: { kind: 'none' } };
114
+ const recheck = planStalledShardRecheck({ version: '0.2.42', measuredCommit: H, forCommit: H,
115
+ failures: [FAILURE], errors: [], stalledFiles: scenario.partialInput.stalledFiles, preservedShardCount: 3,
116
+ existsAtCommit: () => true });
117
+ return recheck.ok ? { action: 'remeasure', evidence: { kind: 'partial', ok: true, files: recheck.plan.files } }
118
+ : { action: 'full sweep', evidence: { kind: 'none' } };
119
+ }
120
+ return { action: 'HOLD', evidence: { kind: 'none' } };
121
+ }
122
+
123
+ function dispositionForOutcome(outcome: 'ok' | 'regression' | 'error'): GateScenarioAction {
124
+ switch (outcome) {
125
+ case 'ok': return 'reuse';
126
+ case 'regression':
127
+ case 'error': return 'HOLD';
128
+ }
129
+ }
130
+
131
+ function output(ids: readonly string[]): string {
132
+ const body = ids.map((id) => `${id.split(' > ')[0]}:\n(fail) ${id.split(' > ')[1]} [1.00ms]\n`).join('');
133
+ return `${body}\n${ids.length} fail\nRan 1 tests across 1 files.\n`;
134
+ }
135
+
136
+ /** Run the production gate classifier with an injected, deterministic sweep outcome. */
137
+ export async function judgeInjectedGateEvent(scenario: GateScenario): Promise<{
138
+ outcome: string; action: GateScenarioAction; evidence: PlannerEvidence; error?: string; podCommandCalls: number;
139
+ }> {
140
+ const root = mkdtempSync(join(tmpdir(), 'gate-node-sim-'));
141
+ const instanceRoot = join(root, 'instance');
142
+ const ledgerRoot = join(root, 'ledger');
143
+ mkdirSync(join(instanceRoot, 'release/1.0.0'), { recursive: true });
144
+ writeFileSync(join(instanceRoot, 'release/1.0.0/release.json'), JSON.stringify({ sourceCommit: B }));
145
+ writeFileSync(join(instanceRoot, 'release/1.0.0/gate-failures.json'), JSON.stringify({ commit: B, failures: [] }));
146
+ const dispatchInput = scenario.dispatchInput ?? { receipts: 'complete' as const, minihAvailable: true };
147
+ const minihDevice = createFakeKubectl({ context: dispatchInput.minihAvailable ? 'node-c' : 'node-c-offline', node: 'worker-sim' });
148
+ const msb1Device = createFakeKubectl({ context: dispatchInput.msb1Available === false ? 'node-b-offline' : 'node-b', node: 'worker-sim' });
149
+ const fakeGh = createFakeGh({ prs: [{ number: 1, title: 'simulated gate event', branch: 'sim', createdAt: '2026-10-29T00:00:00.000Z',
150
+ updatedAt: '2026-10-29T00:00:00.000Z', head: dispatchInput.head40 ?? H }] });
151
+ const minihAvailable = minihDevice.kubectl(['config', 'get-contexts', 'node-c']).status === 0;
152
+ const pr = JSON.parse(fakeGh.api(['api', 'repos/example/repo/pulls/1'])) as { head?: { sha?: string } };
153
+ const msb1Available = msb1Device.kubectl(['config', 'get-contexts', 'node-b']).status === 0;
154
+ const planner = plannerDecision(scenario, { head40: pr.head?.sha ?? '', minihAvailable, msb1Available });
155
+ let podCommandCalls = 0;
156
+ const command: GateRunner['command'] = async (cmd, args, cwd) => {
157
+ if (cmd === 'bun' && args[0] === 'run') {
158
+ const remainsFailing = scenario.gateInjection === 'regression' || scenario.retryResult === 'fail';
159
+ const ids = cwd.endsWith('/cut') && remainsFailing ? [FAILURE] : [];
160
+ return { rc: ids.length ? 1 : 0, output: output(ids) };
161
+ }
162
+ if (cmd === 'git' && args[0] === 'ls-files' && args[1] === '-z') return { rc: 0, output: `${FILE}\0` };
163
+ return { rc: 0, output: '' };
164
+ };
165
+ const tools: GateTools = {
166
+ now: () => Date.now(),
167
+ podCommand: async () => { podCommandCalls++; throw new Error('Pod command is outside the injected sweep seam'); },
168
+ admission: { acquire: async () => () => {}, waitReason: () => null },
169
+ };
170
+ const runner = createGateRunner(root, undefined, command, undefined, undefined, undefined, tools);
171
+ // Inject only the declared test outcome at the sweep boundary; this does not model Pod lifecycle.
172
+ runner.sweep = async (tree) => {
173
+ if (scenario.gateInjection === 'hold') throw new Error(`simulated HOLD: ${scenario.injectedInput}`);
174
+ if (scenario.gateInjection === 'malformed') return { rc: 0, output: 'unparseable simulated JUnit summary' };
175
+ if (tree.endsWith('/cut') && scenario.retryResult) {
176
+ const artifacts = join(root, 'retry-artifacts');
177
+ mkdirSync(artifacts, { recursive: true });
178
+ writeFileSync(join(artifacts, 'install.rc'), '0\n');
179
+ writeFileSync(join(artifacts, 'install.log'), '');
180
+ writeFileSync(join(artifacts, 'part-0.rc'), '1\n');
181
+ writeFileSync(join(artifacts, 'part-0.log'), `${FILE}:\n(pass) stable case [1.00ms]\n(fail) simulated failure [1.00ms]\n1 pass\n1 fail\nRan 2 tests across 1 files.\n`);
182
+ writeFileSync(join(artifacts, 'part-0.junit.xml'), `<testsuites><testsuite file="${FILE}"><testcase name="stable case"/><testcase name="simulated failure"><failure/></testcase></testsuite></testsuites>`);
183
+ writeFileSync(join(artifacts, 'part-0.retry-files'), `${FILE}\n`);
184
+ writeFileSync(join(artifacts, 'part-0.retry-0.started'), '');
185
+ const retryPasses = scenario.retryResult === 'pass';
186
+ writeFileSync(join(artifacts, 'part-0.retry-0.rc'), retryPasses ? '0\n' : '1\n');
187
+ writeFileSync(join(artifacts, 'part-0.retry-0.log'), retryPasses
188
+ ? '1 pass\n0 fail\nRan 1 test across 1 file.\n'
189
+ : '0 pass\n1 fail\nRan 1 test across 1 file.\n');
190
+ writeFileSync(join(artifacts, 'part-0.retry-0.junit.xml'), retryPasses
191
+ ? `<testsuites tests="1"><testsuite file="${FILE}" tests="1"><testcase name="simulated failure"/></testsuite></testsuites>`
192
+ : `<testsuites><testsuite file="${FILE}"><testcase name="simulated failure"><failure/></testcase></testsuite></testsuites>`);
193
+ const read = readShardArtifacts(artifacts, [[FILE]]);
194
+ return { rc: read.rc ?? 2, output: read.output ?? '',
195
+ ...(read.loadFlaky ? { loadFlaky: read.loadFlaky } : {}),
196
+ ...(read.loadFlakyAttemptedFiles ? { loadFlakyAttemptedFiles: read.loadFlakyAttemptedFiles } : {}) };
197
+ }
198
+ const ids = tree.endsWith('/cut') && scenario.gateInjection === 'regression' ? [FAILURE] : [];
199
+ return { rc: ids.length ? 1 : 0, output: output(ids) };
200
+ };
201
+ try {
202
+ const result = await judgeGate({ commit: H, version: '0.2.42', baselineVersion: '1.0.0', instanceRoot, ledgerRoot, repo: root }, runner);
203
+ return { outcome: result.outcome,
204
+ action: result.outcome === 'ok' ? (scenario.planner ? planner.action : dispositionForOutcome(result.outcome)) : dispositionForOutcome(result.outcome),
205
+ evidence: planner.evidence, ...(result.error ? { error: result.error } : {}), podCommandCalls };
206
+ } finally { rmSync(root, { recursive: true, force: true }); }
207
+ }