elanous 0.2.41 → 0.2.43

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 (796) 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 → Om5xS9jpjSXJCeTNGYEi4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{2fe2c302.41b517f88d6fe502.js → 0966f8a1.745fcd44f64a87ea.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{385e4574.e9886ab32759eda3.js → 0ad6802e.ae7afb63fdcb4491.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/114.2b90424d1a3ce84c.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1151-5c2bb8f002ca2dd6.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1200.6a37c202f9f17e9a.js +226 -0
  9. package/apps/pwa/out/_next/static/chunks/1261-a616d5728e02e624.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1313-19f737e0222c4444.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1357.3bbef3976c37f94a.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1362-20adddfaf662b0fa.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{6874.d5cf7eb8edb2cabe.js → 1406.a1dc2ab6f8449374.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/1737-9491fc6ab29b9ec6.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1803-4f91a8e7dcaf042c.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{5744.b9415e18ad623100.js → 1961.a81b12872c3e93a9.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/1970cf59.2d4d8ce5d6c81853.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1971-8890f3962ba7ee0a.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/2073-ba274e00e4f9efb4.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/{5471.1e611302ed3a7c53.js → 2144.25b292396712196d.js} +2 -2
  21. package/apps/pwa/out/_next/static/chunks/{3230-49298c3b73ef2268.js → 2268-53861f339e0b65a2.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/{9834.63ab2bbc3153172e.js → 2312.0c8b61e22d3136d7.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/{1800.f7ff51dc4978a958.js → 2573.387a707f6f9d720c.js} +2 -2
  24. package/apps/pwa/out/_next/static/chunks/273.f156eee28f11af77.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2873.d2140e5a82546401.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/{9048.212083de42d25be3.js → 3072.01338851ca21a6f7.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3091.a5a4143dea33d197.js +90 -0
  28. package/apps/pwa/out/_next/static/chunks/3095.dc44586a5f83b86d.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{2263.e09b6edea33bad2d.js → 3113.d7472bbc27d580c7.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/3228-9650b6447b6fa288.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3402.44b565b314f2263c.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{addc2b32.8c4ff8f0aefe987d.js → 3557ac4a.c8931684475018ad.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/360.ae9f9f4c33c395e8.js +79 -0
  34. package/apps/pwa/out/_next/static/chunks/3638.80412ea63aae8f3f.js +286 -0
  35. package/apps/pwa/out/_next/static/chunks/{a0a01613.6d1cca322238d7fe.js → 363bfab3.9623b9f89363541f.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3694.e0099884345f0198.js +64 -0
  37. package/apps/pwa/out/_next/static/chunks/3744.54f87db52acfd1ab.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3903.3ef4656c67572764.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3935.16701e33f8982dc9.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3955.6922286237f2ac2b.js +24 -0
  41. package/apps/pwa/out/_next/static/chunks/3969.272ee7f9fd6c62e5.js +34 -0
  42. package/apps/pwa/out/_next/static/chunks/4199.ce86b281fd0a60b7.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4311-6dd3144002cc0c2d.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4426-2b230fad00c88930.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{530.d26346e18089640a.js → 4445.7990c76b3751a918.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/4447-14c5161fa59166c7.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4856-b0b8075bba8c53f4.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4870-de370d65e73c0bb5.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4885-2c989165c4b29fad.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4894.fec2ca9e99caefa2.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/5093.8f04b7f8cb899a95.js +94 -0
  52. package/apps/pwa/out/_next/static/chunks/5122-2bb177cebf89e19a.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5154.5f56dc3902e3d275.js +36 -0
  54. package/apps/pwa/out/_next/static/chunks/529.64ff7257180b2ac9.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5394.5dabeb0c62293a28.js +93 -0
  56. package/apps/pwa/out/_next/static/chunks/5461.08bf2404ff38ec85.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5474-22e08a85583209b2.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1219.7e17964e0e7cd8e5.js → 5564.9e72532188f57586.js} +3 -3
  59. package/apps/pwa/out/_next/static/chunks/5567-265df39ed8fe9dcb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/5570-a94ae19811cb2046.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5574-b47c9ef2dceff1fd.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5628.6ddb2d5ffba4ff4c.js +309 -0
  63. package/apps/pwa/out/_next/static/chunks/5730.43d7ccc09988e646.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{1178.1aa9cad0e7695427.js → 5789.2da35c258292e1e5.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/{4133.2056bb4d78f621af.js → 5824.da9527b15a3221e5.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/5866.366966af47fdde5d.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{4527.a69f2894d1bc9f4a.js → 5930.8b4df3b46c32b05a.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5963-c4d8469c52a0828b.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/6001.ec4049ceb3c43418.js +27 -0
  70. package/apps/pwa/out/_next/static/chunks/6120-471f03db1e299c0c.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6175-41479e643aca1878.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6291.a2de4f9787637075.js +104 -0
  73. package/apps/pwa/out/_next/static/chunks/6400-6699907c3537436a.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6428.1f4327d6ae5fdf9a.js +287 -0
  75. package/apps/pwa/out/_next/static/chunks/644.02cb026fa44bcd0a.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6466-6c87d60d3dd174fb.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{9507.7026657a2f47eb64.js → 6540.c7bef57ad8f90a87.js} +16 -16
  78. package/apps/pwa/out/_next/static/chunks/6773.d4264665ab31bec0.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6822.3c789f1a8443e774.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{5574.f35accf4f132b29d.js → 6944.309f4e3ea54d1537.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7261-8ff69d3b2ee671fd.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7266.084c6bbc70035140.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7271.5c0100e7320aa856.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7429-bf5731358c8f2f68.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7464.01f7a0ae1215fbe7.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7479.0fcad5f37eb64f0c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7483.427a2fe2049e388d.js +148 -0
  88. package/apps/pwa/out/_next/static/chunks/7502-be74718178e13e56.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7530.0889722b19572065.js +24 -0
  90. package/apps/pwa/out/_next/static/chunks/7645.5b2ee3ad45c55ea3.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7788.7d1c79f1a8e18946.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7900.096f455c7c1efc53.js +77 -0
  93. package/apps/pwa/out/_next/static/chunks/7910-6f139bcafd238b9f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7966.f71c8958d1637548.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{5947-135e26537d80a6b9.js → 8062-7cd0bcc7f01455ba.js} +3 -3
  96. package/apps/pwa/out/_next/static/chunks/8073.f6cf2f2c71aafbd0.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8201.190b94088980f430.js +74 -0
  98. package/apps/pwa/out/_next/static/chunks/8205.282ca4bb62d54a0a.js +62 -0
  99. package/apps/pwa/out/_next/static/chunks/8313-dfa1021bb58a46d6.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/837-81336ebaca8198a8.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8447.7963352ef5f71b76.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8574-868e8129525ef6d9.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8588.d1c6a2903727ce87.js +149 -0
  104. package/apps/pwa/out/_next/static/chunks/8637.90f92d5c8db4732c.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{2743.5d3f76948be32b34.js → 868.6e953be05bcf6dca.js} +2 -2
  106. package/apps/pwa/out/_next/static/chunks/8706-e1fe0309343a2273.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8749-06384cdfc4520add.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{5964-7e21164a8f2cf0ce.js → 8861-cc1fa1c7b920fa8e.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/8967-7dfebf710c9dec9d.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{5159.115f1c2ca471386c.js → 8986.8e2e4efbfa655c59.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/8997-3c564dbb3b58b055.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/923.2034d10ae91e9c20.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9312.bc1b89c5d4368033.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/943.39ae5e82f4f1893f.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9469.0500480de55fb205.js +32 -0
  116. package/apps/pwa/out/_next/static/chunks/9770.5f75bc6088b16109.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9810-2543267050e58b82.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9870.8419702475254745.js +8 -0
  119. package/apps/pwa/out/_next/static/chunks/9941-376d1b74d51b01a4.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9958.385434ab04241758.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{b2271e54.c1de3347976e90b0.js → aa57532f.510551854ff239b1.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-deea1450b17cb8dc.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-70985b904f8650ef.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a2e15e33e56a4353.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-fc72ce2db12d6ca9.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-be03e41f9436ebd9.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-35a35999382da3f2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-3ff5b1e6ca88b848.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-a65101300a0ee5c1.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-3aca5b6d67dba511.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-45b8ab0a71e61314.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-53046e282d4cda8e.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-17809e60e8354c17.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-fd2442d347bf5898.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e9d720d6fc082e21.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-6b8b4267bab0a677.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-deea1450b17cb8dc.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-8bcf6233ac7c17af.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-7cc25591cfc2126f.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-053e871f35c9beba.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-eff819f0c2d5e084.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-4d7e9d8db5274a87.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2b2d8f5aa5f69ad4.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-0b8f92c5062e68b1.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1bd9d0fdac2ced3d.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-9ee28f7df07428ea.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-44b7a1ff468c6648.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-cbc6523711dc1b65.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-fdad47899c2695be.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-40f9e19149024298.js → page-79a8b5fee4c20871.js} +1 -1
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-03e8ac9606aeaffb.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-4cd55c55ec287e2f.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-db17b4305404161e.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-30041d848350fd02.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c540da022dbf86b0.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9399efc538da057f.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-a142dfb0331a05f5.js → page-ca2d09128c585ca4.js} +1 -1
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-0e2635aecd343038.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ef7f4399b6b7726e.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-deea1450b17cb8dc.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-caf530535b875468.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-eaa20c1543a5fd8e.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c541eb1b75120f61.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-ab5e213eda9479f4.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-0a815f34367b6db6.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-e858ba0ed9393b68.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-1638ee9dd6e0582f.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-4cf5a399109391f2.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b4396321238798ec.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-cb72bfd21006781a.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6135d0242afbc434.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a1dccf907eddb856.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{53aeb4ee-51c92f8d683f5220.js → c7945435-b44d4dbe90ba0dcb.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/{2fdf2931.b431eee4fb468bc3.js → cb0f8df8.09a4a6be97e3fc5f.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/{c0c1a699.0ba79f97005965d4.js → d96660fb.cbc21a2a88539dbb.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/ea514caa.05a24f78d9dffe5f.js +122 -0
  177. package/apps/pwa/out/_next/static/chunks/{83184dcd-0ee6247ff41eb3f2.js → fb7d20d5-6892502b6ee39ca6.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-e8a911e19b1be41f.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-7022f418fabba021.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-e5f15df755756a1e.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-4525f91e36940c9b.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-140f0e519c085b0f.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-8f22ef63dcb865b1.js +1 -0
  184. package/apps/pwa/out/_next/static/css/{b9d8151e48998417.css → 62c858ad53854f47.css} +1 -1
  185. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.css +1 -0
  186. package/apps/pwa/out/approvals/index.html +1 -1
  187. package/apps/pwa/out/approvals/index.txt +23 -23
  188. package/apps/pwa/out/autopilot/index.html +1 -1
  189. package/apps/pwa/out/autopilot/index.txt +23 -23
  190. package/apps/pwa/out/board/index.html +1 -1
  191. package/apps/pwa/out/board/index.txt +23 -23
  192. package/apps/pwa/out/botlab/index.html +1 -1
  193. package/apps/pwa/out/botlab/index.txt +22 -22
  194. package/apps/pwa/out/bots/index.html +1 -1
  195. package/apps/pwa/out/bots/index.txt +22 -22
  196. package/apps/pwa/out/ceo/index.html +1 -1
  197. package/apps/pwa/out/ceo/index.txt +23 -23
  198. package/apps/pwa/out/chat/index.html +1 -1
  199. package/apps/pwa/out/chat/index.txt +22 -22
  200. package/apps/pwa/out/consult/index.html +1 -1
  201. package/apps/pwa/out/consult/index.txt +23 -23
  202. package/apps/pwa/out/control/index.html +1 -1
  203. package/apps/pwa/out/control/index.txt +23 -23
  204. package/apps/pwa/out/decisions/index.html +1 -1
  205. package/apps/pwa/out/decisions/index.txt +22 -22
  206. package/apps/pwa/out/design-check/index.html +1 -1
  207. package/apps/pwa/out/design-check/index.txt +23 -23
  208. package/apps/pwa/out/editor/index.html +1 -1
  209. package/apps/pwa/out/editor/index.txt +24 -25
  210. package/apps/pwa/out/exec/index.html +1 -1
  211. package/apps/pwa/out/exec/index.txt +23 -23
  212. package/apps/pwa/out/field/index.html +1 -1
  213. package/apps/pwa/out/field/index.txt +23 -23
  214. package/apps/pwa/out/healthz +1 -1
  215. package/apps/pwa/out/index.html +1 -1
  216. package/apps/pwa/out/index.txt +22 -22
  217. package/apps/pwa/out/inside/index.html +1 -1
  218. package/apps/pwa/out/inside/index.txt +23 -23
  219. package/apps/pwa/out/intake/index.html +1 -1
  220. package/apps/pwa/out/intake/index.txt +23 -23
  221. package/apps/pwa/out/live/index.html +1 -1
  222. package/apps/pwa/out/live/index.txt +24 -25
  223. package/apps/pwa/out/live-run/index.html +1 -1
  224. package/apps/pwa/out/live-run/index.txt +24 -25
  225. package/apps/pwa/out/loops/index.html +1 -1
  226. package/apps/pwa/out/loops/index.txt +22 -22
  227. package/apps/pwa/out/market/index.html +1 -1
  228. package/apps/pwa/out/market/index.txt +22 -22
  229. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  230. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  231. package/apps/pwa/out/morning/index.html +1 -1
  232. package/apps/pwa/out/morning/index.txt +23 -23
  233. package/apps/pwa/out/observatory/index.html +1 -1
  234. package/apps/pwa/out/observatory/index.txt +23 -23
  235. package/apps/pwa/out/ops/checklist/index.html +1 -1
  236. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  237. package/apps/pwa/out/ops/release/index.html +1 -1
  238. package/apps/pwa/out/ops/release/index.txt +22 -22
  239. package/apps/pwa/out/ops/seats/index.html +1 -1
  240. package/apps/pwa/out/ops/seats/index.txt +22 -22
  241. package/apps/pwa/out/outputs/index.html +1 -1
  242. package/apps/pwa/out/outputs/index.txt +22 -22
  243. package/apps/pwa/out/reflection/index.html +1 -1
  244. package/apps/pwa/out/reflection/index.txt +23 -23
  245. package/apps/pwa/out/scheduler/index.html +1 -1
  246. package/apps/pwa/out/scheduler/index.txt +23 -23
  247. package/apps/pwa/out/sessions/index.html +1 -1
  248. package/apps/pwa/out/sessions/index.txt +22 -22
  249. package/apps/pwa/out/settings/devices/index.html +1 -1
  250. package/apps/pwa/out/settings/devices/index.txt +23 -23
  251. package/apps/pwa/out/settings/index.html +1 -1
  252. package/apps/pwa/out/settings/index.txt +23 -23
  253. package/apps/pwa/out/setup/done/index.html +1 -1
  254. package/apps/pwa/out/setup/done/index.txt +23 -23
  255. package/apps/pwa/out/setup/index.html +1 -1
  256. package/apps/pwa/out/setup/index.txt +23 -23
  257. package/apps/pwa/out/share/index.html +1 -1
  258. package/apps/pwa/out/share/index.txt +23 -23
  259. package/apps/pwa/out/showroom/index.html +1 -1
  260. package/apps/pwa/out/showroom/index.txt +22 -22
  261. package/apps/pwa/out/tasks/index.html +1 -1
  262. package/apps/pwa/out/tasks/index.txt +23 -23
  263. package/apps/pwa/out/term/index.html +1 -1
  264. package/apps/pwa/out/term/index.txt +23 -23
  265. package/apps/pwa/out/today/index.html +1 -1
  266. package/apps/pwa/out/today/index.txt +23 -23
  267. package/apps/pwa/out/trace/index.html +1 -1
  268. package/apps/pwa/out/trace/index.txt +23 -23
  269. package/apps/pwa/out/vault/index.html +1 -1
  270. package/apps/pwa/out/vault/index.txt +23 -23
  271. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  272. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  273. package/apps/pwa/out/workflows/index.html +1 -1
  274. package/apps/pwa/out/workflows/index.txt +23 -23
  275. package/apps/pwa/out/workspace/index.html +1 -1
  276. package/apps/pwa/out/workspace/index.txt +23 -23
  277. package/apps/pwa/out/worktrees/index.html +1 -1
  278. package/apps/pwa/out/worktrees/index.txt +23 -23
  279. package/catalog/external-commands.yaml +5 -3
  280. package/catalog/meta/catalogVersion.yaml +2 -1
  281. package/catalog/signing/catalog-signing-public.pem +3 -0
  282. package/docs/goal-context/04-mock-scenarios.md +13 -0
  283. package/graphs/catalog/catalog.yaml +1 -1
  284. package/graphs/heal/heal-loop.yaml +1 -0
  285. package/graphs/intake/intake-daily.yaml +16 -0
  286. package/graphs/intake/news-sources.yaml +1 -0
  287. package/graphs/intake/recipes.yaml +7 -0
  288. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  289. package/graphs/overlays/stop-heal-ladder.yaml +113 -0
  290. package/graphs/profiles/local.yaml +5 -0
  291. package/graphs/profiles/pod.yaml +4 -0
  292. package/graphs/units/verbs/recipes.yaml +11 -11
  293. package/graphs/work/research-report.yaml +10 -2
  294. package/package.json +6 -2
  295. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  296. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  297. package/plugins/demo-browser-hand/plugin.json +13 -0
  298. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  299. package/plugins/demo-linear-secretary/plugin.json +15 -0
  300. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  301. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  302. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  303. package/plugins/demo-research/plugin.json +16 -0
  304. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  305. package/plugins/demo-video-briefing/plugin.json +15 -0
  306. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  307. package/scripts/build-signed-catalog.ts +48 -0
  308. package/scripts/ci-typecheck-main-delta.sh +88 -0
  309. package/scripts/codex-fallback-live-probe.ts +1 -1
  310. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  311. package/scripts/demo/demo1104-stage.config.ts +21 -0
  312. package/scripts/demo/demo1104-stage.ts +316 -0
  313. package/scripts/goal-method-audit.ts +17 -1
  314. package/scripts/graph-units/land-enqueue.ts +90 -0
  315. package/scripts/heal/run-role.ts +99 -5
  316. package/scripts/hooks/codex-notify.sh +32 -0
  317. package/scripts/install.sh +10 -38
  318. package/scripts/land-global-checks.ts +6 -1
  319. package/scripts/landing-heal/land-plan.ts +57 -0
  320. package/scripts/lib/decompose-ab.ts +1 -0
  321. package/scripts/lib/fixtures/tui-regress/help-insufficient-commands.txt +15 -0
  322. package/scripts/lib/fixtures/tui-regress/help-live.txt +42 -0
  323. package/scripts/lib/fixtures/tui-regress/help-missing-keys.txt +21 -0
  324. package/scripts/lib/fixtures/tui-regress/help-original.txt +51 -0
  325. package/scripts/lib/fixtures/tui-regress/help-shifted-input.txt +26 -0
  326. package/scripts/lib/tui-regress-checks.ts +33 -13
  327. package/scripts/release-loop/auto-approve-node.ts +1 -1
  328. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  329. package/scripts/release-loop/gate-baseline-receipt.ts +47 -9
  330. package/scripts/release-loop/gate-image-pin.ts +81 -0
  331. package/scripts/release-loop/gate-method.ts +139 -0
  332. package/scripts/release-loop/gate-node-sim.ts +207 -0
  333. package/scripts/release-loop/gate-node.ts +463 -64
  334. package/scripts/release-loop/gate-pod-image-sticky-plan.ts +99 -0
  335. package/scripts/release-loop/gate-radius-live.ts +97 -13
  336. package/scripts/release-loop/gate-shard-dispatch.ts +43 -0
  337. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  338. package/scripts/release-loop/gate-train-receipts.ts +122 -0
  339. package/scripts/release-loop/node-verdict.ts +38 -25
  340. package/scripts/release-loop/preflight.ts +362 -8
  341. package/scripts/release-loop/resume-release.ts +83 -8
  342. package/scripts/release-loop/unattended-release.ts +20 -9
  343. package/scripts/rhythm/daily.ts +36 -4
  344. package/scripts/rhythm/linear-progress-sync.ts +298 -0
  345. package/scripts/ux-sim.ts +18 -1
  346. package/scripts/video-pipeline.ts +9 -1
  347. package/scripts/warm-pool-provider-config.ts +286 -0
  348. package/skills/omni-crawl/SKILL.md +5 -2
  349. package/skills/omni-crawl/scripts/main.ts +84 -23
  350. package/src/acp/agent-manager.ts +1 -0
  351. package/src/acp/codex-app-server-agent.ts +33 -0
  352. package/src/acp/codex-app-server-client.ts +153 -16
  353. package/src/acp/core-turn-bridge.ts +27 -9
  354. package/src/acp/event-router.ts +20 -1
  355. package/src/acp/server.ts +6 -0
  356. package/src/agent/registry.ts +2 -0
  357. package/src/agent/task-notification.ts +25 -5
  358. package/src/agent/types.ts +6 -0
  359. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  360. package/src/agent-mission/claude-headless.ts +4 -1
  361. package/src/agent-mission/codex-exec.ts +105 -0
  362. package/src/agent-mission/driver.ts +192 -11
  363. package/src/agent-mission/grok-auth-status.ts +47 -0
  364. package/src/agent-mission/hand-hooks.ts +101 -0
  365. package/src/agent-mission/mission-cli.ts +63 -4
  366. package/src/agent-mission/mission-hand-reply.ts +118 -0
  367. package/src/agent-mission/mission-line.ts +180 -0
  368. package/src/agent-mission/mission-out.ts +833 -0
  369. package/src/agent-mission/tool-install.ts +200 -3
  370. package/src/agent-substrate/context-strategy.ts +4 -4
  371. package/src/agent-substrate/self-review-cli.ts +178 -13
  372. package/src/agents/general-purpose.md +1 -1
  373. package/src/auto-research/research-turn.ts +211 -53
  374. package/src/autopilot/pr-manager.ts +69 -10
  375. package/src/autopilot/pty-control-loop.ts +2 -0
  376. package/src/boot/daemon-tools/self-implement.ts +3 -1
  377. package/src/boot/daemon-tools/web-search.ts +1 -2
  378. package/src/briefing/brief-items.ts +55 -11
  379. package/src/capture/tui-self-report.ts +22 -6
  380. package/src/chat/index.ts +1 -1
  381. package/src/cli/agent-cli.ts +2 -1
  382. package/src/cli/catalog-cli.ts +31 -0
  383. package/src/cli/connector-cli.ts +16 -0
  384. package/src/cli/doctor-fix.ts +2 -2
  385. package/src/cli/fixtures/review-loop-breaker/opwaiver-32646-1694ccc7a170.json +1 -0
  386. package/src/cli/fixtures/review-loop-breaker/opwaiver-32853-bd8f73595c83.json +1 -0
  387. package/src/cli/fixtures/review-loop-breaker/opwaiver-33097-1cc85900413c.json +1 -0
  388. package/src/cli/fixtures/review-loop-breaker/opwaiver-33106-972f31e4a3ca.json +1 -0
  389. package/src/cli/fixtures/review-loop-breaker/opwaiver-33113-3ab51f05968f.json +1 -0
  390. package/src/cli/fixtures/review-loop-breaker/pr-33097-1cc85900413c.json +1 -0
  391. package/src/cli/intake-source-cli.ts +44 -8
  392. package/src/cli/msg-cli.ts +32 -3
  393. package/src/cli/pr-cli.ts +21 -1
  394. package/src/cli/pr-land-heavy-remote.ts +75 -5
  395. package/src/cli/pr-land-overlap-evidence.ts +113 -2
  396. package/src/cli/pr-land-pod-shadow-job.ts +202 -4
  397. package/src/cli/pr-land-pod-shadow.ts +9 -2
  398. package/src/cli/release-checklist-read-cli.ts +57 -19
  399. package/src/cli/release-cli.ts +23 -3
  400. package/src/cli/research-cli.ts +13 -5
  401. package/src/cli/setup-cli.ts +166 -6
  402. package/src/cli/setup-keys.ts +187 -0
  403. package/src/cli/task-plugin-wizard-host.ts +114 -0
  404. package/src/cli/tasks-cli.ts +61 -9
  405. package/src/cli/tui-test-cli.ts +186 -0
  406. package/src/compact/auto.ts +8 -1
  407. package/src/config.ts +4 -2
  408. package/src/connectors/linear-daily-progress.ts +228 -0
  409. package/src/connectors/linear-projector.ts +34 -12
  410. package/src/connectors/linear.ts +151 -7
  411. package/src/control-plane/ledger.ts +52 -2
  412. package/src/control-plane/server.ts +16 -2
  413. package/src/core-turn/deep-turn-bloom.ts +67 -0
  414. package/src/core-turn/research-policy.ts +37 -0
  415. package/src/core-turn/run-core-turn.ts +606 -95
  416. package/src/core-turn/run-goal-loop.ts +18 -0
  417. package/src/core-turn/types.ts +4 -0
  418. package/src/dashboard/chat/acp-chat.ts +10 -0
  419. package/src/dashboard/classic-sidetab-mission-job.ts +161 -0
  420. package/src/dashboard/classic-sidetab-mission-pair.ts +81 -0
  421. package/src/dashboard/classic-sidetab-mission-trio.ts +219 -0
  422. package/src/dashboard/classic-sidetab-mission.ts +347 -0
  423. package/src/dashboard/index.ts +517 -18
  424. package/src/dashboard/input/agent-wake.ts +23 -1
  425. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  426. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +17 -0
  427. package/src/dashboard/mission-cli-consumer.ts +165 -0
  428. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  429. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  430. package/src/dashboard/seat-boot-preamble.ts +171 -1
  431. package/src/dashboard/side-basic-runtime.ts +54 -1
  432. package/src/dashboard/sidetab-runtime.ts +90 -1
  433. package/src/dashboard/skill-catalog-preamble.ts +101 -0
  434. package/src/dashboard/skill-detection-runtime.ts +55 -15
  435. package/src/dashboard/slash-runtime/dashboard-handlers.ts +15 -0
  436. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  437. package/src/dashboard/turn-preamble.ts +53 -15
  438. package/src/dashboard/turn-prompt-runtime.ts +4 -2
  439. package/src/decisions/linear-progress-summary.ts +78 -0
  440. package/src/decisions/linear-progress-sync.ts +152 -0
  441. package/src/domains/outbound-alert.ts +49 -11
  442. package/src/domains/telegram-kind-route.ts +16 -9
  443. package/src/graph-runner/arg-allowance.ts +13 -0
  444. package/src/graph-runner/graph-cli.ts +23 -7
  445. package/src/graph-runner/graph-run-api.ts +3 -1
  446. package/src/graph-runner/graph-tick.ts +10 -2
  447. package/src/graph-runner/runner.ts +86 -18
  448. package/src/graph-wizard/mission-compose.ts +407 -12
  449. package/src/grok/agent-search.ts +14 -4
  450. package/src/grok/credential.ts +28 -11
  451. package/src/harness/dispatch-backpressure.ts +54 -1
  452. package/src/harness/dispatch-shadow-compare.ts +74 -0
  453. package/src/harness/harness-cli-command.ts +11 -1
  454. package/src/harness/harness-pod-dispatch.ts +81 -15
  455. package/src/harness/harness-stop.ts +155 -11
  456. package/src/harness/skill-exec.ts +21 -9
  457. package/src/harness/skill-select.ts +1 -1
  458. package/src/hooks/error-report-cloud.ts +101 -0
  459. package/src/hooks/receiver.ts +29 -2
  460. package/src/index.ts +159 -13
  461. package/src/instance/spawn-elanous.ts +6 -4
  462. package/src/intake-plane/actions.ts +354 -0
  463. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  464. package/src/intake-plane/intake-sources.ts +78 -8
  465. package/src/intake-plane/items.ts +14 -4
  466. package/src/intake-plane/linear-mission-sync.ts +80 -0
  467. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  468. package/src/intake-plane/linear-wish.ts +227 -1
  469. package/src/life/life-cli.ts +168 -0
  470. package/src/life/life-kinds.ts +160 -0
  471. package/src/live-supply/budget-consumer.ts +78 -0
  472. package/src/live-supply/read.ts +3 -0
  473. package/src/live-supply/snapshot.ts +45 -0
  474. package/src/llm/provider-credentials.ts +8 -2
  475. package/src/llm.ts +168 -9
  476. package/src/loops/orchestrator/coordinator-shadow.ts +226 -0
  477. package/src/loops/orchestrator/tick.ts +13 -0
  478. package/src/maturity/feature-maturity.ts +4 -4
  479. package/src/msg/msg-sse-server.ts +3 -3
  480. package/src/msg/msg-store.ts +177 -19
  481. package/src/native-tool-catalog.ts +38 -4
  482. package/src/nexus/api/harness-traversal.ts +11 -0
  483. package/src/nexus/api/http-server.ts +37 -1
  484. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  485. package/src/nexus/index.ts +7 -2
  486. package/src/nexus/outbound/format.ts +9 -0
  487. package/src/nexus/outbound/router.ts +98 -13
  488. package/src/nexus/setup-status.ts +9 -0
  489. package/src/nexus/state/state.ts +3 -0
  490. package/src/oauth/codex-account-store.ts +20 -7
  491. package/src/oauth/codex-owner-mirror.ts +44 -0
  492. package/src/oauth/codex.ts +17 -2
  493. package/src/oauth/fallback-chain.ts +47 -17
  494. package/src/onboarding/first-run-doctor.ts +8 -1
  495. package/src/onboarding/first-run.ts +85 -26
  496. package/src/onboarding/key-setup.ts +103 -0
  497. package/src/onboarding/menu-answer.ts +13 -0
  498. package/src/onboarding/secret-prompt.ts +37 -0
  499. package/src/plugins/install/plugin-install.ts +59 -0
  500. package/src/pr-tool/census.ts +133 -2
  501. package/src/pty-shell/pty-control-ipc.ts +4 -1
  502. package/src/pty-shell/tui-run-state.ts +188 -2
  503. package/src/registry/catalog-server.ts +232 -0
  504. package/src/registry/loader.ts +45 -1
  505. package/src/registry/types.ts +1 -2
  506. package/src/release-loop/checklist-target-path-hint.ts +13 -0
  507. package/src/release-loop/checklist.ts +9 -1
  508. package/src/repl/index.ts +43 -2
  509. package/src/research/axis-fanout.ts +136 -16
  510. package/src/research/bloom-exemplars.ts +3 -1
  511. package/src/research/gap-followup.ts +13 -1
  512. package/src/research/plugin-discovery.ts +36 -14
  513. package/src/research-bridge/invoke.ts +22 -5
  514. package/src/research-bridge/types.ts +2 -0
  515. package/src/self-dev/ask-launch-flow.ts +72 -1
  516. package/src/self-dev/decompose.ts +119 -5
  517. package/src/self-dev/dev-cli.ts +4 -1
  518. package/src/self-dev/dev-pipeline.ts +5 -0
  519. package/src/self-dev/draft-residue.ts +64 -5
  520. package/src/self-dev/graph-front-nodes.ts +2 -1
  521. package/src/self-dev/graph-journey-route.ts +76 -21
  522. package/src/self-dev/launch-preflight-text.ts +5 -6
  523. package/src/self-dev/launch-preflight.ts +58 -0
  524. package/src/self-dev/orchestrate.ts +13 -3
  525. package/src/self-dev/review-provider-fallback.ts +9 -2
  526. package/src/self-dev/run-supervisor.ts +42 -4
  527. package/src/self-dev/run-types.ts +4 -0
  528. package/src/self-dev/shard-aggregate.ts +4 -0
  529. package/src/self-dev/shard-run.ts +36 -15
  530. package/src/self-implement/abandoned-classification.ts +12 -3
  531. package/src/self-implement/budget-gate.ts +7 -0
  532. package/src/self-implement/child-llm-preference.ts +10 -1
  533. package/src/self-implement/doctor-visit.ts +118 -8
  534. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  535. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  536. package/src/self-implement/gate-artifacts.ts +2 -1
  537. package/src/self-implement/goal-author-cli.ts +4 -2
  538. package/src/self-implement/goal-author.ts +684 -7
  539. package/src/self-implement/graph-overlay-yaml.ts +37 -4
  540. package/src/self-implement/graph-overlay.ts +3 -1
  541. package/src/self-implement/graph-profile-yaml.ts +107 -0
  542. package/src/self-implement/graph-yaml.ts +26 -3
  543. package/src/self-implement/headless-elanous-driver.ts +31 -2
  544. package/src/self-implement/heal-intake.ts +112 -4
  545. package/src/self-implement/heal-triage.ts +20 -0
  546. package/src/self-implement/host-regate.ts +27 -4
  547. package/src/self-implement/merge-train.ts +5 -0
  548. package/src/self-implement/off-diff-evidence.ts +249 -5
  549. package/src/self-implement/orchestrator.ts +365 -25
  550. package/src/self-implement/regate-detail.ts +38 -1
  551. package/src/self-implement/rework-child-provider.ts +25 -0
  552. package/src/self-implement/run-chart.ts +122 -0
  553. package/src/self-implement/run-ledger.ts +162 -11
  554. package/src/self-implement/run-stop.ts +188 -4
  555. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  556. package/src/self-implement/stop-autoheal.ts +13 -0
  557. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  558. package/src/self-implement/train-gate-receipt.ts +166 -0
  559. package/src/self-implement/train-gate-remote.ts +62 -18
  560. package/src/session/chat.ts +40 -4
  561. package/src/session/session-fanout.ts +2 -0
  562. package/src/session/streaming/acp-stream-sink.ts +2 -1
  563. package/src/session/streaming/chunk-producer.ts +6 -0
  564. package/src/session/streaming/stream-compositor.ts +3 -2
  565. package/src/session-runtime/index.ts +135 -5
  566. package/src/session-runtime/retry-policy.ts +1 -1
  567. package/src/session-runtime/tier-flip.ts +3 -3
  568. package/src/setup/llm-env-detect.ts +3 -0
  569. package/src/setup/service-key-catalog.ts +46 -0
  570. package/src/setup/service-keys.ts +241 -0
  571. package/src/sidetab-core/model.ts +19 -5
  572. package/src/sidetab-core/visible-agent-mission.ts +262 -0
  573. package/src/skills/name-match.ts +20 -0
  574. package/src/skills/tools/agent.ts +53 -6
  575. package/src/skills/tools/omni-search.ts +173 -13
  576. package/src/task-agent/parent-host.ts +10 -0
  577. package/src/task-agent/pod-distributor-entry.ts +3 -0
  578. package/src/task-agent/repair-outcomes.ts +65 -0
  579. package/src/task-agent/task-hand.ts +47 -7
  580. package/src/task-orchestrator/dispatcher.ts +14 -1
  581. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  582. package/src/task-orchestrator/store.ts +16 -5
  583. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +4 -0
  584. package/src/task-orchestrator/surfaces/pod-distributor.ts +48 -0
  585. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +92 -1
  586. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +38 -1
  587. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  588. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +33 -6
  589. package/src/task-orchestrator/surfaces/pod-source-bundle.ts +45 -9
  590. package/src/task-orchestrator/surfaces/pod-source-receive.ts +178 -16
  591. package/src/task-orchestrator/surfaces/pod-source-spec.ts +3 -3
  592. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  593. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +237 -41
  594. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +80 -3
  595. package/src/task-orchestrator/surfaces/self-implement-pod.ts +337 -51
  596. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  597. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  598. package/src/task-orchestrator/types.ts +14 -0
  599. package/src/telegram.ts +14 -16
  600. package/src/terminal/coding-agent.ts +14 -5
  601. package/src/terminal/session-registry.ts +1 -1
  602. package/src/tokens.ts +35 -2
  603. package/src/tool-hints/gate.ts +1 -0
  604. package/src/tool-runtime/agent-runtime.ts +2 -0
  605. package/src/tool-runtime/browser-hand-runtime.ts +381 -0
  606. package/src/tool-runtime/browser-runtime.ts +2 -1
  607. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  608. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +57 -0
  609. package/src/tool-runtime/elanous-skills-list-runtime.ts +5 -1
  610. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  611. package/src/tool-runtime/index.ts +6 -0
  612. package/src/tool-runtime/skill-exec-runtime.ts +33 -13
  613. package/src/tool-runtime/types.ts +4 -0
  614. package/src/tui/entry.ts +38 -5
  615. package/src/tui/sidetab/attach.ts +177 -1
  616. package/src/tui/sidetab/herdr-portal.ts +225 -0
  617. package/src/tui-client/local-chat-turn.ts +26 -13
  618. package/src/tui.ts +22 -0
  619. package/src/user-config.ts +34 -9
  620. package/src/user-intent/types.ts +4 -3
  621. package/src/ux-sim/browser-hand.ts +165 -0
  622. package/src/ux-sim/draft-inventory-builder.ts +198 -0
  623. package/src/ux-sim/fake-browser-page.ts +81 -0
  624. package/src/ux-sim/fake-kubectl.ts +37 -3
  625. package/src/ux-sim/fake-linear-device.ts +31 -0
  626. package/src/ux-sim/fault-pool-cap.ts +11 -6
  627. package/src/ux-sim/graph-engine-sim.ts +47 -0
  628. package/src/ux-sim/linear-secretary.ts +216 -0
  629. package/src/ux-sim/mock-scenario-catalog.json +93 -0
  630. package/src/ux-sim/mock-scenario-catalog.ts +274 -0
  631. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  632. package/src/ux-sim/scenario.ts +185 -48
  633. package/src/ux-sim/service-key-setup.ts +50 -0
  634. package/src/ux-sim/term-slash-device.ts +74 -0
  635. package/src/ux-sim/turn-throw-sim.ts +31 -0
  636. package/src/version/packed-revision.json +1 -1
  637. package/src/voice/voice-tts-singleton.ts +18 -3
  638. package/src/web-search/exa.ts +77 -0
  639. package/src/web-search/grok.ts +5 -9
  640. package/src/web-search/index.ts +30 -9
  641. package/src/web-search/provider.ts +4 -1
  642. package/src/web-search/x-intent.ts +5 -0
  643. package/apps/pwa/out/_next/static/chunks/1115.434ae2ecb0ad986d.js +0 -149
  644. package/apps/pwa/out/_next/static/chunks/1121.667cec0bcdbb3fdb.js +0 -36
  645. package/apps/pwa/out/_next/static/chunks/1197-54da59d250a6e476.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/1245.1cfd13b26dbd71d6.js +0 -287
  647. package/apps/pwa/out/_next/static/chunks/1494-f93046ff5c5a124d.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/1609.2b312797599b8e45.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/1661.0dd330f3d89f73f3.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/167-0c121e4b47e0f9da.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/1700.cdc2bf8cc685e221.js +0 -90
  652. package/apps/pwa/out/_next/static/chunks/1703-78e46acad29f3cfc.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/1765.679b29625c8e88d4.js +0 -77
  654. package/apps/pwa/out/_next/static/chunks/1971-7efb628c471dc5a0.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/1999-8de7b7bb36801913.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/2073.689dcb2680113d76.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/2198-557d49184104d165.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/221-440ce67fa9f5c839.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/2427-8ed8e98624cbd664.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/2457-725c5827bc003795.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/2491-2718b15a5ccb75a5.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/2527-5c636a43c7cc5dde.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/2692-1027cb16fe4ccf49.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/2773.0e80b9d325fb5635.js +0 -32
  665. package/apps/pwa/out/_next/static/chunks/2873-0f3cb56c8e3528ea.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/3097.864e92bdaa2f4d15.js +0 -79
  667. package/apps/pwa/out/_next/static/chunks/3136-d6870ba63300a93e.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/3173-0289113d434e83b7.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/325-dd9208a1a0ab7ce4.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/3283.528f430dd043fb4e.js +0 -74
  671. package/apps/pwa/out/_next/static/chunks/3295.cc8cb13b8f0dae1a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/3688-86e3b88abf18cb3b.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/3804-7220467a5473a8df.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/3808.3e1e247ce7bdf889.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/3927.b5473ad109da44c5.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/3934-98ea94832e194796.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/4156.ba4de4a3664f04b4.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/4297-239ca82f293faab0.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4320-dcc5a7734126f4c9.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/4434.94b4c552a2d91e69.js +0 -148
  681. package/apps/pwa/out/_next/static/chunks/4579.03e4092f73950965.js +0 -226
  682. package/apps/pwa/out/_next/static/chunks/4667.97e31aa38c95c475.js +0 -309
  683. package/apps/pwa/out/_next/static/chunks/4702.4a4adc1f16d7c93b.js +0 -64
  684. package/apps/pwa/out/_next/static/chunks/4815.481501c57b3568d9.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/487-d16e698ef14662d9.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/4888-7a38bf522c9cc6fe.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/5034-30e429d6bb086881.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/5040-35c494e60dadd97d.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/50c6ab1e.81a96e419350909d.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/5154.4b6a836179356f30.js +0 -94
  691. package/apps/pwa/out/_next/static/chunks/5228-a8200df486278f2d.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/5379.97af106d09566f69.js +0 -8
  693. package/apps/pwa/out/_next/static/chunks/5479-b6372e762719f92f.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/5534-699c5cbcbc96c5d7.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/5701.9c4e8f250312eeee.js +0 -24
  696. package/apps/pwa/out/_next/static/chunks/5892.2526d962339662d8.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/5937.c2df9e3447e1f667.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/5941.8210cc93c9202c0a.js +0 -286
  699. package/apps/pwa/out/_next/static/chunks/5975.4004f820ae3cecd5.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/6142-7ccd48795d7abd55.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/6160.bf9177b8c1bfb243.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/6398.71ba0690c8027555.js +0 -27
  703. package/apps/pwa/out/_next/static/chunks/6492.2bd5c10edc1a064e.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/6552.a3840aa7da35ad68.js +0 -62
  705. package/apps/pwa/out/_next/static/chunks/6736.1e36d3ac5fa5e41d.js +0 -24
  706. package/apps/pwa/out/_next/static/chunks/6900.3ccbe069bdd4556a.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/71327eb4.add50b365f94bf3a.js +0 -122
  708. package/apps/pwa/out/_next/static/chunks/7136.deca3e3a2ddaa374.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/7139-ee9f8ed2677a40b3.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/7191.fdc955f7d96064a4.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/7423-e0aa5d9e2962120e.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/7453.afc1ea7e05d56a8c.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/7503-5e6a3d7fe67e4a0c.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/7761-476fd7bf768abd34.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/7975.eafb12097a0a9e62.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/8050-9b364bdef8f71927.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/8152.64e253c35cccfaae.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/8190.620f0231b3924bcb.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/8448.45b6b1f1a99eeb35.js +0 -104
  720. package/apps/pwa/out/_next/static/chunks/8464-e24f10451b658aac.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/8477.e4c944bb3aa5d2f3.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/8710.ca385257d5ca422e.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/8830.627ccf294ec2465c.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/8880.64c445592f04acaf.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/8981.c706964c8ba27aff.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/9053.bd0fffaff8d3f836.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/9161-c66e723d7ec9d682.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/9185.1ecdf9b65c0bb684.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/9356.fccd5f58086b4ff5.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/9446.dc0406109371d329.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/9506.dcf25d467a42627e.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/9541.eb8e2f8480c7feca.js +0 -93
  733. package/apps/pwa/out/_next/static/chunks/9577.ed7582186efa5482.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/9579.4a8169600fff2058.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/9642-ff2e039eb62e3b92.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/9659-8f2323348113ad80.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/9724.4c5623af2db43153.js +0 -34
  738. package/apps/pwa/out/_next/static/chunks/9869.81a1e24ca682d5a0.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-8d9d76ea322d855c.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed2c4e59f9f1fe21.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-2dc99e03c5d76ca0.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/board/page-b5a3a788330e920f.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/botlab/page-14949db884bfa672.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea76c85b36388a97.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/ceo/page-01716d20af62d325.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/chat/page-62baf6881a64b1e9.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/consult/page-f89ba590c2af8afa.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/control/page-22f8b0f78d9637e5.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/decisions/page-817f9d7e6820be80.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/design-check/page-ffb9bc0d2650249a.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/editor/page-f6d0e64873c0f629.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/exec/page-8bfa0d4ba23a209d.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/field/page-f5060462249e32c7.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/healthz/route-8d9d76ea322d855c.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2049f8b1ef79117.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/intake/page-1446c5fa93907f11.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/layout-b48a7a07c5204156.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/live/page-e974b8c4ca47614c.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/live-run/page-8a919b869bd28594.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/loops/page-d31b8de6bfcd72ed.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/market/page-64765f817909db29.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-d128c8569a36ee9b.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/morning/page-b2679d357e9b9270.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/not-found-6fabec98a9e7b269.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/observatory/page-048f30149dcf1349.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-9113181d6b5a2725.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-1e7a755a13227611.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3c8f8b67a203cf07.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/page-18032f5437215062.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/reflection/page-da3b739192fd0ee3.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d332545571bd6fd1.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/sessions/page-5237aa5b3f3b8ec5.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/settings/page-d16e56c3989c147e.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6b6593600869e2cd.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/setup/layout-8d9d76ea322d855c.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/setup/page-29e8b8a8396b55cb.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/share/page-b3414d856a1a7e2f.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c3affa52b7ce961b.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f21dddf9f95b6fab.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/term/page-f5a30a24745bf088.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/today/page-8c8569a09b4d4e34.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/trace/page-2ce32722c0243483.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/vault/page-4767b0d9c0a98c6c.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-116ee1339c387a75.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/workflows/page-35e8c50ca4ef7ffc.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/workspace/page-52e17113356bb891.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7458ae05ed2ac1a0.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/framework-ad6c9dd524ad6ef8.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/main-app-2ddd1f2b44d6aa59.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/main-e3d82bdc358d20c5.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/pages/_app-71d5aa3896e1655f.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/pages/_error-03ffc54e00438546.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/webpack-56bb89af5a611d0b.js +0 -1
  794. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  795. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +0 -1
  796. /package/apps/pwa/out/_next/static/{GiOLWmt4MqDZePubBjA4Q → Om5xS9jpjSXJCeTNGYEi4}/_ssgManifest.js +0 -0
@@ -6,6 +6,9 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
6
6
  import { getUserConfig } from '../user-config.js';
7
7
  import { debug, redactSecretText } from '../debug/log.js';
8
8
  import { gateRemoteHostCap, realGateRemoteRunner, resolveGateRemoteSettings, runOnRemote, type GateRemoteRunner, type RemoteRunOutcome } from '../self-implement/gate-remote.js';
9
+ import { decideWarmReuse, type WarmReuseEvidenceByConsumer, type WarmReuseSwitchConfig } from '../task-orchestrator/surfaces/pod-warm-switch.js';
10
+ import { buildLandWarmEvidence, type LandShadowSampleWindow } from './pr-land-pod-shadow-job.js';
11
+ import { readWarmReuseEvidence, warmReuseEvidencePath, type WarmReuseEvidenceRow } from '../task-orchestrator/surfaces/warm-reuse-evidence.js';
9
12
 
10
13
  const SHA = /^[0-9a-f]{40}$/i;
11
14
  // This is the stable fallback order when settings.host is unavailable; an explicitly configured allowlisted host
@@ -16,7 +19,7 @@ export type PrLandHeavyHost = typeof PR_LAND_HEAVY_HOSTS[number];
16
19
  const allowedHost = (host: string): host is PrLandHeavyHost => PR_LAND_HEAVY_HOSTS.some((candidate) => candidate === host);
17
20
 
18
21
  export interface HeavyRemoteEvidence {
19
- schema: 2;
22
+ schema: 3;
20
23
  pr: number;
21
24
  head: string;
22
25
  main: string;
@@ -66,6 +69,46 @@ export interface HeavyRemoteDeps {
66
69
  /** Test seam — same cadence as self gate (`dispatchHeavyCheck`): sleep at most 15s while a host stays busy. */
67
70
  sleep?: (ms: number) => void;
68
71
  observe?: (event: string, data: Record<string, unknown>) => void;
72
+ /** WARM-REUSE-LAND-CONSUMER-WIRE — land warm 재사용 config seam(기본은 `getUserConfig().pod?.warmReuse`). */
73
+ warmReuseConfig?: () => WarmReuseSwitchConfig | undefined;
74
+ /** WARM-REUSE-LAND-CONSUMER-WIRE — land shadow Job 결과 창 seam(기본 없음 = 증거 없음 = off). */
75
+ landShadowSamples?: () => LandShadowSampleWindow | undefined;
76
+ /** Durable shadow journal reader seam. */
77
+ readWarmEvidence?: (identity: { consumer: 'land' | 'gate-recheck'; pr: number; head: string; main: string }) => WarmReuseEvidenceRow[] | undefined;
78
+ warmEvidencePath?: () => string;
79
+ }
80
+
81
+ function journalLandShadowSamples(input: HeavyRemoteInput, deps: HeavyRemoteDeps): LandShadowSampleWindow | undefined {
82
+ const read = deps.readWarmEvidence ?? ((identity) => readWarmReuseEvidence(
83
+ (deps.warmEvidencePath ?? warmReuseEvidencePath)(), identity));
84
+ const rows = read({ consumer: 'land', pr: input.pr, head: input.head, main: input.main });
85
+ if (!rows?.length) return undefined;
86
+ const samples = rows.map((row) => ({ head: row.head, main: row.main,
87
+ lock: row.expectedLockHash ?? '', leaseValid: row.leaseValid === true && !!row.leaseId && !!row.workerId
88
+ && row.generation !== undefined && row.expectedLockHash === row.workerLockHash,
89
+ canaryPassed: row.canaryPassed === true, agree: row.agree === true }));
90
+ const latest = rows[rows.length - 1]!;
91
+ const gateRows = read({ consumer: 'gate-recheck', pr: input.pr, head: input.head, main: input.main });
92
+ let gateRecheck: LandShadowSampleWindow['gateRecheck'];
93
+ if (gateRows?.length) {
94
+ let consecutiveMatchSamples = 0;
95
+ for (let i = gateRows.length - 1; i >= 0; i--) {
96
+ const row = gateRows[i]!;
97
+ if (row.workerId !== latest.workerId || row.expectedLockHash !== latest.expectedLockHash
98
+ || row.workerLockHash !== row.expectedLockHash || row.leaseValid !== true
99
+ || !row.leaseId || row.generation === undefined
100
+ || row.canaryPassed !== true || row.agree !== true) break;
101
+ consecutiveMatchSamples++;
102
+ }
103
+ const latestGate = gateRows[gateRows.length - 1]!;
104
+ gateRecheck = { consecutiveMatchSamples, recentMismatchCount: gateRows.filter((row) => row.agree === false).length,
105
+ leaseValid: latestGate.leaseValid === true && !!latestGate.leaseId && !!latestGate.workerId && latestGate.generation !== undefined,
106
+ canaryPassed: latestGate.canaryPassed === true,
107
+ expected: { head: input.head, main: input.main, lock: latestGate.expectedLockHash },
108
+ worker: { head: input.head, main: input.main, lock: latestGate.workerLockHash } };
109
+ }
110
+ const lock = latest.expectedLockHash ?? '';
111
+ return { samples, lock, ...(gateRecheck ? { gateRecheck } : {}) };
69
112
  }
70
113
 
71
114
  function evidencePath(input: HeavyRemoteInput): string {
@@ -77,7 +120,7 @@ function validRootPlan(value: unknown): value is RootPlanSummary | null {
77
120
  if (!value || typeof value !== 'object') return false;
78
121
  const plan = value as Partial<RootPlanSummary>;
79
122
  return (plan.mode === 'affected' || plan.mode === 'full')
80
- && (plan.roots === null || (Number.isSafeInteger(plan.roots) && plan.roots >= 0))
123
+ && (plan.roots === null || (typeof plan.roots === 'number' && Number.isSafeInteger(plan.roots) && plan.roots >= 0))
81
124
  && typeof plan.promoted === 'boolean'
82
125
  && (plan.reason === null || typeof plan.reason === 'string');
83
126
  }
@@ -86,7 +129,7 @@ function matchingEvidence(path: string, input: HeavyRemoteInput): HeavyRemoteEvi
86
129
  if (!existsSync(path)) return null;
87
130
  try {
88
131
  const data: HeavyRemoteEvidence = JSON.parse(readFileSync(path, 'utf8'));
89
- return data.schema === 2 && data.pr === input.pr && data.head === input.head
132
+ return data.schema === 3 && data.pr === input.pr && data.head === input.head
90
133
  && data.main === input.main && allowedHost(data.host) && Number.isFinite(data.elapsedMs)
91
134
  && typeof data.interferenceMeasured === 'boolean' && validRootPlan(data.rootPlan) ? data : null;
92
135
  } catch { return null; }
@@ -209,6 +252,33 @@ export function ensurePrLandHeavyRemote(input: HeavyRemoteInput, deps: HeavyRemo
209
252
  if (!Number.isSafeInteger(input.pr) || input.pr <= 0 || !SHA.test(input.head) || !SHA.test(input.main)) {
210
253
  return { ok: false, source: 'unmeasured', reason: 'invalid-pr-head-or-main', elapsedMs: 0, evidencePath: path };
211
254
  }
255
+ // WARM-REUSE-LAND-CONSUMER-WIRE — 무거운 착지 판정마다 land 소비자 판정을 1줄 남긴다(pod.warm/switch-decision).
256
+ // 판정은 그림자 전용이다: live 여부와 무관하게 원격 게이트는 기존(fresh) 경로를 그대로 간다.
257
+ // 증거는 land shadow Job 결과 창(주입 seam · 기본 없음=증거 없음=off)에서 만들고, 판정 실패는 착지를 깨지 않는다.
258
+ let warmConfig: WarmReuseSwitchConfig | undefined;
259
+ let warmEvidence: WarmReuseEvidenceByConsumer | undefined;
260
+ let warmStage: 'config' | 'evidence' = 'config';
261
+ try {
262
+ warmConfig = deps.warmReuseConfig?.() ?? getUserConfig().pod?.warmReuse;
263
+ } catch (error) {
264
+ debug.log('pod.warm', 'land-shadow-unavailable', {
265
+ pr: input.pr, stage: warmStage,
266
+ reason: `warm-${warmStage}-read-failed`,
267
+ detail: error instanceof Error ? error.message : String(error), execution: 'fresh-gate',
268
+ }, { level: 'warn' });
269
+ }
270
+ try {
271
+ warmStage = 'evidence';
272
+ const samples = deps.landShadowSamples ? deps.landShadowSamples() : journalLandShadowSamples(input, deps);
273
+ warmEvidence = buildLandWarmEvidence(samples, { head: input.head, main: input.main });
274
+ } catch (error) {
275
+ debug.log('pod.warm', 'land-shadow-unavailable', {
276
+ pr: input.pr, stage: warmStage, reason: 'warm-evidence-read-failed',
277
+ detail: error instanceof Error ? error.message : String(error), execution: 'fresh-gate',
278
+ }, { level: 'warn' });
279
+ }
280
+ // Read failures leave config/evidence absent, but every valid landing still emits one fail-closed decision.
281
+ decideWarmReuse('land', warmConfig, warmEvidence);
212
282
  // A cached success is still a landing claim; accept only a measured host in the landing allowlist.
213
283
  const settings = deps.settings ?? resolveGateRemoteSettings(getUserConfig().gateRemote);
214
284
  if (!allowedHost(settings.host)) {
@@ -234,7 +304,7 @@ export function ensurePrLandHeavyRemote(input: HeavyRemoteInput, deps: HeavyRemo
234
304
  // then run typecheck and self gate (changed tests and PWA reach/build) at that exact pair.
235
305
  // The detached integration commit stays on the selected host and never changes the PR branch.
236
306
  argv: (sha) => ['sh', '-c',
237
- 'git -c user.name=elanous-gate -c user.email=gate@localhost -c commit.gpgsign=false merge --no-ff --no-edit "$1" && TSC_BASE_REF="$1" bun run scripts/ci-typecheck-changed.ts --local && bun bin/elanous.mjs self gate --changed --base "$1" --local --shards 4 && bun scripts/pr-land-extra-remote-gates.ts "$1"',
307
+ 'git -c user.name=elanous-gate -c user.email=gate@localhost -c commit.gpgsign=false merge --no-ff --no-edit "$1" && bash scripts/ci-typecheck-main-delta.sh "$1" && bun bin/elanous.mjs self gate --changed --base "$1" --local --shards 4 && bun scripts/pr-land-extra-remote-gates.ts "$1"',
238
308
  'sh', sha(input.main)],
239
309
  }, deps.runner ?? realGateRemoteRunner);
240
310
  } catch (error) {
@@ -277,7 +347,7 @@ export function ensurePrLandHeavyRemote(input: HeavyRemoteInput, deps: HeavyRemo
277
347
  return { ok: false, host: selectedHost, attemptedHost: selectedHost, source: 'unmeasured', reason, elapsedMs, evidencePath: path, ...(failureLogPath ? { failureLogPath } : {}) };
278
348
  }
279
349
  const evidence: HeavyRemoteEvidence = {
280
- schema: 2, pr: input.pr, head: input.head, main: input.main, host: selectedHost,
350
+ schema: 3, pr: input.pr, head: input.head, main: input.main, host: selectedHost,
281
351
  passedAt: new Date().toISOString(), elapsedMs: outcome.ms, rootPlan: rootPlanFromOutput(outcome.stdout),
282
352
  interferenceMeasured: extraGates.interferenceMeasured,
283
353
  };
@@ -14,6 +14,9 @@
14
14
  * ③ 리뷰 — 증거가 가리키는 `review-results/<card>-<pr>-<head접두 10~40>.json`(TA 가 받는 `self review --json` stdout)이
15
15
  * 파일명에서 같은 PR·머리 접두이고 내용에서 전체 PR·머리가 정확히 같으며 `reviewed:true` · `verdict ∈ {pass, warn}` · must-fix 가 «잰 수» 0 인가
16
16
  * (자동 병합 canAuto · TA-LAND-WARN-MUSTFIX0 과 같은 규칙 — must-fix 를 못 셌으면 거부).
17
+ * ③' 공급자(PRLAND-ACP-CLAUDE-ALLOW) — 백엔드가 `acp:claude`(또는 `acp:claude/…`, acp-fallback+`claude`)인 리뷰도
18
+ * ③ 을 만족하고 «같은 머리의 선택된 리뷰» 이면 착지 증거다. 같은 머리의 실패한 금지 리뷰는 후보에서
19
+ * superseded 로 제외되고(supersedes 장부), 유효한 같은-머리 리뷰가 없으면 종전처럼 거부한다(fail-closed).
17
20
  * ⓐ 이미 조상(TC #26019 실측) — 겹친 최근 착지 커밋이 «전부» 고정 머리의 조상이면 그 겹침은 이미 그 머리의 게이트·리뷰에
18
21
  * 반영됐다 ⇒ ①② 없이 ③ 만으로 통과(관측 reason `already-ancestor`). 하나라도 조상이 아니면 ①②③ 전부.
19
22
  * ⓐ' 증거 파일이 없을 때(`verifyAncestorAutoPass`) — 같은 ⓐ 를 표준 자리 `review-results/*-<pr>-<head접두 10~40>.json` 만으로 잰다
@@ -119,6 +122,17 @@ function checkSelectedReviewAttempts(input: VerifyOverlapEvidenceInput, e: Parti
119
122
  let selectedRecord: Record<string, unknown> | undefined;
120
123
  try { selectedRecord = lastReviewRecord(input.readFile(selected)); } catch { return { ok: false, reason: 'review-unreadable' }; }
121
124
  const hasResolvedPrior = hasResolvedPriorDeclaration(selectedRecord);
125
+ if (selectedRecord?.reviewer === 'OP-waiver') {
126
+ const waiver = validOpWaiver(selectedRecord, input.pr, selectedHead);
127
+ if (!waiver.ok) return { ok: false, reason: waiver.reason };
128
+ const linkedSameHeadFailure = candidates.some((path) => {
129
+ if (path === selected || !adjudicatesReviewFile(waiver.adjudicates, path)) return false;
130
+ const failed = checkReview(input, { reviewResult: path }, selectedHead);
131
+ return !failed.ok && /^review-(?:verdict-fail|must-fix-[1-9][0-9]*)$/.test(failed.reason)
132
+ && reviewAttemptHasExactSameHeadFail(input, path, selectedHead);
133
+ });
134
+ if (!linkedSameHeadFailure) return { ok: false, reason: 'review-op-waiver-same-head-failure-missing' };
135
+ }
122
136
  if (entries?.length || hasResolvedPrior) {
123
137
  try { selectedTime = input.reviewMtime(selected); } catch { return { ok: false, reason: 'review-attempt-time-unmeasured' }; }
124
138
  if (!Number.isFinite(selectedTime)) return { ok: false, reason: 'review-attempt-time-unmeasured' };
@@ -196,8 +210,77 @@ function lastReviewRecord(text: string): Record<string, unknown> | undefined {
196
210
  return undefined;
197
211
  }
198
212
 
213
+ const OP_WAIVER_DISPOSITIONS = new Set(['already-fixed', 'out-of-scope-followup', 'reviewer-error']);
214
+
215
+ function canonicalWaiverDisposition(value: unknown): string | undefined {
216
+ if (typeof value !== 'string') return undefined;
217
+ if (OP_WAIVER_DISPOSITIONS.has(value)) return value;
218
+ // These labels occur in OP's saved, approved adjudications; accept only their
219
+ // narrow semantic aliases while new decisions use the canonical vocabulary.
220
+ if (value === 'fixed-in-this-head') return 'already-fixed';
221
+ if (value === 'evidence-provided' || value === 'reviewer-misread-contract') return 'reviewer-error';
222
+ return undefined;
223
+ }
224
+
225
+ function opWaiverTestResult(value: unknown, head: string): boolean {
226
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
227
+ const run = value as Record<string, unknown>;
228
+ if (typeof run.sha !== 'string' || run.sha.toLowerCase() !== head || (run.exit !== undefined && run.exit !== 0)) return false;
229
+ const hasRunDescription = ['command', 'scope', 'rawOutput'].some((key) => typeof run[key] === 'string' && (run[key] as string).trim());
230
+ if (!hasRunDescription) return false;
231
+ let pass = typeof run.pass === 'number' && Number.isSafeInteger(run.pass) ? run.pass : undefined;
232
+ let fail = typeof run.fail === 'number' && Number.isSafeInteger(run.fail) ? run.fail : undefined;
233
+ if ((pass === undefined || fail === undefined) && run.tests && typeof run.tests === 'object' && !Array.isArray(run.tests)) {
234
+ const rows = Object.values(run.tests as Record<string, unknown>);
235
+ const parsed = rows.map((row) => typeof row === 'string' ? /^(\d+)\/(\d+)$/.exec(row) : null);
236
+ if (rows.length > 0 && parsed.every(Boolean)) {
237
+ pass = parsed.reduce((sum, row) => sum + Number(row![1]), 0);
238
+ fail = parsed.reduce((sum, row) => sum + Number(row![2]), 0);
239
+ }
240
+ }
241
+ return pass !== undefined && pass > 0 && fail === 0;
242
+ }
243
+
244
+ function validOpWaiver(record: Record<string, unknown> | undefined, pr: number, head: string):
245
+ | { ok: true; adjudicates: string; findingCount: number }
246
+ | { ok: false; reason: string } {
247
+ if (!record || record.reviewer !== 'OP-waiver') return { ok: false, reason: 'review-op-waiver-reviewer' };
248
+ const waiver = record.waiver;
249
+ if (!waiver || typeof waiver !== 'object' || Array.isArray(waiver)) return { ok: false, reason: 'review-op-waiver-missing' };
250
+ const value = waiver as Record<string, unknown>;
251
+ if (value.by !== 'OP' || typeof value.approvedBy !== 'string' || !value.approvedBy.trim()) {
252
+ return { ok: false, reason: 'review-op-waiver-approval-missing' };
253
+ }
254
+ if (typeof value.adjudicates !== 'string' || !value.adjudicates.trim()) return { ok: false, reason: 'review-op-waiver-adjudication-missing' };
255
+ if (!opWaiverTestResult(value.headTestRun, head)) return { ok: false, reason: 'review-op-waiver-head-test-missing' };
256
+ if (!Array.isArray(value.dispositions) || value.dispositions.length === 0) return { ok: false, reason: 'review-op-waiver-dispositions-missing' };
257
+ const findings = new Set<number>();
258
+ for (const raw of value.dispositions) {
259
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return { ok: false, reason: 'review-op-waiver-disposition-invalid' };
260
+ const item = raw as Record<string, unknown>;
261
+ if (!Number.isSafeInteger(item.finding) || (item.finding as number) < 1 || findings.has(item.finding as number)
262
+ || !canonicalWaiverDisposition(item.disposition)
263
+ || typeof item.evidence !== 'string' || !item.evidence.trim()) return { ok: false, reason: 'review-op-waiver-disposition-invalid' };
264
+ if (canonicalWaiverDisposition(item.disposition) === 'out-of-scope-followup'
265
+ && !/(?:#[1-9]\d*|\b[A-Z][A-Z0-9]+(?:-[A-Z0-9]+)+\b)/.test(item.evidence)) {
266
+ return { ok: false, reason: 'review-op-waiver-followup-missing' };
267
+ }
268
+ findings.add(item.finding as number);
269
+ }
270
+ const ordered = [...findings].sort((a, b) => a - b);
271
+ if (ordered.some((finding, index) => finding !== index + 1)) return { ok: false, reason: 'review-op-waiver-findings-incomplete' };
272
+ const recordPr = typeof record.pr === 'number' ? record.pr : Number(record.pr);
273
+ if (!Number.isSafeInteger(recordPr) || recordPr !== pr) return { ok: false, reason: 'review-op-waiver-pr-mismatch' };
274
+ return { ok: true, adjudicates: value.adjudicates, findingCount: findings.size };
275
+ }
276
+
277
+ function adjudicatesReviewFile(adjudicates: string, path: string): boolean {
278
+ return adjudicates.split(/[\s,;()]+/).includes(basename(path));
279
+ }
280
+
199
281
  function hasResolvedPriorDeclaration(review: Record<string, unknown> | undefined): boolean {
200
282
  if (!review) return false;
283
+ if (review.reviewer === 'OP-waiver' && review.waiver && typeof review.waiver === 'object' && !Array.isArray(review.waiver)) return true;
201
284
  const value = review.resolvedPrior;
202
285
  if (value === true) return true;
203
286
  if (Array.isArray(value) && value.length > 0) return true;
@@ -250,12 +333,18 @@ function reviewAttemptExplicitlyResolved(input: VerifyOverlapEvidenceInput, sele
250
333
  let failed: Record<string, unknown> | undefined;
251
334
  try { failed = lastReviewRecord(input.readFile(failedPath)); } catch { return false; }
252
335
  if (!failed || failed.pr === undefined || String(failed.pr) !== String(input.pr)
253
- || (typeof failed.headCommit === 'string' && failed.headCommit.toLowerCase() !== head)
336
+ || typeof failed.headCommit !== 'string' || failed.headCommit.toLowerCase() !== head
254
337
  || (typeof failed.currentHeadCommit === 'string' && failed.currentHeadCommit.toLowerCase() !== head)) return false;
255
338
  const rawFindings = findingList(failed.mustFix).map((finding) => finding.trim());
256
339
  const findings = rawFindings.map(normalizedFinding);
257
340
  if (findings.length === 0) return false;
258
341
 
342
+ const waiver = validOpWaiver(selected, input.pr, head);
343
+ if (waiver.ok) {
344
+ if (failed.reviewed !== true || failed.verdict !== 'fail' || rawFindings.length === 0) return false;
345
+ return adjudicatesReviewFile(waiver.adjudicates, failedPath) && waiver.findingCount === rawFindings.length;
346
+ }
347
+
259
348
  const declared = selected.resolvedPrior;
260
349
  if (declared !== undefined && declared !== false && containsUnresolvedDeclaration(declared)) return false;
261
350
  const intentBlocks = [selected.intent, selected.intentBlock, selected.reviewIntent, selected.reviewIntentBlock]
@@ -327,6 +416,15 @@ function reviewAttemptExplicitlyResolved(input: VerifyOverlapEvidenceInput, sele
327
416
  return findings.every((finding) => resolvedSet.has(finding));
328
417
  }
329
418
 
419
+ function reviewAttemptHasExactSameHeadFail(input: VerifyOverlapEvidenceInput, failedPath: string, head: string): boolean {
420
+ let failed: Record<string, unknown> | undefined;
421
+ try { failed = lastReviewRecord(input.readFile(failedPath)); } catch { return false; }
422
+ return Boolean(failed && failed.pr !== undefined && String(failed.pr) === String(input.pr)
423
+ && failed.reviewed === true && failed.verdict === 'fail'
424
+ && typeof failed.headCommit === 'string' && failed.headCommit.toLowerCase() === head
425
+ && findingList(failed.mustFix).length > 0);
426
+ }
427
+
330
428
  type Checked = { ok: false; reason: string; baseTip?: string; gateBase?: string; windowCommits?: number }
331
429
  | (OverlapEvidenceVerdict & { ok: true; baseTip?: string });
332
430
 
@@ -358,16 +456,26 @@ function checkReview(input: Pick<VerifyOverlapEvidenceInput, 'pr' | 'readFile'>
358
456
  if (!review.head || review.head.toLowerCase() !== reviewHead) return { ok: false, reason: 'review-head-mismatch', baseTip };
359
457
  // The capture parser projects away model provenance; inspect the same last result-shaped line here.
360
458
  const raw = lastReviewRecord(text);
459
+ let acpClaudeEvidence: { actualBackend: string; model: string; reviewRoute: string } | undefined;
361
460
  if (raw) {
461
+ if (raw.reviewer === 'OP-waiver') {
462
+ const waiver = validOpWaiver(raw, input.pr, head);
463
+ if (!waiver.ok) return { ok: false, reason: waiver.reason, baseTip };
464
+ }
362
465
  const actualBackend = typeof raw.actualBackend === 'string' ? raw.actualBackend.trim().toLowerCase() : '';
363
466
  const model = typeof raw.model === 'string' ? raw.model.trim().toLowerCase() : '';
364
467
  const route = typeof raw.reviewRoute === 'string' ? raw.reviewRoute.trim().toLowerCase() : '';
365
468
  const respondedProvider = typeof raw.respondedProvider === 'string' ? raw.respondedProvider.trim().toLowerCase() : '';
366
469
  const respondedModel = typeof raw.respondedModel === 'string' ? raw.respondedModel.trim().toLowerCase() : '';
470
+ // PRLAND-ACP-CLAUDE-ALLOW — `acp:claude` is no longer refused outright. A review that satisfies
471
+ // the landing contract below (same PR/head, reviewed, pass|warn, counted must-fix 0) is evidence
472
+ // whatever backend produced it; a failed acp:claude attempt is excluded by the same-head
473
+ // supersedes ledger instead of blocking every landing. This note records the provenance only —
474
+ // the contract below still decides, so an invalid or other-head acp:claude review stays rejected.
367
475
  if (actualBackend === 'acp:claude' || actualBackend.startsWith('acp:claude/')
368
476
  || model === 'acp:claude' || model.startsWith('acp:claude/')
369
477
  || ((route === 'acp' || route === 'acp-fallback') && typeof raw.fallbackBackend === 'string' && raw.fallbackBackend.trim().toLowerCase() === 'claude')) {
370
- return { ok: false, reason: 'review-forbidden-acp-claude', baseTip };
478
+ acpClaudeEvidence = { actualBackend, model, reviewRoute: route };
371
479
  }
372
480
  const requested = typeof raw.requestedModel === 'string' ? raw.requestedModel.trim().toLowerCase() : '';
373
481
  if (requested) {
@@ -391,6 +499,9 @@ function checkReview(input: Pick<VerifyOverlapEvidenceInput, 'pr' | 'readFile'>
391
499
  if (review.reviewed !== true) return { ok: false, reason: 'review-not-reviewed', baseTip };
392
500
  if (review.verdict === null || !ACCEPTED_REVIEW_VERDICTS.has(review.verdict)) return { ok: false, reason: `review-verdict-${review.verdict ?? 'null'}`, baseTip };
393
501
  if (review.mustFix !== 0) return { ok: false, reason: review.mustFix === null ? 'review-must-fix-unknown' : `review-must-fix-${review.mustFix}`, baseTip };
502
+ if (acpClaudeEvidence) {
503
+ debug.log('pr.land', 'review-acp-claude-accepted', { pr: input.pr, head, reviewResult: e.reviewResult, ...acpClaudeEvidence });
504
+ }
394
505
  if (carry) {
395
506
  if (!input.cwd || !input.remote || !input.branch) return { ok: false, reason: 'carry-repo-unmeasured', baseTip };
396
507
  const digest = createHash('sha256').update(text).digest('hex');
@@ -3,7 +3,15 @@ import { readFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { runPodCommand, type RunPodCommandOptions, type PodCommandResult } from '../task-orchestrator/surfaces/pod-command-job.js';
5
5
  import { redactSecretText } from '../debug/log.js';
6
+ import { getUserConfig } from '../user-config.js';
6
7
  import type { RootPlanSummary } from './pr-land-heavy-remote.js';
8
+ import type { WarmReuseEvidence, WarmReuseEvidenceByConsumer, WarmReuseSwitchConfig } from '../task-orchestrator/surfaces/pod-warm-switch.js';
9
+ import { requestWarmPodReplay, finalizeWarmPodReplay, quarantineWarmPodReplay } from '../task-orchestrator/surfaces/pod-warm-worker-provider.js';
10
+ import { assessWarmWorkerShadow, type WarmWorkerFileResult } from '../task-orchestrator/surfaces/pod-warm-worker-protocol.js';
11
+ import { writeWarmJobManifest, warmReferenceFromJobArtifacts } from '../../scripts/release-loop/gate-warm-artifacts.js';
12
+ import type { ActualWarmLeaseEvidence } from '../task-orchestrator/surfaces/warm-reuse-evidence.js';
13
+ import { randomUUID } from 'node:crypto';
14
+ import { spawnSync } from 'node:child_process';
7
15
 
8
16
  const SHA = /^[0-9a-f]{40}$/i;
9
17
  const MARKER = 'ELANOUS_PRLAND_SHADOW';
@@ -11,7 +19,7 @@ const MARKER = 'ELANOUS_PRLAND_SHADOW';
11
19
  export const LANDING_POD_SHADOW_HOST_TIMEOUT_MS = 10 * 60_000;
12
20
  export const LANDING_POD_SHADOW_STATUS_UNREADABLE_MS = 60_000;
13
21
 
14
- export interface LandingPodShadowInput { head: string; main: string }
22
+ export interface LandingPodShadowInput { pr?: number; repo?: string; host?: string; head: string; main: string }
15
23
  export interface LandingPodShadowVerdict {
16
24
  measured: boolean;
17
25
  ok: boolean;
@@ -20,9 +28,26 @@ export interface LandingPodShadowVerdict {
20
28
  gateRc?: number;
21
29
  reason?: string;
22
30
  job?: string;
31
+ /** Warm evidence only exists after a real worker lease and exact per-file comparison. */
32
+ warmEvidence?: ActualWarmLeaseEvidence;
33
+ warmReason?: string;
34
+ warmTestFiles?: string[];
23
35
  }
24
36
 
25
- export function landingPodShadowScript(head: string, main: string): string {
37
+ const LAND_TEST_PATH = /^(?:[A-Za-z0-9_-][A-Za-z0-9_.-]*\/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*\.test\.tsx?$/;
38
+ export const LAND_WARM_CANARY_TIMEOUT_MS = 5 * 60_000;
39
+
40
+ /** Changed test files are the bounded canary scope; no test file means no warm evidence. */
41
+ export function changedLandWarmTestFiles(repo: string, head: string, main: string): string[] {
42
+ if (!SHA.test(head) || !SHA.test(main)) return [];
43
+ const result = spawnSync('git', ['-C', repo, 'diff', '--name-only', '--diff-filter=ACMR', `${main}...${head}`], {
44
+ encoding: 'utf8', timeout: 15_000, maxBuffer: 2 * 1024 * 1024,
45
+ });
46
+ if (result.status !== 0) return [];
47
+ return [...new Set(result.stdout.split(/\r?\n/).filter((path) => LAND_TEST_PATH.test(path)))].sort();
48
+ }
49
+
50
+ export function landingPodShadowScript(head: string, main: string, afterGate = ''): string {
26
51
  if (!SHA.test(head) || !SHA.test(main)) throw new Error('pod shadow: invalid head/main');
27
52
  return [
28
53
  'set -u',
@@ -38,17 +63,117 @@ export function landingPodShadowScript(head: string, main: string): string {
38
63
  `printf '${MARKER}_TSC_PLAN %s\\n' "$(grep '^\\[tsc-gate\\] root-plan ' /tmp/prland-shadow-tsc.log | tail -n 1 | sed 's/^\\[tsc-gate\\] root-plan //')"`,
39
64
  "tail -n 8 /tmp/prland-shadow-tsc.log; tail -n 8 /tmp/prland-shadow-gate.log",
40
65
  `printf '${MARKER} head=%s main=%s tsc=%s gate=%s\\n' '${head}' '${main}' "$tsc_rc" "$gate_rc"`,
66
+ ...(afterGate ? [afterGate] : []),
41
67
  'exit 0',
42
68
  ].join('\n');
43
69
  }
44
70
 
71
+ function landWarmColdTestScript(files: readonly string[], head: string, attemptId: string): string {
72
+ if (files.some((file) => !LAND_TEST_PATH.test(file)) || !SHA.test(head) || !/^[0-9a-f-]{36}$/i.test(attemptId))
73
+ throw new Error('pod shadow: invalid warm test scope');
74
+ return files.map((file, index) => {
75
+ const prefix = `"$HOME/outbox/pr-land-warm/${index}"`;
76
+ const quotedFile = `'${file}'`;
77
+ return [
78
+ `mkdir -p "$HOME/outbox/pr-land-warm"`,
79
+ `bun test --reporter=junit --reporter-outfile=${prefix}.junit.xml ${quotedFile} >${prefix}.log 2>&1`,
80
+ 'test_rc=$?',
81
+ `printf '%s' "$test_rc" >${prefix}.rc`,
82
+ `printf '{"commit":"${head}","attemptId":"${attemptId}","files":["${file}"],"rc":%s,"jobFailed":false,"jobExitCode":0}\n' "$test_rc" >${prefix}.json`,
83
+ `printf '[warm-worker] file=%s\\n[warm-worker] cut=%s attempt=%s\\n' '${file}' '${head}' '${attemptId}' >${prefix}.log.stamped`,
84
+ `cat ${prefix}.log >>${prefix}.log.stamped`,
85
+ `printf '\\n[warm-worker] junit-sha256=%s\\n' "$(sha256sum ${prefix}.junit.xml 2>/dev/null | cut -d' ' -f1)" >>${prefix}.log.stamped`,
86
+ `mv ${prefix}.log.stamped ${prefix}.log`,
87
+ ].join('\n');
88
+ }).join('\n');
89
+ }
90
+
91
+ async function runWarmLandCanary(input: {
92
+ pr: number; head: string; main: string; host: string; repo: string;
93
+ job: PodCommandResult; files: readonly string[]; attemptId: string; coldGatePassed: boolean;
94
+ timeoutMs?: number;
95
+ readReference?: typeof warmReferenceFromJobArtifacts;
96
+ requestWarm?: typeof requestWarmPodReplay;
97
+ finalizeWarm?: typeof finalizeWarmPodReplay;
98
+ quarantineWarm?: typeof quarantineWarmPodReplay;
99
+ warmConfig?: () => WarmReuseSwitchConfig | undefined;
100
+ }): Promise<{ warmEvidence?: ActualWarmLeaseEvidence; reason: string }> {
101
+ let config: WarmReuseSwitchConfig | undefined;
102
+ try { config = input.warmConfig ? input.warmConfig() : getUserConfig().pod?.warmReuse; }
103
+ catch { return { reason: 'warm-config-unavailable' }; }
104
+ if (input.host !== 'node-b') return { reason: 'canary-host-mismatch' };
105
+ if (config?.land !== true) return { reason: 'land-canary-flag-off' };
106
+ if (!input.files.length) return { reason: 'changed-test-files-unmeasured' };
107
+ const coldFiles = input.files.map((file, index) => {
108
+ const prefix = join(input.job.artifactsDir, 'outbox', 'pr-land-warm', String(index));
109
+ const writeManifest = writeWarmJobManifest(prefix, file, input.head, input.attemptId);
110
+ return writeManifest ? (input.readReference ?? warmReferenceFromJobArtifacts)(prefix, file,
111
+ { cutSha: input.head, attemptId: input.attemptId }) : null;
112
+ });
113
+ if (coldFiles.some((row) => row === null)) return { reason: 'cold-reference-unmeasured' };
114
+ const requestWarm = input.requestWarm ?? requestWarmPodReplay;
115
+ let replay;
116
+ const timeoutMs = input.timeoutMs ?? LAND_WARM_CANARY_TIMEOUT_MS;
117
+ const request = requestWarm({ protocol: 1, runId: `land-${input.pr}-${input.head.slice(0, 8)}`,
118
+ attemptId: input.attemptId, cutSha: input.head, baselineSha: input.main,
119
+ deadlineAt: Date.now() + timeoutMs, files: [...input.files], envProfile: 'gate-v1' });
120
+ const timedOut = Symbol('warm-canary-timeout');
121
+ let timer: ReturnType<typeof setTimeout> | undefined;
122
+ try {
123
+ const raced = await Promise.race([request, new Promise<typeof timedOut>((resolve) => {
124
+ timer = setTimeout(() => resolve(timedOut), timeoutMs);
125
+ })]);
126
+ if (raced === timedOut) {
127
+ // The provider API has no AbortSignal yet. Fence any late lease as soon as it arrives.
128
+ void request.then(async (late) => {
129
+ if (late.command) await (input.quarantineWarm ?? quarantineWarmPodReplay)(late.command, 'land-shadow-late-after-timeout');
130
+ }).catch(() => {});
131
+ return { reason: 'warm-request-timeout' };
132
+ }
133
+ replay = raced;
134
+ } catch (error) { return { reason: `warm-request-failed:${error instanceof Error ? error.name : 'unknown'}` }; }
135
+ finally { if (timer) clearTimeout(timer); }
136
+ const command = replay.command;
137
+ if (!command) return { reason: replay.transport.reason ?? 'warm-lease-unmeasured' };
138
+ const decision = assessWarmWorkerShadow(command, coldFiles as WarmWorkerFileResult[], replay.transport.reply);
139
+ const matched = decision.reason === 'match';
140
+ let leaseValid = replay.transport.status === 'observed' && replay.transport.reason === 'complete';
141
+ try {
142
+ if (matched) await (input.finalizeWarm ?? finalizeWarmPodReplay)(command);
143
+ else { leaseValid = false; await (input.quarantineWarm ?? quarantineWarmPodReplay)(command, `land-shadow-${decision.reason}`); }
144
+ } catch { leaseValid = false; }
145
+ // The reply is the worker-side observation. Falling back to the host's requested key
146
+ // would turn a missing worker identity into a false positive comparison.
147
+ const workerLockHash = replay.transport.reply?.key?.lockHash;
148
+ if (!command.leaseId || !Number.isSafeInteger(command.generation) || command.generation < 1
149
+ || !command.key.lockHash || !workerLockHash) return { reason: 'warm-lease-identity-unmeasured' };
150
+ return { reason: decision.reason, warmEvidence: {
151
+ workerId: command.workerId,
152
+ leaseId: command.leaseId, generation: command.generation,
153
+ expectedLockHash: command.key.lockHash, workerLockHash,
154
+ leaseValid, canaryPassed: matched && leaseValid && input.coldGatePassed, agree: matched,
155
+ } };
156
+ }
157
+
45
158
  export async function runLandingPodShadowJob(input: LandingPodShadowInput, deps: {
46
159
  runPod?: (options: RunPodCommandOptions) => Promise<PodCommandResult>;
47
160
  readLog?: (path: string) => string;
48
161
  /** Deterministic timer seam for the host deadline. */
49
162
  armTimeout?: (onTimeout: () => void, ms: number) => () => void;
163
+ testFiles?: readonly string[];
164
+ warmReplay?: typeof requestWarmPodReplay;
165
+ finalizeWarm?: typeof finalizeWarmPodReplay;
166
+ quarantineWarm?: typeof quarantineWarmPodReplay;
167
+ readReference?: typeof warmReferenceFromJobArtifacts;
168
+ warmConfig?: () => WarmReuseSwitchConfig | undefined;
169
+ warmTimeoutMs?: number;
50
170
  } = {}): Promise<LandingPodShadowVerdict> {
51
- const script = landingPodShadowScript(input.head, input.main);
171
+ let warmConfig: WarmReuseSwitchConfig | undefined;
172
+ try { warmConfig = deps.warmConfig ? deps.warmConfig() : getUserConfig().pod?.warmReuse; } catch { /* no warm launch without readable config */ }
173
+ const canaryEnabled = input.host === 'node-b' && warmConfig?.land === true;
174
+ const files = canaryEnabled ? deps.testFiles ?? (input.repo ? changedLandWarmTestFiles(input.repo, input.head, input.main) : []) : [];
175
+ const attemptId = randomUUID();
176
+ const script = landingPodShadowScript(input.head, input.main, landWarmColdTestScript(files, input.head, attemptId));
52
177
  const controller = new AbortController();
53
178
  const armTimeout = deps.armTimeout ?? ((onTimeout: () => void, ms: number) => {
54
179
  const timer = setTimeout(onTimeout, ms);
@@ -105,5 +230,78 @@ export async function runLandingPodShadowJob(input: LandingPodShadowInput, deps:
105
230
  if (!rootPlan) return { measured: false, ok: false, rootPlan: null, reason: 'root-plan-missing', job: job.job };
106
231
  const tscRc = Number(match[1]);
107
232
  const gateRc = Number(match[2]);
108
- return { measured: true, ok: tscRc === 0 && gateRc === 0, rootPlan, tscRc, gateRc, job: job.job };
233
+ const verdict: LandingPodShadowVerdict = { measured: true, ok: tscRc === 0 && gateRc === 0, rootPlan, tscRc, gateRc, job: job.job,
234
+ ...(files.length ? { warmTestFiles: [...files] } : {}) };
235
+ if (input.pr && input.repo && input.host) {
236
+ const warm = await runWarmLandCanary({ pr: input.pr, head: input.head, main: input.main, host: input.host,
237
+ repo: input.repo, job, files, attemptId, coldGatePassed: verdict.ok,
238
+ ...(deps.warmTimeoutMs !== undefined ? { timeoutMs: deps.warmTimeoutMs } : {}),
239
+ ...(deps.readReference ? { readReference: deps.readReference } : {}),
240
+ ...(deps.warmReplay ? { requestWarm: deps.warmReplay } : {}),
241
+ ...(deps.finalizeWarm ? { finalizeWarm: deps.finalizeWarm } : {}),
242
+ ...(deps.quarantineWarm ? { quarantineWarm: deps.quarantineWarm } : {}),
243
+ warmConfig: () => warmConfig });
244
+ verdict.warmReason = warm.reason;
245
+ if (warm.warmEvidence) verdict.warmEvidence = warm.warmEvidence;
246
+ }
247
+ return verdict;
248
+ }
249
+
250
+ /** WARM-REUSE-LAND-CONSUMER-WIRE — land shadow Job 결과 표본(착지쌍·lock·lease·카나리아·그림자 일치). */
251
+ export interface LandingShadowSample {
252
+ /** shadow Job 이 잰 착지쌍 — 원격 게이트가 잰 head/main 와 정확히 같아야 표본으로 센다. */
253
+ head: string;
254
+ main: string;
255
+ /** shadow Job 이 돈 Pod generation lock — 원값 그대로 대조한다. */
256
+ lock: string;
257
+ /** shadow Job 이 lease 를 잡고 끝까지 쟀나. */
258
+ leaseValid: boolean;
259
+ /** shadow Job 카나리아(착지 tsc+gate) 통과. */
260
+ canaryPassed: boolean;
261
+ /** 같은 착지의 fresh(원격 게이트) 판정과 그림자 비교 일치 — 불일치 표본은 최근 mismatch 로 센다. */
262
+ agree: boolean;
263
+ }
264
+
265
+ /** land 소비자 판정 증거 입력 — 최근 창 표본 ⊕ 이번 착지가 기대하는 warm 워커 lock ⊕ 선행 소비자 증거. */
266
+ export interface LandShadowSampleWindow {
267
+ /** 최근 창 — 마지막 원소가 가장 최근 shadow 결과다. */
268
+ samples: LandingShadowSample[];
269
+ /** 이번 착지가 기대하는 warm 워커 lock(현재 Pod generation). */
270
+ lock: string;
271
+ /** 선행 소비자(gate-recheck)의 자기 증거 — land 는 이 칸이 live 여야 live 가 될 수 있다(비면 off). */
272
+ gateRecheck?: WarmReuseEvidence;
273
+ }
274
+
275
+ /**
276
+ * WARM-REUSE-LAND-CONSUMER-WIRE — land shadow Job 결과에서 소비자('land') 판정 증거를 만든다.
277
+ * 판정 본체는 pod-warm-switch.ts `decideWarmReuse` — 이 모듈은 증거의 산지만 담당한다.
278
+ * 창이 없거나 비면 land 증거 칸이 비어 off 다 — 못 잰 증거는 통과가 아니다.
279
+ * 원값은 고쳐 읽지 않고 정확히 비교한다(신원 형식 어긋남은 pod-warm-switch 판정이 끊는다).
280
+ */
281
+ export function buildLandWarmEvidence(
282
+ window: LandShadowSampleWindow | undefined,
283
+ expected: { head: string; main: string },
284
+ ): WarmReuseEvidenceByConsumer {
285
+ const evidence: WarmReuseEvidenceByConsumer = window?.gateRecheck ? { 'gate-recheck': window.gateRecheck } : {};
286
+ if (!window || window.samples.length === 0) return evidence;
287
+ const latest = window.samples[window.samples.length - 1]!;
288
+ let consecutiveMatchSamples = 0;
289
+ for (let index = window.samples.length - 1; index >= 0; index--) {
290
+ const sample = window.samples[index]!;
291
+ if (sample.head !== expected.head || sample.main !== expected.main || sample.lock !== window.lock
292
+ || sample.leaseValid !== true || sample.canaryPassed !== true || sample.agree !== true) break;
293
+ consecutiveMatchSamples++;
294
+ }
295
+ const recentMismatchCount = window.samples.filter((sample) => sample.agree === false).length;
296
+ return {
297
+ ...evidence,
298
+ land: {
299
+ consecutiveMatchSamples,
300
+ recentMismatchCount,
301
+ leaseValid: latest.leaseValid,
302
+ canaryPassed: latest.canaryPassed,
303
+ expected: { head: expected.head, main: expected.main, lock: window.lock },
304
+ worker: { head: latest.head, main: latest.main, lock: latest.lock },
305
+ },
306
+ };
109
307
  }
@@ -15,6 +15,8 @@ export interface HeavyOnPodShadowInput<T> {
15
15
  runPod: () => T | Promise<T>;
16
16
  log: (category: string, event: string, data: Record<string, unknown>) => void;
17
17
  warn: (message: string) => void;
18
+ /** Evidence persistence is best effort; it must never change the cold landing verdict. */
19
+ onShadow?: (observation: { pod: unknown; agree: boolean }) => void;
18
20
  }
19
21
 
20
22
  function agree(local: unknown, pod: unknown): boolean {
@@ -38,22 +40,25 @@ function elapsedMs(started: number): number {
38
40
  }
39
41
 
40
42
  export async function runHeavyOnPodShadow<T>(input: HeavyOnPodShadowInput<T>): Promise<T> {
41
- const { enabled, pr, head, local, runPod, log, warn } = input;
43
+ const { enabled, pr, head, local, runPod, log, warn, onShadow } = input;
42
44
  if (!enabled) return local;
43
45
 
44
46
  const localMs = 0;
45
47
  const started = performance.now();
46
48
  try {
47
49
  const pod = await runPod();
50
+ const agrees = agree(local, pod);
48
51
  log('pr.land', 'heavy-on-pod-shadow', {
49
52
  pr,
50
53
  head,
51
54
  local,
52
55
  pod,
53
- agree: agree(local, pod),
56
+ agree: agrees,
54
57
  podMs: elapsedMs(started),
55
58
  localMs,
56
59
  });
60
+ try { onShadow?.({ pod, agree: agrees }); }
61
+ catch (error) { warn(`shadow evidence write failed: ${error instanceof Error ? error.message : String(error)}`); }
57
62
  } catch (error) {
58
63
  warn(error instanceof Error ? error.message : String(error));
59
64
  log('pr.land', 'heavy-on-pod-shadow', {
@@ -62,6 +67,8 @@ export async function runHeavyOnPodShadow<T>(input: HeavyOnPodShadowInput<T>): P
62
67
  agree: false,
63
68
  podMs: elapsedMs(started), localMs,
64
69
  });
70
+ try { onShadow?.({ pod: { measured: false, ok: false, reason: `pod-exception:${error instanceof Error ? error.name : 'unknown'}` }, agree: false }); }
71
+ catch (writeError) { warn(`shadow evidence write failed: ${writeError instanceof Error ? writeError.message : String(writeError)}`); }
65
72
  }
66
73
  return local;
67
74
  }