elanous 0.2.38 → 0.2.40

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 (615) 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/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{7954.4f7a8832663ee979.js → 1060.014f1f01a17aec26.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 1281.d81877e35b9068f4.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{2104.70e086d5174a4736.js → 1350.59f40e39e02d91b1.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1452.162bb2d9d699e82a.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +286 -0
  10. package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +149 -0
  12. package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +90 -0
  14. package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +104 -0
  15. package/apps/pwa/out/_next/static/chunks/2047.8f23e210995d4548.js +2 -0
  16. package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.js → 2066.a77257c8c350770a.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{8019.21ca554a821dad01.js → 2177.df8547f9d7215c4e.js} +3 -3
  20. package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.js → 2226.2cf61ec781827219.js} +2 -2
  22. package/apps/pwa/out/_next/static/chunks/2281-b8cede695c6c650e.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6493.27ad77de7aac7966.js → 2499.02fbfd18126c10c0.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/{7628.6b16863ac3972333.js → 2522.f2766b76d22c8bdf.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/{9299.24e2a7d9b6d1f91b.js → 261.0d471e8aded799f3.js} +3 -3
  27. package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +27 -0
  30. package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2774-719820e3f5b2a3eb.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/2829-734fe8bf2eee7347.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{7524.ce973525d30b3d52.js → 3330.7443183b7e6fdbdf.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/{3124-561f7f037943cde2.js → 3746-f80a78f220bf37b5.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +24 -0
  45. package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +77 -0
  46. package/apps/pwa/out/_next/static/chunks/{bb6987f9.3647e1a23b0e3217.js → 3b355b3d.6f73c98bf6f9c749.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +36 -0
  48. package/apps/pwa/out/_next/static/chunks/{8994d93e.33ba491f95345fc2.js → 409c787b.e48c5bec8ec10456.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/{5041-5aada92ca215ffdd.js → 413-24c8284bda08241d.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +287 -0
  52. package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4351.0f37a6db2b34d50b.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{5638.107314dc479e2f37.js → 470.51a72a2348306455.js} +2 -2
  56. package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/{8487.291666583bebe640.js → 4769.9fd582071301f382.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/{8509.3a54d4e61893d7cb.js → 483.725e4a61be922788.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.js → 4864a2ca.1c1c280a7772c5e5.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +74 -0
  63. package/apps/pwa/out/_next/static/chunks/{8879.ac06755bcf3e44a1.js → 5383.bdfa5d886e39a826.js} +1 -1
  64. package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 5436.fdf6fa8ae3e9588d.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5622.94893f5aea7185d0.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +8 -0
  70. package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +62 -0
  72. package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +94 -0
  76. package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/{7161-8f22db3ec5ed005e.js → 6051-0ae955eedb10adb9.js} +3 -3
  78. package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/{3291.f6c1005387d514bd.js → 6257.c0037b8949239f5e.js} +2 -2
  80. package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6624.981ef7caeb680560.js +32 -0
  85. package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/{5203.51e5d8b5f1dcfe53.js → 6749.0744ce6eb08d40e9.js} +3 -3
  87. package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/{1938.0e6c60ee91c4d7f5.js → 6908.06008c67f6380ea9.js} +2 -2
  90. package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{de8b930d.d94c0f42acf807fc.js → 6cc1d1d6.9a98dd4622f1afc6.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +93 -0
  96. package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7515.1ad6efe157fa4448.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +24 -0
  100. package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8086.1ab9103c41be884f.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/{1026-44010f405704050c.js → 8272-025653884f9645d2.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.js → 8357.1aaa713b052a78b1.js} +4 -4
  110. package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{4199-f7c6eb40cd0322f8.js → 8639-92c11d069792429e.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9069.657590a84afb8fac.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9175.2de5209a5ce6f68a.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.js → 9189505a.980427ac048c8c60.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9992.07ce73c10bd5e6a1.js +79 -0
  123. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-866aac5ff226a7f3.js → page-ba957ff875a026a0.js} +1 -1
  128. package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live/page-4edb8df90f4537ce.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/morning/page-fca2e59a81744d9e.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/term/page-139d722de1dcd6c1.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workspace/page-ccde99f07aaf71f7.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → b84cad00.594027ebe0531fe2.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → ca3702f8.2913182e73889fa2.js} +7 -7
  177. package/apps/pwa/out/_next/static/chunks/{3f0de3de-2340c532c00395db.js → d5d3cefc-373c4eb722ed848b.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/{framework-4b12a946f352cee2.js → framework-002b472a66935d31.js} +1 -1
  180. package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +22 -22
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +22 -22
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +22 -22
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +21 -21
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +21 -21
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +22 -22
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +21 -21
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +22 -22
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +22 -22
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +21 -21
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +22 -22
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +22 -22
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +22 -22
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +22 -22
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +21 -21
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +21 -21
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +22 -22
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +22 -22
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +22 -22
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +21 -21
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +21 -21
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +22 -22
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +22 -22
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +21 -21
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +21 -21
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +21 -21
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +22 -22
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +22 -22
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +21 -21
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +22 -22
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +22 -22
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +22 -22
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +22 -22
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +22 -22
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +21 -21
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +22 -22
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +22 -22
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +22 -22
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +22 -22
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +22 -22
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +22 -22
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +22 -22
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +22 -22
  278. package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
  279. package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
  280. package/graphs/demo/persona-marketer/recipes.yaml +19 -0
  281. package/graphs/video/explainer-line.yaml +4 -1
  282. package/package.json +1 -1
  283. package/scripts/dead-code/report.ts +169 -0
  284. package/scripts/lib/morning-report-options.ts +3 -4
  285. package/scripts/lib/tui-regress-evidence.ts +56 -0
  286. package/scripts/morning-report.ts +5 -1
  287. package/scripts/public-export.ts +15 -7
  288. package/scripts/release-loop/export-check-node.ts +21 -3
  289. package/scripts/release-loop/gate-node.ts +379 -48
  290. package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
  291. package/scripts/release-loop/gate-shard-receipts.ts +89 -0
  292. package/scripts/release-loop/gate-wall.ts +5 -5
  293. package/scripts/release-loop/preflight.ts +6 -2
  294. package/scripts/release-loop/resume-release.ts +20 -5
  295. package/scripts/release-loop/resume.ts +48 -0
  296. package/scripts/release-loop/version-node.ts +7 -2
  297. package/scripts/release-story/draft.ts +1 -1
  298. package/scripts/research-bench/README.md +53 -0
  299. package/scripts/research-bench/questions.json +66 -0
  300. package/scripts/research-bench/rubric.md +33 -0
  301. package/scripts/research-bench/run.ts +523 -0
  302. package/scripts/tui-regress.ts +85 -10
  303. package/src/acp/core-turn-bridge.ts +8 -0
  304. package/src/agent/autonomous-tools.ts +10 -3
  305. package/src/agent/monad-agent-turn.ts +4 -1
  306. package/src/agent/registry.ts +26 -2
  307. package/src/agent/shared-app-tools.ts +1 -1
  308. package/src/agent/surface-ux/build.ts +12 -3
  309. package/src/agent/surface-ux/types.ts +1 -1
  310. package/src/agent/task-notification.ts +75 -6
  311. package/src/agent/types.ts +3 -0
  312. package/src/agent-mission/driver.ts +29 -3
  313. package/src/agent-mission/mission-cli.ts +2 -1
  314. package/src/agent-substrate/review-context-pack.ts +365 -0
  315. package/src/agent-substrate/self-review-cli.ts +226 -17
  316. package/src/ask-user-question/index.ts +6 -0
  317. package/src/ask-user-question/inline-resolver.ts +49 -0
  318. package/src/auto-research/question-ladder-contract.ts +22 -3
  319. package/src/auto-research/research-turn.ts +350 -17
  320. package/src/autopilot/agent-loop.ts +1 -1
  321. package/src/autopilot/pty-control-loop.ts +8 -1
  322. package/src/boot/daemon-tools/index.ts +4 -3
  323. package/src/boot/daemon-tools/self-implement.ts +270 -2
  324. package/src/boot/daemon-tools/types.ts +2 -0
  325. package/src/budget/llm-cost.ts +44 -5
  326. package/src/budget/unified-usage.ts +17 -1
  327. package/src/capture/tui-self-report.ts +14 -0
  328. package/src/chat/index.ts +33 -7
  329. package/src/cli/agent-cli.ts +43 -8
  330. package/src/cli/intake-cli.ts +22 -1
  331. package/src/cli/lesson-cli.ts +19 -3
  332. package/src/cli/log-event-names.ts +1 -0
  333. package/src/cli/pod-cli.ts +17 -2
  334. package/src/cli/pty-takeover-cli.ts +67 -7
  335. package/src/cli/release-cli.ts +52 -6
  336. package/src/cli/repo-cli.ts +2 -1
  337. package/src/cli/tasks-cli.ts +36 -9
  338. package/src/control-plane/ledger.ts +21 -4
  339. package/src/core-turn/run-core-turn.ts +44 -3
  340. package/src/core-turn/run-goal-loop.ts +152 -8
  341. package/src/core-turn/types.ts +9 -0
  342. package/src/dashboard/chat/acp-chat.ts +2 -2
  343. package/src/dashboard/classic-sigquit.ts +16 -0
  344. package/src/dashboard/index.ts +321 -27
  345. package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
  346. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
  347. package/src/dashboard/input/chat-main-slash-command.ts +7 -0
  348. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  349. package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
  350. package/src/dashboard/input/external-input-host.ts +2 -0
  351. package/src/dashboard/sidetab-runtime.ts +228 -0
  352. package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
  353. package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
  354. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
  355. package/src/dashboard/term-slash-runtime.ts +16 -18
  356. package/src/dashboard/turn-preamble.ts +2 -0
  357. package/src/domains/knowledge.ts +1 -1
  358. package/src/esc-abort-gate.ts +33 -1
  359. package/src/execution-loop/launch-gate.ts +206 -1
  360. package/src/graph-runner/graph-cli.ts +6 -4
  361. package/src/graph-runner/runner.ts +31 -9
  362. package/src/graph-wizard/generate.ts +16 -7
  363. package/src/graph-wizard/mission-compose.ts +201 -0
  364. package/src/grok/agent-search.ts +8 -2
  365. package/src/grok/credential.ts +5 -0
  366. package/src/grounding/ref-index.ts +11 -0
  367. package/src/grounding/ref-vector.ts +61 -0
  368. package/src/grounding/sources-cli.ts +2 -2
  369. package/src/grounding/sources.ts +15 -1
  370. package/src/harness/harness-cli-command.ts +38 -9
  371. package/src/harness/harness-pod-dispatch.ts +7 -1
  372. package/src/index.ts +18 -4
  373. package/src/input/external-input-queue.ts +10 -0
  374. package/src/intake-plane/collect-telegram-saved.ts +36 -1
  375. package/src/intake-plane/intake-to-tasks.ts +246 -3
  376. package/src/lessons/friction-ledger.ts +154 -0
  377. package/src/live-supply/collector.ts +149 -0
  378. package/src/live-supply/probes.ts +52 -0
  379. package/src/live-supply/snapshot.ts +40 -0
  380. package/src/llm.ts +431 -76
  381. package/src/loops/orchestrator/tick.ts +8 -0
  382. package/src/nexus/api/harness-api.ts +2 -1
  383. package/src/pty/snapshot.py +132 -0
  384. package/src/pty-shell/pty-control-ipc.ts +29 -2
  385. package/src/pty-shell/pty-manifest.ts +59 -3
  386. package/src/pty-shell/registry.ts +2 -0
  387. package/src/pty-shell/tui-run-state.ts +80 -3
  388. package/src/release-loop/gate-host-reservation.ts +13 -4
  389. package/src/release-loop/gate-shard-ledger.ts +68 -0
  390. package/src/release-loop/merged-pr-checklist.ts +25 -2
  391. package/src/release-loop/rehearsal-shard-plan.ts +6 -1
  392. package/src/release-loop/rehearsal.ts +27 -0
  393. package/src/research/edge-decision.ts +124 -15
  394. package/src/research/gap-followup.ts +249 -0
  395. package/src/research/lenses/counter-evidence.ts +100 -0
  396. package/src/research/lenses/working-backwards.ts +89 -0
  397. package/src/research/plugin-discovery.ts +242 -0
  398. package/src/research-bridge/invoke.ts +4 -2
  399. package/src/research-bridge/types.ts +2 -0
  400. package/src/self-dev/ask-launch-flow.ts +34 -106
  401. package/src/self-dev/dev-cli.ts +2 -0
  402. package/src/self-dev/dev-pipeline.ts +8 -4
  403. package/src/self-dev/graph-journey-route.ts +10 -2
  404. package/src/self-dev/launch-preflight-text.ts +2 -2
  405. package/src/self-dev/launch-preflight.ts +38 -7
  406. package/src/self-dev/orchestrate-cli.ts +1 -0
  407. package/src/self-dev/run-supervisor.ts +19 -0
  408. package/src/self-implement/device-first.ts +8 -2
  409. package/src/self-implement/doctor-visit.ts +76 -58
  410. package/src/self-implement/gate-artifacts.ts +3 -0
  411. package/src/self-implement/gate-baseline.ts +75 -4
  412. package/src/self-implement/gate-cli.ts +317 -9
  413. package/src/self-implement/gate-receipt-registry.ts +180 -0
  414. package/src/self-implement/gate-remote.ts +145 -22
  415. package/src/self-implement/goal-author-clarification.ts +178 -24
  416. package/src/self-implement/goal-author-decompose.ts +24 -15
  417. package/src/self-implement/goal-author.ts +9 -5
  418. package/src/self-implement/host-regate.ts +120 -45
  419. package/src/self-implement/impl-findings-feedback.ts +188 -0
  420. package/src/self-implement/knowhow-pack.ts +189 -10
  421. package/src/self-implement/off-diff-evidence.ts +124 -0
  422. package/src/self-implement/orchestrator.ts +85 -7
  423. package/src/self-implement/run-ledger.ts +46 -8
  424. package/src/self-implement/run-stop.ts +12 -0
  425. package/src/self-implement/seams.ts +6 -3
  426. package/src/self-implement/self-implement-cli.ts +4 -2
  427. package/src/session/chat.ts +89 -15
  428. package/src/session-runtime/provider-circuit.ts +140 -0
  429. package/src/shell-runner/file-engine.ts +1 -0
  430. package/src/shell-runner/types.ts +4 -0
  431. package/src/sidetab-core/model.ts +176 -0
  432. package/src/skills/tools/schedule-wakeup.ts +23 -1
  433. package/src/skills/tools/shell.ts +51 -5
  434. package/src/steward/directive-audit.ts +354 -0
  435. package/src/surface/child-process.ts +31 -0
  436. package/src/surface/tui-stderr-owner.ts +48 -0
  437. package/src/task-agent/cover.ts +30 -12
  438. package/src/task-agent/judge.ts +56 -0
  439. package/src/task-agent/postland-card.ts +35 -2
  440. package/src/task-agent/rejudge-on-head.ts +46 -2
  441. package/src/task-agent/repair-cycle.ts +1 -1
  442. package/src/task-agent/task-hand.ts +129 -24
  443. package/src/task-agent/tier-split.ts +105 -21
  444. package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
  445. package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
  446. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +27 -2
  447. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
  448. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
  449. package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
  450. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
  451. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
  452. package/src/task-orchestrator/surfaces/self-implement-pod.ts +186 -33
  453. package/src/tool-runtime/skill-exec-runtime.ts +95 -5
  454. package/src/tui/entry.ts +15 -2
  455. package/src/tui/inline-choice.ts +188 -0
  456. package/src/tui/sidetab/list.ts +2 -176
  457. package/src/tui/slash/term.ts +12 -1
  458. package/src/tui-client/dashboard-session.ts +7 -1
  459. package/src/user-config.ts +34 -4
  460. package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
  461. package/src/ux-sim/fake-land-queue.ts +88 -0
  462. package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
  463. package/src/ux-sim/goal-interim-trace.ts +24 -0
  464. package/src/ux-sim/next-tui-seat-scenarios.ts +8 -13
  465. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
  466. package/src/version/packed-revision.json +1 -1
  467. package/src/video-pipeline/recipes/explainer.ts +54 -2
  468. package/src/web-search/grok.ts +32 -6
  469. package/src/web-search/index.ts +8 -7
  470. package/src/workflow-runtime/node-catalog.ts +53 -4
  471. package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +0 -27
  472. package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
  481. package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
  482. package/apps/pwa/out/_next/static/chunks/2415.738b777642a02233.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
  492. package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
  494. package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
  498. package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
  504. package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
  514. package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
  515. package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
  517. package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
  520. package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
  523. package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
  527. package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
  539. package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +0 -77
  544. package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
  554. package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
  555. package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
  556. package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
  560. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
  605. package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
  615. /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
@@ -1,8 +1,8 @@
1
- import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
- import { randomUUID } from 'node:crypto';
1
+ import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { createHash, randomUUID } from 'node:crypto';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { spawnSync } from 'node:child_process';
5
- import { join } from 'node:path/posix';
5
+ import { basename, join, resolve } from 'node:path/posix';
6
6
  import { prepareDeterministicChildEnvironment } from '../../scripts/lib/deterministic-env.js';
7
7
  import { audit as auditEntryBudget, entryBudgetAffected } from '../../scripts/ratchets/next-tui-entry-budget.js';
8
8
  import { withGateTestEnv } from '../../scripts/lib/gate-test-env.js';
@@ -14,11 +14,12 @@ import { runIosUnitTestGate } from '../../scripts/ci-ios-unit-tests.js';
14
14
  import { runPwaBuildGate } from '../../scripts/ci-pwa-build-gate.js';
15
15
  import { runMockModuleRestoreGate } from '../../scripts/ci-mock-module-restore-gate.js';
16
16
  import { parseReviewDepthFromFilesJson } from '../agent-mission/review-depth.js';
17
- import { buildGateBaselineReport, calculateGateTestCountChange, formatGateBaselineNote, formatGateTestCountNote, isGateTestFile, recheckTimeoutOnlyIntroducedFailures, runGateBaseline, type BaselineProcessResult, type BaselineProcessStatus, type GateTestFailure, type TimeoutRecheckRecord, type TimeoutRerunObservation } from './gate-baseline.js';
17
+ import { buildGateBaselineReport, calculateGateTestCountChange, formatGateBaselineNote, formatGateTestCountNote, isGateTestFile, recheckOutsideScopeFailures, recheckTimeoutOnlyIntroducedFailures, runGateBaseline, type BaselineProcessResult, type BaselineProcessStatus, type GateBaselineReport, type GateTestFailure, type InterferenceRecheckRecord, type TimeoutRecheckRecord, type TimeoutRerunObservation } from './gate-baseline.js';
18
18
  import { resolveGateScope } from './gate-scope.js';
19
19
  import { publicExposureFiles, runExposeGate } from './expose-gate.js';
20
20
  import { getUserConfig } from '../user-config.js';
21
21
  import { debug, redactSecretText } from '../debug/log.js';
22
+ import { getElanousConfigDir } from '../elanous-config-dir.js';
22
23
  import { buildDocumentGuardianIndex, formatDocumentGuardians } from './document-guardian-index.js';
23
24
  import { buildImporterTestIndex, importerTestsNotInRunSet, isTestPath, type ImporterTestIndex } from './importer-test-index.js';
24
25
  import { isCommentOnlySourceChange } from './comment-only-source.js';
@@ -38,6 +39,8 @@ import { defaultGateEnvKey, defaultRevResolver, resolveArtifactDir, writeGateArt
38
39
  export interface SelfGateCliOptions {
39
40
  base?: string;
40
41
  pr?: string;
42
+ /** Bypass reuse of the last passing test radius; still write this run's receipt for the next invocation. */
43
+ noInherit?: boolean;
41
44
  shards?: number;
42
45
  /** Live shard bundle concurrency; default three, bounded to one through four. */
43
46
  shardConcurrency?: number;
@@ -106,11 +109,11 @@ interface SelfGateCliDeps {
106
109
  runTests?: (cwd: string, files: readonly string[]) => ProcessResult;
107
110
  runBaseline?: (cwd: string, files: readonly string[], baseRef: string) => BaselineProcessResult;
108
111
  runTimeoutRecheck?: (cwd: string, file: string, name: string, timeoutMs: number) => { observation?: TimeoutRerunObservation; elapsedMs: number; output: string };
112
+ runInterferenceRecheck?: (cwd: string, report: GateBaselineReport, baseRef: string, relatedTestFiles: readonly string[]) => GateBaselineReport;
109
113
  runShards?: typeof runShardedGateTests;
110
114
  runShardsAsync?: typeof runShardedGateTestsAsync;
111
115
  /** Test seam for the live progress line. */
112
116
  writeProgressStderr?: (line: string) => void;
113
- now?: () => number;
114
117
  runIsolationGate?: (out: GateOutput) => number;
115
118
  runMockModuleRestoreGate?: (out: GateOutput) => number;
116
119
  /** 모델 이름 하드코딩 래칫(🅕 #20521) — `pr land` 만 물고 하니스 무인 병합은 안 물면 위반이 main 에 들어가 남의 착지를 막는다(🅣 2026-09-25). */
@@ -128,12 +131,19 @@ interface SelfGateCliDeps {
128
131
  /** `--artifact-dir` 전용 심 — 커밋 sha 해석(실패 = null) · 환경 키. */
129
132
  resolveRev?: RevResolver;
130
133
  envKey?: () => string;
134
+ /** Receipt-store seam for tests; production stores under ~/.elanous/gate-receipts. */
135
+ gateReceiptDir?: () => string;
136
+ now?: () => number;
131
137
  }
132
138
 
133
139
  /** `--artifact-dir` 가 쓸 재료 — 판정 경로가 «채우기만» 하고 읽지 않는다. */
134
140
  interface GateArtifactCapture {
135
141
  baseRef?: string;
136
142
  testFiles?: readonly string[];
143
+ fullTestFiles?: readonly string[];
144
+ failedTestFiles?: readonly string[];
145
+ testReceiptMeasured?: boolean;
146
+ receiptDecision?: GateReceiptDecision;
137
147
  sharded?: ReturnType<typeof runShardedGateTests>;
138
148
  verdict?: string;
139
149
  verdictLine?: string;
@@ -144,6 +154,7 @@ interface GateArtifactCapture {
144
154
  unrunImporters?: number | null;
145
155
  importerLookupFailed?: string;
146
156
  timeoutRechecks?: readonly TimeoutRecheckRecord[];
157
+ interferenceRechecks?: readonly InterferenceRecheckRecord[];
147
158
  }
148
159
 
149
160
  /** SIDE-VERIFY ③ — summary 정수 칸: 게이트가 이미 낸 `result.baseline` ⊕ `unrunImporterTotal` 을 «옮기기만» 한다.
@@ -799,6 +810,7 @@ export function selectGateTestFiles(cwd: string, options: GateSelectionOptions =
799
810
  export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): SelfGateCliResult {
800
811
  const capture: GateArtifactCapture = {};
801
812
  const result = runSelfGateCliCore(cwd, options, deps, capture, false) as SelfGateCliResult;
813
+ persistGateReceipt(cwd, capture, deps);
802
814
  if (options.artifactDir !== undefined) emitGateArtifacts(cwd, options.artifactDir, result, capture, deps);
803
815
  return result;
804
816
  }
@@ -807,6 +819,7 @@ export function runSelfGateCli(cwd: string, options: SelfGateCliOptions = {}, de
807
819
  export async function runSelfGateCliAsync(cwd: string, options: SelfGateCliOptions = {}, deps: SelfGateCliDeps = {}): Promise<SelfGateCliResult> {
808
820
  const capture: GateArtifactCapture = {};
809
821
  const result = await runSelfGateCliCore(cwd, options, deps, capture, true);
822
+ persistGateReceipt(cwd, capture, deps);
810
823
  if (options.artifactDir !== undefined) emitGateArtifacts(cwd, options.artifactDir, result, capture, deps);
811
824
  return result;
812
825
  }
@@ -830,6 +843,7 @@ function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCli
830
843
  verdict: capture.verdict ?? null,
831
844
  ...(capture.verdictLine !== undefined ? { verdictLine: capture.verdictLine } : {}),
832
845
  ...(capture.timeoutRechecks ? { timeoutRechecks: capture.timeoutRechecks } : {}),
846
+ ...(capture.interferenceRechecks ? { interferenceRechecks: capture.interferenceRechecks } : {}),
833
847
  exitCode: result.exitCode,
834
848
  counts: counts.counts,
835
849
  ...(counts.reason !== undefined ? { countsUnavailableReason: counts.reason } : {}),
@@ -844,6 +858,246 @@ function emitGateArtifacts(cwd: string, artifactDir: string, result: SelfGateCli
844
858
  }
845
859
  }
846
860
 
861
+ const GATE_RECEIPT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
862
+ const GATE_RECEIPT_SCHEMA = 1;
863
+
864
+ interface GateReceipt {
865
+ schema: 1;
866
+ createdAt: number;
867
+ repositoryHash: string;
868
+ branch: string;
869
+ baseSha: string;
870
+ headSha: string;
871
+ runtime: string;
872
+ environmentKey: string;
873
+ lockfileHash: string;
874
+ fullTestFiles: string[];
875
+ failedTestFiles: string[];
876
+ measured: boolean;
877
+ }
878
+
879
+ interface GateReceiptIdentity extends Omit<GateReceipt, 'createdAt' | 'fullTestFiles' | 'failedTestFiles' | 'measured'> {
880
+ receiptPath: string;
881
+ receiptDir: string;
882
+ }
883
+
884
+ interface GateReceiptDecision {
885
+ mode: 'full' | 'inherit';
886
+ reason: string;
887
+ identity?: GateReceiptIdentity;
888
+ sourceHead?: string;
889
+ runTestFiles?: readonly string[];
890
+ inheritedTestFiles?: readonly string[];
891
+ }
892
+
893
+ function sha256(value: string | Buffer): string {
894
+ return createHash('sha256').update(value).digest('hex');
895
+ }
896
+
897
+ function normalizedRepositoryUrl(value: string): string | undefined {
898
+ const raw = value.trim();
899
+ if (!raw) return undefined;
900
+ if (!raw.includes('://')) {
901
+ const scp = /^(?:[^@]+@)?([^:]+):(.+)$/.exec(raw);
902
+ if (scp) return `${scp[1].toLowerCase()}/${scp[2]}`.replace(/\.git$/i, '');
903
+ }
904
+ try {
905
+ const url = new URL(raw);
906
+ url.username = '';
907
+ url.password = '';
908
+ url.search = '';
909
+ url.hash = '';
910
+ return `${url.protocol.toLowerCase()}//${url.host.toLowerCase()}${url.pathname}`.replace(/\.git$/i, '').replace(/\/$/, '');
911
+ } catch { return undefined; }
912
+ }
913
+
914
+ function gateReceiptIdentity(
915
+ cwd: string,
916
+ selection: ChangedFileSelection,
917
+ deps: SelfGateCliDeps,
918
+ ): { identity?: GateReceiptIdentity; reason?: string } {
919
+ const run = deps.runCommand ?? defaultRunCommand;
920
+ const command = (args: string[]) => {
921
+ try { return run('git', args, cwd); }
922
+ catch (error) { return { status: null, stderr: error instanceof Error ? error.message : String(error) }; }
923
+ };
924
+ const worktree = command(['status', '--porcelain=v1', '-z', '--untracked-files=all']);
925
+ if (worktree.status !== 0 || worktree.error || worktree.stdout === undefined) {
926
+ return { reason: 'worktree-status-unavailable' };
927
+ }
928
+ if (worktree.stdout.length > 0) return { reason: 'worktree-dirty' };
929
+ const remote = command(['config', '--get', 'remote.origin.url']);
930
+ const repositoryUrl = remote.status === 0 ? normalizedRepositoryUrl(remote.stdout ?? '') : undefined;
931
+ if (!repositoryUrl) return { reason: 'repository-origin-unavailable' };
932
+ const branch = selection.prHeadRefName?.trim() || (() => {
933
+ const result = command(['branch', '--show-current']);
934
+ return result.status === 0 ? (result.stdout ?? '').trim() : '';
935
+ })();
936
+ if (!branch) return { reason: 'branch-unavailable' };
937
+ if (selection.baseRef === 'HEAD') return { reason: 'uncommitted-or-no-stable-base' };
938
+ const resolveRev = deps.resolveRev ?? defaultRevResolver(cwd);
939
+ const baseSha = resolveRev(selection.baseRef);
940
+ const headSha = resolveRev('HEAD');
941
+ if (!baseSha || !headSha || !/^[0-9a-f]{40}$/.test(baseSha) || !/^[0-9a-f]{40}$/.test(headSha)) {
942
+ return { reason: 'base-or-head-sha-unavailable' };
943
+ }
944
+ const lockfile = ['bun.lock', 'bun.lockb'].map((name) => join(cwd, name)).find((path) => existsSync(path));
945
+ if (!lockfile) return { reason: 'lockfile-unavailable' };
946
+ let lockfileHash: string;
947
+ try { lockfileHash = sha256(readFileSync(lockfile)); }
948
+ catch { return { reason: 'lockfile-unreadable' }; }
949
+ const runtime = process.versions.bun ?? (globalThis as { Bun?: { version?: string } }).Bun?.version;
950
+ if (!runtime) return { reason: 'bun-runtime-unavailable' };
951
+ let environmentKey: string;
952
+ try { environmentKey = (deps.envKey ?? defaultGateEnvKey)(); }
953
+ catch { return { reason: 'environment-key-unavailable' }; }
954
+ const repositoryHash = sha256(repositoryUrl);
955
+ const receiptDir = deps.gateReceiptDir?.() ?? join(getElanousConfigDir(), 'gate-receipts');
956
+ const key = sha256(`${repositoryUrl}\0${branch}\0${baseSha}`);
957
+ return {
958
+ identity: {
959
+ schema: GATE_RECEIPT_SCHEMA, repositoryHash, branch, baseSha, headSha, runtime,
960
+ environmentKey, lockfileHash, receiptDir, receiptPath: join(receiptDir, `${key}.json`),
961
+ },
962
+ };
963
+ }
964
+
965
+ function pruneExpiredGateReceipts(receiptDir: string, now: number): void {
966
+ try {
967
+ for (const name of readdirSync(receiptDir)) {
968
+ if (!/^[a-f0-9]{64}\.json$/.test(name)) continue;
969
+ const path = join(receiptDir, name);
970
+ try {
971
+ const stat = lstatSync(path);
972
+ if (stat.isFile() && !stat.isSymbolicLink() && now - stat.mtimeMs > GATE_RECEIPT_TTL_MS) rmSync(path, { force: true });
973
+ } catch { /* a stale receipt disappearing concurrently is harmless */ }
974
+ }
975
+ } catch { /* the first receipt has no directory to prune */ }
976
+ }
977
+
978
+ function isGateReceipt(value: unknown): value is GateReceipt {
979
+ if (!value || typeof value !== 'object') return false;
980
+ const item = value as Partial<GateReceipt>;
981
+ return item.schema === GATE_RECEIPT_SCHEMA && typeof item.createdAt === 'number'
982
+ && typeof item.repositoryHash === 'string' && typeof item.branch === 'string'
983
+ && typeof item.baseSha === 'string' && /^[0-9a-f]{40}$/.test(item.baseSha)
984
+ && typeof item.headSha === 'string' && /^[0-9a-f]{40}$/.test(item.headSha)
985
+ && typeof item.runtime === 'string' && typeof item.environmentKey === 'string'
986
+ && typeof item.lockfileHash === 'string' && /^[0-9a-f]{64}$/.test(item.lockfileHash)
987
+ && Array.isArray(item.fullTestFiles) && item.fullTestFiles.every((path) => typeof path === 'string' && isGateTestFile(path))
988
+ && Array.isArray(item.failedTestFiles) && item.failedTestFiles.every((path) => typeof path === 'string' && isGateTestFile(path))
989
+ && typeof item.measured === 'boolean';
990
+ }
991
+
992
+ function rejectGateReceipt(cwd: string, reason: string, details: Record<string, unknown> = {}): GateReceiptDecision {
993
+ try { debug.log('self-implement', 'gate.receipt-inheritance-rejected', { reason, ...details }); } catch { /* telemetry must not alter the gate */ }
994
+ return { mode: 'full', reason };
995
+ }
996
+
997
+ function decideGateReceiptInheritance(
998
+ cwd: string,
999
+ options: SelfGateCliOptions,
1000
+ selection: ChangedFileSelection,
1001
+ fullTestFiles: readonly string[],
1002
+ deps: SelfGateCliDeps,
1003
+ ): GateReceiptDecision {
1004
+ // Existing injected-command fixtures stay isolated unless a test explicitly supplies a receipt directory.
1005
+ if (deps.runCommand && !deps.gateReceiptDir) return { mode: 'full', reason: 'injected-command-no-receipt-store' };
1006
+ const resolved = gateReceiptIdentity(cwd, selection, deps);
1007
+ if (!resolved.identity) return rejectGateReceipt(cwd, resolved.reason ?? 'receipt-identity-unavailable');
1008
+ const identity = resolved.identity;
1009
+ if (options.noInherit) {
1010
+ try { debug.log('self-implement', 'gate.receipt-inheritance-rejected', { reason: 'forced-full', baseSha: identity.baseSha, headSha: identity.headSha }); } catch { /* observation only */ }
1011
+ return { mode: 'full', reason: 'forced-full', identity };
1012
+ }
1013
+ const now = deps.now?.() ?? Date.now();
1014
+ pruneExpiredGateReceipts(identity.receiptDir, now);
1015
+ let prior: unknown;
1016
+ try {
1017
+ const stat = lstatSync(identity.receiptPath);
1018
+ if (!stat.isFile() || stat.isSymbolicLink()) return rejectGateReceipt(cwd, 'receipt-not-regular-file', { baseSha: identity.baseSha });
1019
+ prior = JSON.parse(readFileSync(identity.receiptPath, 'utf8'));
1020
+ } catch (error) {
1021
+ const code = (error as NodeJS.ErrnoException)?.code;
1022
+ return rejectGateReceipt(cwd, code === 'ENOENT' ? 'no-prior-receipt' : 'receipt-read-failed', { baseSha: identity.baseSha });
1023
+ }
1024
+ if (!isGateReceipt(prior)) return rejectGateReceipt(cwd, 'receipt-schema-invalid', { baseSha: identity.baseSha });
1025
+ if (now - prior.createdAt > GATE_RECEIPT_TTL_MS) {
1026
+ try { rmSync(identity.receiptPath, { force: true }); } catch { /* stale file can remain without affecting the full gate */ }
1027
+ return rejectGateReceipt(cwd, 'receipt-expired', { previousHead: prior.headSha });
1028
+ }
1029
+ if (prior.repositoryHash !== identity.repositoryHash || prior.branch !== identity.branch) return rejectGateReceipt(cwd, 'repository-or-branch-mismatch');
1030
+ if (prior.baseSha !== identity.baseSha) return rejectGateReceipt(cwd, 'base-sha-mismatch', { previousBase: prior.baseSha, currentBase: identity.baseSha });
1031
+ if (prior.runtime !== identity.runtime || prior.environmentKey !== identity.environmentKey) return rejectGateReceipt(cwd, 'runtime-mismatch', { previousRuntime: prior.runtime, currentRuntime: identity.runtime });
1032
+ if (prior.lockfileHash !== identity.lockfileHash) return rejectGateReceipt(cwd, 'lockfile-hash-mismatch');
1033
+ if (!prior.measured) return rejectGateReceipt(cwd, 'previous-test-run-unmeasured', { previousHead: prior.headSha });
1034
+ const ancestor = (deps.runCommand ?? defaultRunCommand)('git', ['merge-base', '--is-ancestor', prior.headSha, identity.headSha], cwd);
1035
+ if (ancestor.status !== 0 || ancestor.error) return rejectGateReceipt(cwd, 'previous-head-not-ancestor', { previousHead: prior.headSha, currentHead: identity.headSha });
1036
+
1037
+ const diff = (deps.runCommand ?? defaultRunCommand)('git', ['diff', '--name-only', `${prior.headSha}..${identity.headSha}`], cwd);
1038
+ if (diff.status !== 0 || diff.error || diff.stdout === undefined) return rejectGateReceipt(cwd, 'head-delta-unavailable', { previousHead: prior.headSha });
1039
+ const changedFiles = [...new Set(diff.stdout.split('\n').map((path) => normalizeGatePath(path.trim())).filter(Boolean))].sort();
1040
+ try {
1041
+ const deltaSelection = { files: changedFiles, baseRef: prior.headSha };
1042
+ const deltaOptions: GateSelectionOptions = { ...options, base: prior.headSha, pr: undefined };
1043
+ const deltaDeps: GateSelectionDeps = { ...deps, changedFiles: () => deltaSelection };
1044
+ const deltaPrepared = prepareGateTestSelection(cwd, deltaOptions, deltaDeps);
1045
+ if (deltaPrepared.lookupFailed || deltaPrepared.routeIndex?.lookupFailures.length) {
1046
+ return rejectGateReceipt(cwd, 'head-delta-test-radius-unmeasured', { previousHead: prior.headSha });
1047
+ }
1048
+ const deltaTests = finishGateTestSelection(deltaPrepared, deltaOptions, cwd, deltaDeps).testFiles;
1049
+ const current = new Set(fullTestFiles);
1050
+ const previous = new Set(prior.fullTestFiles);
1051
+ const previousFailures = new Set(prior.failedTestFiles);
1052
+ const changed = new Set(deltaTests);
1053
+ const runTestFiles = fullTestFiles.filter((path) => changed.has(path) || previousFailures.has(path) || !previous.has(path));
1054
+ const run = new Set(runTestFiles);
1055
+ const inheritedTestFiles = fullTestFiles.filter((path) => previous.has(path) && !previousFailures.has(path) && !run.has(path));
1056
+ // A current scope path not accounted for by the receipt is run, never silently inherited.
1057
+ for (const path of fullTestFiles) if (!previous.has(path) && !run.has(path)) return rejectGateReceipt(cwd, 'new-test-not-selected', { path });
1058
+ if (current.size !== fullTestFiles.length) return rejectGateReceipt(cwd, 'current-test-scope-duplicate');
1059
+ try {
1060
+ debug.log('self-implement', 'gate.receipt-inheritance-accepted', {
1061
+ previousHead: prior.headSha, currentHead: identity.headSha, baseSha: identity.baseSha,
1062
+ changedFiles, rerunTestFiles: runTestFiles, inheritedTestFiles,
1063
+ });
1064
+ } catch { /* observation only */ }
1065
+ return { mode: 'inherit', reason: 'matching-prior-receipt', identity, sourceHead: prior.headSha,
1066
+ runTestFiles, inheritedTestFiles };
1067
+ } catch (error) {
1068
+ return rejectGateReceipt(cwd, 'head-delta-test-radius-failed', { message: error instanceof Error ? error.message : String(error) });
1069
+ }
1070
+ }
1071
+
1072
+ function persistGateReceipt(cwd: string, capture: GateArtifactCapture, deps: SelfGateCliDeps): void {
1073
+ const decision = capture.receiptDecision;
1074
+ const identity = decision?.identity;
1075
+ if (!identity) return;
1076
+ if (deps.runCommand && !deps.gateReceiptDir) return;
1077
+ if (capture.testReceiptMeasured !== true || !capture.fullTestFiles || !capture.failedTestFiles) {
1078
+ try { debug.log('self-implement', 'gate.receipt-write-rejected', { reason: 'test-outcome-unmeasured', headSha: identity.headSha }); } catch { /* observation only */ }
1079
+ return;
1080
+ }
1081
+ const failed = [...new Set(capture.failedTestFiles)].filter((path) => capture.fullTestFiles!.includes(path)).sort();
1082
+ const receipt: GateReceipt = {
1083
+ schema: GATE_RECEIPT_SCHEMA, createdAt: deps.now?.() ?? Date.now(), repositoryHash: identity.repositoryHash,
1084
+ branch: identity.branch, baseSha: identity.baseSha, headSha: identity.headSha, runtime: identity.runtime,
1085
+ environmentKey: identity.environmentKey, lockfileHash: identity.lockfileHash,
1086
+ fullTestFiles: [...new Set(capture.fullTestFiles)].sort(), failedTestFiles: failed, measured: true,
1087
+ };
1088
+ const temporary = join(identity.receiptDir, `.${basename(identity.receiptPath)}.${process.pid}.${randomUUID()}.tmp`);
1089
+ try {
1090
+ mkdirSync(identity.receiptDir, { recursive: true, mode: 0o700 });
1091
+ pruneExpiredGateReceipts(identity.receiptDir, receipt.createdAt);
1092
+ writeFileSync(temporary, `${JSON.stringify(receipt, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
1093
+ renameSync(temporary, identity.receiptPath);
1094
+ try { debug.log('self-implement', 'gate.receipt-written', { headSha: identity.headSha, baseSha: identity.baseSha, testFiles: receipt.fullTestFiles.length, failedTestFiles: failed.length }); } catch { /* observation only */ }
1095
+ } catch (error) {
1096
+ try { rmSync(temporary, { force: true }); } catch { /* best effort */ }
1097
+ try { debug.log('self-implement', 'gate.receipt-write-rejected', { reason: 'receipt-write-failed', message: error instanceof Error ? error.message : String(error) }); } catch { /* observation only */ }
1098
+ }
1099
+ }
1100
+
847
1101
  /** A completed bundle is observed immediately, before the synchronous runner returns. Each sink is best effort. */
848
1102
  function shardProgressObserver(cwd: string, options: SelfGateCliOptions, deps: SelfGateCliDeps): (progress: ShardRunProgress) => void {
849
1103
  const now = deps.now ?? Date.now;
@@ -879,8 +1133,17 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
879
1133
  const expose = publicExposureFiles(selection.files).length > 0
880
1134
  ? runExposeGate(cwd, selection.files, getUserConfig().harness?.exposeGate === 'strict' ? 'strict' : 'warn', deps.runCommand)
881
1135
  : { passed: true, log: '' };
882
- const { alwaysInclude, alwaysIncludeMissing, alwaysIncludeExtra, importerTestsAdded, commentOnlySources, scenarioTests, testFiles,
1136
+ const { alwaysInclude, alwaysIncludeMissing, alwaysIncludeExtra, importerTestsAdded, commentOnlySources, scenarioTests, testFiles: fullTestFiles,
883
1137
  skipTestStep, importerTestsNotRun, unrunImporterTotal, callerTestsOverflow, importerLookupFailed } = finishGateTestSelection(prepared, options, cwd, deps);
1138
+ const receiptDecision = options.base || options.pr || options.noInherit
1139
+ ? decideGateReceiptInheritance(cwd, options, selection, fullTestFiles, deps) : undefined;
1140
+ if (receiptDecision && !receiptDecision.identity && (!deps.runCommand || deps.gateReceiptDir)) {
1141
+ receiptDecision.identity = gateReceiptIdentity(cwd, selection, deps).identity;
1142
+ }
1143
+ const testFiles = receiptDecision?.mode === 'inherit' ? [...(receiptDecision.runTestFiles ?? fullTestFiles)] : [...fullTestFiles];
1144
+ capture.fullTestFiles = [...fullTestFiles];
1145
+ capture.receiptDecision = receiptDecision;
1146
+ const relatedTestFiles = [...new Set([...selection.files.filter(isTestPath), ...(scope.testArgs ?? []), ...importerTestsAdded])];
884
1147
  const lines = [
885
1148
  // ⛔⭐ 「changed=0」을 «초록»으로 읽는 사고가 났다(2026-09-02 · 🅕 보고 · 🅣 재현).
886
1149
  // 커밋 «전»에 돌리면 작업 트리 변경은 «안 세므로» changed=0 이 나오는데,
@@ -889,7 +1152,10 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
889
1152
  + (selection.files.length === 0 && (selection.ignoredDirtyPaths?.length ?? 0) > 0
890
1153
  ? ` ⚠️ 센 것이 0인데 «커밋 안 된» 변경 ${selection.ignoredDirtyPaths!.length}개가 있다 — 「통과」가 아니라 「안 쟀다」다(커밋 뒤 다시 돌려라)`
891
1154
  : ''),
892
- `scope: ${scope.testArgs?.join(', ') ?? '(test step skipped)'}`,
1155
+ `scope: ${receiptDecision?.mode === 'inherit' ? testFiles.join(', ') || '(all tests inherited)' : scope.testArgs?.join(', ') ?? '(test step skipped)'}`,
1156
+ ...(receiptDecision ? [receiptDecision.mode === 'inherit'
1157
+ ? `gate receipt: inherited ${receiptDecision.inheritedTestFiles?.length ?? 0} · rerun ${testFiles.length} · source head ${receiptDecision.sourceHead?.slice(0, 12) ?? '(unknown)'}`
1158
+ : `gate receipt: full radius (${receiptDecision.reason})`] : []),
893
1159
  `ignored unrelated worktree changes: ${selection.ignoredDirtyPaths === undefined ? '(not checked)' : selection.ignoredDirtyPaths.join(', ') || '(none)'}`,
894
1160
  `unverified: ${scope.unverified.length} (${scope.unverified.join(', ') || '(none)'})`,
895
1161
  `elanous runtime artifacts: ${scope.elanousRuntimeArtifacts.length} (${scope.elanousRuntimeArtifacts.join(', ') || '(none)'})`,
@@ -958,8 +1224,29 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
958
1224
  lines.push(`next-tui-entry-budget: UNMEASURED ${error instanceof Error ? error.message : String(error)}`);
959
1225
  }
960
1226
 
1227
+ if (receiptDecision?.mode === 'inherit' && testFiles.length === 0 && fullTestFiles.length > 0) {
1228
+ capture.testReceiptMeasured = true;
1229
+ capture.failedTestFiles = [];
1230
+ capture.verdict = 'passed';
1231
+ const testLine = formatPartialObservationNote(unrunImporterTotal ?? 0,
1232
+ `tests: pass (${receiptDecision.inheritedTestFiles?.length ?? 0} files inherited from ${receiptDecision.sourceHead?.slice(0, 12) ?? 'prior receipt'})`);
1233
+ lines.push(testLine);
1234
+ capture.verdictLine = testLine;
1235
+ const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
1236
+ logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
1237
+ return {
1238
+ exitCode: policyPassed && androidPassed && iosPassed && pwaPassed && entryBudgetPassed && expose.passed ? 0 : 1,
1239
+ lines, changedFiles: selection.files, testFiles, unverified: scope.unverified,
1240
+ documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests,
1241
+ alwaysIncludeMissing, importerTestsAdded,
1242
+ baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 },
1243
+ };
1244
+ }
1245
+
961
1246
  if (skipTestStep) {
962
1247
  const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
1248
+ capture.testReceiptMeasured = false;
1249
+ capture.failedTestFiles = [];
963
1250
  logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
964
1251
  Object.assign(capture, { verdict: 'skipped', artifactsUnavailable: 'no-tests' } satisfies GateArtifactCapture);
965
1252
  return { exitCode: androidPassed && iosPassed && pwaPassed && entryBudgetPassed && policyPassed && expose.passed ? 0 : 1, lines, changedFiles: selection.files, testFiles: [], unverified: scope.unverified, documentPaths: scope.documentPaths, documentsWithoutDerivedTests: scope.documentsWithoutDerivedTests, alwaysIncludeMissing, importerTestsAdded, baseline: { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 } };
@@ -1006,6 +1293,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
1006
1293
  let shardBaseline: SelfGateCliResult['baseline'];
1007
1294
  let unmeasuredReason: string | undefined;
1008
1295
  if (aggregate.status === 'unmeasured') {
1296
+ capture.testReceiptMeasured = false;
1297
+ capture.failedTestFiles = [];
1009
1298
  unmeasuredReason = sharded.reason
1010
1299
  ? redactSecretText(sharded.reason).replace(/[\r\n\t\x00-\x1f\x7f]+/g, ' ').slice(0, 500)
1011
1300
  : aggregate.retryShardIds.join(', ') || 'no complete JUnit';
@@ -1017,8 +1306,12 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
1017
1306
  capture.unmeasuredReason = unmeasuredReason;
1018
1307
  }
1019
1308
  else if (aggregate.report) {
1020
- const report = recheckTimeoutOnlyIntroducedFailures(cwd, aggregate.report, deps.runTimeoutRecheck);
1309
+ const timeoutReport = recheckTimeoutOnlyIntroducedFailures(cwd, aggregate.report, deps.runTimeoutRecheck);
1310
+ const report = deps.runShards || deps.runShardsAsync
1311
+ ? deps.runInterferenceRecheck?.(cwd, timeoutReport, selection.baseRef, relatedTestFiles) ?? timeoutReport
1312
+ : (deps.runInterferenceRecheck ?? recheckOutsideScopeFailures)(cwd, timeoutReport, selection.baseRef, relatedTestFiles);
1021
1313
  capture.timeoutRechecks = report.timeoutRechecks;
1314
+ capture.interferenceRechecks = report.interferenceRechecks;
1022
1315
  const timeoutRecheckResolvedFailure = aggregate.status === 'failed'
1023
1316
  && (report.loadTimeout ?? 0) > 0
1024
1317
  && report.introduced === 0 && report.unknown === 0 && report.preconditionUnmet === 0
@@ -1026,6 +1319,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
1026
1319
  && report.baselineStatus !== 'unknown';
1027
1320
  const effectiveStatus = timeoutRecheckResolvedFailure ? 'passed' : aggregate.status;
1028
1321
  capture.verdict = effectiveStatus;
1322
+ capture.testReceiptMeasured = report.unknown === 0 && report.preconditionUnmet === 0 && report.worktreeFailuresParsed;
1323
+ capture.failedTestFiles = [...new Set(report.failures.map((failure) => failure.file).filter((file): file is string => typeof file === 'string'))];
1029
1324
  logGateCliBaseline(cwd, {
1030
1325
  introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown,
1031
1326
  preconditionUnmet: report.preconditionUnmet, timedOut: report.timedOut,
@@ -1035,6 +1330,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
1035
1330
  lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, formatGateBaselineNote(report, unrunImporterTotal ?? 0)));
1036
1331
  shardBaseline = { introduced: report.introduced, preexisting: report.preexisting, unknown: report.unknown, preconditionUnmet: report.preconditionUnmet };
1037
1332
  } else {
1333
+ capture.testReceiptMeasured = true;
1334
+ capture.failedTestFiles = [];
1038
1335
  lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
1039
1336
  logGateCliBaseline(cwd, { ...ZERO_GATE_BASELINE, unrunImporterTotal, lookupFailed: importerLookupFailed });
1040
1337
  shardBaseline = { introduced: 0, preexisting: 0, unknown: 0, preconditionUnmet: 0 };
@@ -1056,6 +1353,8 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
1056
1353
  const worktreeLog = formatProcessOutput(test);
1057
1354
  Object.assign(capture, { unshardedRc: test.status, artifactsUnavailable: 'unsharded' } satisfies GateArtifactCapture);
1058
1355
  if (test.status === 0 && !test.error) {
1356
+ capture.testReceiptMeasured = true;
1357
+ capture.failedTestFiles = [];
1059
1358
  lines.push(formatPartialObservationNote(unrunImporterTotal ?? 0, `tests: pass (${testFiles.length} files)`));
1060
1359
  Object.assign(capture, { verdict: 'passed', verdictLine: lines[lines.length - 1] } satisfies GateArtifactCapture);
1061
1360
  const policyPassed = runPolicyGates(selection.files, cwd, lines, deps);
@@ -1065,8 +1364,17 @@ function runSelfGateCliCore(cwd: string, options: SelfGateCliOptions, deps: Self
1065
1364
 
1066
1365
  if (worktreeLog.includes('deterministic environment setup failed')) lines.push(worktreeLog);
1067
1366
  const baseline = (deps.runBaseline ?? runGateBaseline)(cwd, testFiles, selection.baseRef);
1068
- const report = recheckTimeoutOnlyIntroducedFailures(cwd, buildGateBaselineReport(worktreeLog, baseline), deps.runTimeoutRecheck);
1367
+ // An injected runner can represent a virtual checkout; only the real runner may use this host's file tree.
1368
+ const currentFileExists = deps.runTests ? undefined : (file: string) => existsSync(resolve(cwd, file));
1369
+ const timeoutReport = recheckTimeoutOnlyIntroducedFailures(cwd,
1370
+ buildGateBaselineReport(worktreeLog, baseline, undefined, 0, currentFileExists), deps.runTimeoutRecheck);
1371
+ const report = deps.runTests
1372
+ ? deps.runInterferenceRecheck?.(cwd, timeoutReport, selection.baseRef, relatedTestFiles) ?? timeoutReport
1373
+ : (deps.runInterferenceRecheck ?? recheckOutsideScopeFailures)(cwd, timeoutReport, selection.baseRef, relatedTestFiles);
1069
1374
  capture.timeoutRechecks = report.timeoutRechecks;
1375
+ capture.interferenceRechecks = report.interferenceRechecks;
1376
+ capture.testReceiptMeasured = report.unknown === 0 && report.preconditionUnmet === 0 && report.worktreeFailuresParsed;
1377
+ capture.failedTestFiles = [...new Set(report.failures.map((failure) => failure.file).filter((file): file is string => typeof file === 'string'))];
1070
1378
  logGateCliBaseline(cwd, {
1071
1379
  introduced: report.introduced,
1072
1380
  preexisting: report.preexisting,
@@ -0,0 +1,180 @@
1
+ /**
2
+ * GATE-ONCE-PER-HEAD (0.2.40 첫 조각 · OP 10-27 23:0x 지시) — host-regate 통과 영수증의 지속 등록부.
3
+ *
4
+ * S: 같은 PR head 의 자식 gate 뒤 host-regate 와 착지 게이트가 같은 시험을 다시 실행해 Pod 와 호스트 자원을 소모한다.
5
+ * C: 통과 사실이 어디에도 남지 않아 매 호출이 전 검사를 다시 돌릴 수밖에 없다.
6
+ * Q: 정확히 같은 통합 입력과 측정 범위에 대해 이미 통과한 게이트만 승계할 수 있는가?
7
+ * A: 통과 영수증을 이 등록부에 원자적으로 기록하고, runHostRegate 가 재검증·통합 후보 구성 뒤 현재 key 와
8
+ * 일치하는 통과 영수증만 승계한다. 불일치·결손·불완전·실패/측정불가 영수증은 원래 검사를 실행한다.
9
+ *
10
+ * 원본 영수증 없이 통과 판정 금지: 승계는 저장된 영수증 행 하나를 통해서만 일어나고, 그 행의 key 는
11
+ * 행 스스로의 필드에서 다시 계산되어야 한다(gateReceiptSelfKey). key 가 필드와 맞지 않는 행은 저장도
12
+ * 승계도 거절한다.
13
+ *
14
+ * 원자성: saveGateReceipts 는 임시 파일에 온전히 쓴 뒤 rename(2) 로 바꾼다 — 부분 쓰기는 관측될 수 없다.
15
+ * 프로세스끼리의 동시 저장은 각자 온전한 등록부를 남긴다(늦은 쪽이 이긴다). 잃은 영수증은 다음 호출을
16
+ * 원래 검사로 되돌릴 뿐, 잘못된 통과를 만들지 않는다 — 실패 방향으로 열린다.
17
+ */
18
+ import { createHash, randomUUID } from 'node:crypto';
19
+ import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
20
+ import { basename, dirname, join } from 'node:path';
21
+ import { gateTestBaseline } from '../../scripts/lib/gate-test-env.js';
22
+
23
+ export const GATE_RECEIPT_SCHEMA = 1;
24
+ export type GateReceiptVerdict = 'passed' | 'failed' | 'unmeasured';
25
+
26
+ const SHA40 = /^[0-9a-f]{40}$/i;
27
+ const SHA256 = /^[0-9a-f]{64}$/i;
28
+
29
+ /** 한 번의 host-regate 측정을 정체 짓는 입력. 판정(verdict)은 identity 가 아니라 key 계산에 들어간다. */
30
+ export interface GateReceiptIdentity {
31
+ /** 40자 PR head SHA */
32
+ headCommit: string;
33
+ /** 40자 실제 측정 base SHA — PR 에 기록된 baseRefOid 가 아니라 얹어 잰 끝 */
34
+ baseCommit: string;
35
+ /** 검사를 실행한 Bun 식별값(bun --version) */
36
+ bunVersion: string;
37
+ /** 검사가 설치·실행한 lockfile 의 SHA-256(bun.lock/bun.lockb 바이트) — 없으면 'absent' */
38
+ lockfileHash: string;
39
+ /** 정규화된 radius 파일 집합(병합 후보 기준 변경 파일 — 중복 제거·정렬) */
40
+ radiusFiles: readonly string[];
41
+ /** 이 영수증이 통과한 검사 토큰(종류 ⊕ 측정 범위 — 중복 제거·정렬) */
42
+ checks: readonly string[];
43
+ /** 실행 환경 지문(gateEnvFingerprint) */
44
+ envFingerprint: string;
45
+ }
46
+
47
+ export interface GateReceipt extends GateReceiptIdentity {
48
+ schema: typeof GATE_RECEIPT_SCHEMA;
49
+ key: string;
50
+ verdict: GateReceiptVerdict;
51
+ savedAt: string;
52
+ }
53
+
54
+ export type GateReceiptRegistry = Record<string, GateReceipt>;
55
+
56
+ /**
57
+ * 검사 종류·판정·환경까지 포함한 정준 직렬화의 SHA-256. 같은 측정·같은 판정만 같은 key 를 받는다.
58
+ * head/base 는 40자 hex 여야 한다 — 그보다 못한 입력으로 영수증을 만들 수 없게 문을 닫는다.
59
+ */
60
+ export function computeReceiptKey(identity: GateReceiptIdentity, verdict: GateReceiptVerdict): string {
61
+ if (!SHA40.test(identity.headCommit)) throw new Error('gate receipt head SHA is not 40 hex characters');
62
+ if (!SHA40.test(identity.baseCommit)) throw new Error('gate receipt base SHA is not 40 hex characters');
63
+ const canonical = JSON.stringify({
64
+ schema: GATE_RECEIPT_SCHEMA,
65
+ head: identity.headCommit.toLowerCase(),
66
+ base: identity.baseCommit.toLowerCase(),
67
+ bun: identity.bunVersion,
68
+ lockfile: identity.lockfileHash,
69
+ radius: [...new Set(identity.radiusFiles)].sort(),
70
+ checks: [...new Set(identity.checks)].sort(),
71
+ env: identity.envFingerprint,
72
+ verdict,
73
+ });
74
+ return createHash('sha256').update(canonical).digest('hex');
75
+ }
76
+
77
+ /** 행의 key 를 행 스스로의 필드에서 다시 계산한다 — 위조·불일치 행은 저장된 key 와 어긋난다. */
78
+ export function gateReceiptSelfKey(receipt: GateReceipt): string {
79
+ return computeReceiptKey(receipt, receipt.verdict);
80
+ }
81
+
82
+ function isGateReceipt(value: unknown): value is GateReceipt {
83
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
84
+ const row = value as Partial<GateReceipt>;
85
+ return row.schema === GATE_RECEIPT_SCHEMA && typeof row.key === 'string' && SHA256.test(row.key)
86
+ && (row.verdict === 'passed' || row.verdict === 'failed' || row.verdict === 'unmeasured')
87
+ && SHA40.test(row.headCommit ?? '') && SHA40.test(row.baseCommit ?? '')
88
+ && typeof row.bunVersion === 'string' && typeof row.lockfileHash === 'string'
89
+ && Array.isArray(row.radiusFiles) && row.radiusFiles.every((file) => typeof file === 'string')
90
+ && Array.isArray(row.checks) && row.checks.every((check) => typeof check === 'string')
91
+ && typeof row.envFingerprint === 'string' && typeof row.savedAt === 'string';
92
+ }
93
+
94
+ /**
95
+ * 결손·손상 파일은 빈 등록부로 복구한다 — 못 읽은 영수증은 «없다» 로 취급해 원래 검사를 실행한다.
96
+ * 모양이 어긋나거나 행의 key 가 맵 키와 다른 행은 버린다.
97
+ */
98
+ export function loadGateReceipts(path: string): GateReceiptRegistry {
99
+ let raw: string;
100
+ try { raw = readFileSync(path, 'utf8'); }
101
+ catch { return {}; }
102
+ let parsed: unknown;
103
+ try { parsed = JSON.parse(raw); }
104
+ catch { return {}; }
105
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
106
+ const registry: GateReceiptRegistry = {};
107
+ for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
108
+ if (!isGateReceipt(value) || value.key !== key) continue;
109
+ registry[key] = value;
110
+ }
111
+ return registry;
112
+ }
113
+
114
+ /** write-then-rename 원자적 기록 — 부분 쓰기 노출 금지. 임시 파일은 같은 디렉터리에 무작위 이름으로 둔다. */
115
+ export function saveGateReceipts(path: string, registry: GateReceiptRegistry): void {
116
+ mkdirSync(dirname(path), { recursive: true });
117
+ const tmp = join(dirname(path), `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`);
118
+ writeFileSync(tmp, `${JSON.stringify(registry, null, 2)}\n`);
119
+ try { renameSync(tmp, path); }
120
+ catch (error) {
121
+ try { unlinkSync(tmp); } catch { /* 최선의 정리 — 원래 오류를 지운다 */ }
122
+ throw error;
123
+ }
124
+ }
125
+
126
+ /** 통과 영수증을 지속 등록부에 원자적으로 병합 기록한다. key 가 필드와 맞지 않는 행은 쓰기 단계에서 거절한다. */
127
+ export function saveGateReceipt(path: string, receipt: GateReceipt): void {
128
+ if (gateReceiptSelfKey(receipt) !== receipt.key) throw new Error('gate receipt key does not match its own fields');
129
+ const registry = loadGateReceipts(path);
130
+ registry[receipt.key] = receipt;
131
+ saveGateReceipts(path, registry);
132
+ }
133
+
134
+ /**
135
+ * 승계 거절 사유. 불일치(head/base/env/Bun·lockfile/radius)·결손·불완전(현재 측정 범위 미커버)·
136
+ * 실패/측정불가 판정을 가려 한 줄로 남긴다 — debug.log 의 decline 이유가 된다.
137
+ */
138
+ export function describeGateReceiptDecline(probe: GateReceiptIdentity, registry: GateReceiptRegistry): string {
139
+ const receipts = Object.values(registry);
140
+ if (!receipts.length) return 'gate receipt registry empty';
141
+ const sameHeadBase = receipts.filter((receipt) => receipt.headCommit.toLowerCase() === probe.headCommit.toLowerCase()
142
+ && receipt.baseCommit.toLowerCase() === probe.baseCommit.toLowerCase());
143
+ if (!sameHeadBase.length) return `no receipt for head ${probe.headCommit.slice(0, 12)} base ${probe.baseCommit.slice(0, 12)}`;
144
+ for (const receipt of sameHeadBase) {
145
+ const differs: string[] = [];
146
+ if (receipt.verdict !== 'passed') differs.push(`verdict=${receipt.verdict}`);
147
+ if (receipt.envFingerprint !== probe.envFingerprint) differs.push('env fingerprint differs');
148
+ if (receipt.bunVersion !== probe.bunVersion || receipt.lockfileHash !== probe.lockfileHash) differs.push('bun/lockfile differs');
149
+ if ([...new Set(receipt.radiusFiles)].sort().join('\n') !== [...new Set(probe.radiusFiles)].sort().join('\n')) differs.push('changed-file radius differs');
150
+ const current = [...new Set(probe.checks)].sort();
151
+ const stored = [...new Set(receipt.checks)].sort();
152
+ if (stored.join('\n') !== current.join('\n')) {
153
+ const missing = current.filter((check) => !stored.includes(check));
154
+ differs.push(missing.length && stored.every((check) => current.includes(check))
155
+ ? `receipt does not cover: ${missing.join(',')}`
156
+ : `receipt checks differ (stored ${stored.join(',')})`);
157
+ }
158
+ if (differs.length) return `receipt ${receipt.key.slice(0, 12)} ${differs.join(' · ')}`;
159
+ }
160
+ return 'no stored receipt matches this measurement key';
161
+ }
162
+
163
+ /** 실행 환경 지문: 플랫폼 ⊕ 게이트 시험 baseline(TZ·locale·fake-LLM 스위치)의 정준 직렬화 SHA-256. */
164
+ export function gateEnvFingerprint(env: NodeJS.ProcessEnv): string {
165
+ const baseline = gateTestBaseline(env);
166
+ const canonical = JSON.stringify({
167
+ platform: process.platform,
168
+ env: Object.fromEntries(Object.entries(baseline).sort(([a], [b]) => a.localeCompare(b))),
169
+ });
170
+ return createHash('sha256').update(canonical).digest('hex');
171
+ }
172
+
173
+ /** 후보 워크트리가 실제로 설치·실행한 lockfile 의 SHA-256. 둘 다 없으면 'absent'. */
174
+ export function gateLockfileHash(worktree: string): string {
175
+ for (const name of ['bun.lock', 'bun.lockb']) {
176
+ if (!existsSync(join(worktree, name))) continue;
177
+ return createHash('sha256').update(readFileSync(join(worktree, name))).digest('hex');
178
+ }
179
+ return 'absent';
180
+ }