@chorus-aidlc/chorus 0.18.0 → 0.19.0

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 (329) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-build-manifest.json +341 -339
  3. package/.next/standalone/.next/app-path-routes-manifest.json +41 -41
  4. package/.next/standalone/.next/build-manifest.json +5 -5
  5. package/.next/standalone/.next/prerender-manifest.json +27 -27
  6. package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page.js +1 -1
  7. package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page.js +1 -1
  10. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page.js +1 -1
  13. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page.js.nft.json +1 -1
  14. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page.js +2 -2
  16. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page.js +2 -2
  19. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page_client-reference-manifest.js +1 -1
  21. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page.js +2 -2
  22. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js +2 -2
  25. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page_client-reference-manifest.js +1 -1
  27. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js +2 -2
  28. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page_client-reference-manifest.js +1 -1
  30. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page.js +2 -2
  31. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page.js +1 -1
  34. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js +1 -1
  37. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page_client-reference-manifest.js +1 -1
  39. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js +1 -1
  40. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page_client-reference-manifest.js +1 -1
  42. package/.next/standalone/.next/server/app/(dashboard)/projects/page.js +1 -1
  43. package/.next/standalone/.next/server/app/(dashboard)/projects/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/(dashboard)/projects/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/(dashboard)/settings/page.js +2 -2
  46. package/.next/standalone/.next/server/app/(dashboard)/settings/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  50. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  51. package/.next/standalone/.next/server/app/admin/companies/[uuid]/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/admin/companies/new/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/admin/companies/new.html +2 -2
  54. package/.next/standalone/.next/server/app/admin/companies/new.rsc +2 -2
  55. package/.next/standalone/.next/server/app/admin/companies/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/admin/companies.html +2 -2
  57. package/.next/standalone/.next/server/app/admin/companies.rsc +2 -2
  58. package/.next/standalone/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/admin.html +2 -2
  60. package/.next/standalone/.next/server/app/admin.rsc +2 -2
  61. package/.next/standalone/.next/server/app/api/admin/companies/[uuid]/route_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/api/admin/companies/route_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/api/admin/login/route_client-reference-manifest.js +1 -1
  64. package/.next/standalone/.next/server/app/api/admin/session/route_client-reference-manifest.js +1 -1
  65. package/.next/standalone/.next/server/app/api/agent-connections/route_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/api/agents/[uuid]/route_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route_client-reference-manifest.js +1 -1
  68. package/.next/standalone/.next/server/app/api/agents/route_client-reference-manifest.js +1 -1
  69. package/.next/standalone/.next/server/app/api/api-keys/[uuid]/route_client-reference-manifest.js +1 -1
  70. package/.next/standalone/.next/server/app/api/api-keys/route_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/api/auth/callback/route_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/api/auth/check-default/route_client-reference-manifest.js +1 -1
  73. package/.next/standalone/.next/server/app/api/auth/company-oidc/route_client-reference-manifest.js +1 -1
  74. package/.next/standalone/.next/server/app/api/auth/default-login/route_client-reference-manifest.js +1 -1
  75. package/.next/standalone/.next/server/app/api/auth/identify/route_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -1
  78. package/.next/standalone/.next/server/app/api/auth/sync-token/route_client-reference-manifest.js +1 -1
  79. package/.next/standalone/.next/server/app/api/comments/route_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/api/daemon/connection-heartbeat/route_client-reference-manifest.js +1 -1
  81. package/.next/standalone/.next/server/app/api/daemon/control/route.js +1 -1
  82. package/.next/standalone/.next/server/app/api/daemon/control/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/daemon/control/route_client-reference-manifest.js +1 -1
  84. package/.next/standalone/.next/server/app/api/daemon/directory-request/report/route_client-reference-manifest.js +1 -1
  85. package/.next/standalone/.next/server/app/api/daemon/execution-state/route_client-reference-manifest.js +1 -1
  86. package/.next/standalone/.next/server/app/api/daemon/executions/route_client-reference-manifest.js +1 -1
  87. package/.next/standalone/.next/server/app/api/daemon/pending-turns/route_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route_client-reference-manifest.js +1 -1
  89. package/.next/standalone/.next/server/app/api/daemon/resume/route_client-reference-manifest.js +1 -1
  90. package/.next/standalone/.next/server/app/api/daemon/transcript/route_client-reference-manifest.js +1 -1
  91. package/.next/standalone/.next/server/app/api/daemon/turn-advance/route_client-reference-manifest.js +1 -1
  92. package/.next/standalone/.next/server/app/api/daemon-directory-requests/[uuid]/route_client-reference-manifest.js +1 -1
  93. package/.next/standalone/.next/server/app/api/daemon-directory-requests/route_client-reference-manifest.js +1 -1
  94. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route_client-reference-manifest.js +1 -1
  95. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route_client-reference-manifest.js +1 -1
  96. package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route_client-reference-manifest.js +1 -1
  97. package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route_client-reference-manifest.js +1 -1
  98. package/.next/standalone/.next/server/app/api/daemon-sessions/route_client-reference-manifest.js +1 -1
  99. package/.next/standalone/.next/server/app/api/documents/[uuid]/route_client-reference-manifest.js +1 -1
  100. package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route_client-reference-manifest.js +1 -1
  101. package/.next/standalone/.next/server/app/api/events/notifications/route_client-reference-manifest.js +1 -1
  102. package/.next/standalone/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
  103. package/.next/standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route_client-reference-manifest.js +1 -1
  105. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route_client-reference-manifest.js +1 -1
  106. package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route_client-reference-manifest.js +1 -1
  107. package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route_client-reference-manifest.js +1 -1
  108. package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route_client-reference-manifest.js +1 -1
  109. package/.next/standalone/.next/server/app/api/ideas/[uuid]/route_client-reference-manifest.js +1 -1
  110. package/.next/standalone/.next/server/app/api/ideas/[uuid]/wake-preview/route_client-reference-manifest.js +1 -1
  111. package/.next/standalone/.next/server/app/api/ideas/conversational/route_client-reference-manifest.js +1 -1
  112. package/.next/standalone/.next/server/app/api/mcp/route_client-reference-manifest.js +1 -1
  113. package/.next/standalone/.next/server/app/api/me/assignments/route_client-reference-manifest.js +1 -1
  114. package/.next/standalone/.next/server/app/api/mentionables/route_client-reference-manifest.js +1 -1
  115. package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route_client-reference-manifest.js +1 -1
  117. package/.next/standalone/.next/server/app/api/notifications/preferences/route_client-reference-manifest.js +1 -1
  118. package/.next/standalone/.next/server/app/api/notifications/read-all/route_client-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/app/api/notifications/unread-count/route_client-reference-manifest.js +1 -1
  121. package/.next/standalone/.next/server/app/api/project-groups/[uuid]/dashboard/route_client-reference-manifest.js +1 -1
  122. package/.next/standalone/.next/server/app/api/project-groups/[uuid]/route_client-reference-manifest.js +1 -1
  123. package/.next/standalone/.next/server/app/api/project-groups/route_client-reference-manifest.js +1 -1
  124. package/.next/standalone/.next/server/app/api/project-visits/pin/route_client-reference-manifest.js +1 -1
  125. package/.next/standalone/.next/server/app/api/project-visits/route_client-reference-manifest.js +1 -1
  126. package/.next/standalone/.next/server/app/api/project-visits/visit/route_client-reference-manifest.js +1 -1
  127. package/.next/standalone/.next/server/app/api/projects/[uuid]/activity/route_client-reference-manifest.js +1 -1
  128. package/.next/standalone/.next/server/app/api/projects/[uuid]/agent-cwds/route_client-reference-manifest.js +1 -1
  129. package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route_client-reference-manifest.js +1 -1
  130. package/.next/standalone/.next/server/app/api/projects/[uuid]/documents/route_client-reference-manifest.js +1 -1
  131. package/.next/standalone/.next/server/app/api/projects/[uuid]/group/route_client-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route_client-reference-manifest.js +1 -1
  133. package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route_client-reference-manifest.js +1 -1
  134. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/[proposalUuid]/validate/route_client-reference-manifest.js +1 -1
  135. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/route_client-reference-manifest.js +1 -1
  136. package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/summary/route_client-reference-manifest.js +1 -1
  137. package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route_client-reference-manifest.js +1 -1
  138. package/.next/standalone/.next/server/app/api/projects/[uuid]/route_client-reference-manifest.js +1 -1
  139. package/.next/standalone/.next/server/app/api/projects/[uuid]/stats/route_client-reference-manifest.js +1 -1
  140. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route_client-reference-manifest.js +1 -1
  141. package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route_client-reference-manifest.js +1 -1
  142. package/.next/standalone/.next/server/app/api/projects/agent-cwd-options/route_client-reference-manifest.js +1 -1
  143. package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  144. package/.next/standalone/.next/server/app/api/proposals/[uuid]/approve/route_client-reference-manifest.js +1 -1
  145. package/.next/standalone/.next/server/app/api/proposals/[uuid]/close/route_client-reference-manifest.js +1 -1
  146. package/.next/standalone/.next/server/app/api/proposals/[uuid]/reject/route_client-reference-manifest.js +1 -1
  147. package/.next/standalone/.next/server/app/api/proposals/[uuid]/revoke/route_client-reference-manifest.js +1 -1
  148. package/.next/standalone/.next/server/app/api/proposals/[uuid]/route_client-reference-manifest.js +1 -1
  149. package/.next/standalone/.next/server/app/api/references/[uuid]/route_client-reference-manifest.js +1 -1
  150. package/.next/standalone/.next/server/app/api/references/route_client-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  152. package/.next/standalone/.next/server/app/api/session/route_client-reference-manifest.js +1 -1
  153. package/.next/standalone/.next/server/app/api/sessions/[uuid]/route_client-reference-manifest.js +1 -1
  154. package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route_client-reference-manifest.js +1 -1
  155. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route_client-reference-manifest.js +1 -1
  156. package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route_client-reference-manifest.js +1 -1
  157. package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route_client-reference-manifest.js +1 -1
  158. package/.next/standalone/.next/server/app/api/tasks/[uuid]/route_client-reference-manifest.js +1 -1
  159. package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route_client-reference-manifest.js +1 -1
  160. package/.next/standalone/.next/server/app/index.html +2 -2
  161. package/.next/standalone/.next/server/app/index.rsc +2 -2
  162. package/.next/standalone/.next/server/app/login/admin/page_client-reference-manifest.js +1 -1
  163. package/.next/standalone/.next/server/app/login/admin.html +2 -2
  164. package/.next/standalone/.next/server/app/login/admin.rsc +2 -2
  165. package/.next/standalone/.next/server/app/login/callback/page_client-reference-manifest.js +1 -1
  166. package/.next/standalone/.next/server/app/login/callback.html +2 -2
  167. package/.next/standalone/.next/server/app/login/callback.rsc +2 -2
  168. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  169. package/.next/standalone/.next/server/app/login/pick-workspace/page_client-reference-manifest.js +1 -1
  170. package/.next/standalone/.next/server/app/login/pick-workspace.html +2 -2
  171. package/.next/standalone/.next/server/app/login/pick-workspace.rsc +2 -2
  172. package/.next/standalone/.next/server/app/login.html +2 -2
  173. package/.next/standalone/.next/server/app/login.rsc +2 -2
  174. package/.next/standalone/.next/server/app/onboarding/page.js +2 -2
  175. package/.next/standalone/.next/server/app/onboarding/page.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
  177. package/.next/standalone/.next/server/app/onboarding.html +2 -2
  178. package/.next/standalone/.next/server/app/onboarding.rsc +3 -3
  179. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  180. package/.next/standalone/.next/server/app/projects.html +2 -2
  181. package/.next/standalone/.next/server/app/projects.rsc +3 -3
  182. package/.next/standalone/.next/server/app/settings.html +2 -2
  183. package/.next/standalone/.next/server/app/settings.rsc +4 -4
  184. package/.next/standalone/.next/server/app-paths-manifest.json +41 -41
  185. package/.next/standalone/.next/server/chunks/1318.js +1 -1
  186. package/.next/standalone/.next/server/chunks/{5201.js → 1416.js} +2 -2
  187. package/.next/standalone/.next/server/chunks/1559.js +2 -2
  188. package/.next/standalone/.next/server/chunks/{4810.js → 1683.js} +1 -1
  189. package/.next/standalone/.next/server/chunks/2572.js +2 -2
  190. package/.next/standalone/.next/server/chunks/2961.js +1 -1
  191. package/.next/standalone/.next/server/chunks/3112.js +1 -1
  192. package/.next/standalone/.next/server/chunks/3341.js +1 -0
  193. package/.next/standalone/.next/server/chunks/3419.js +1 -1
  194. package/.next/standalone/.next/server/chunks/5245.js +1 -1
  195. package/.next/standalone/.next/server/chunks/6113.js +1 -1
  196. package/.next/standalone/.next/server/chunks/6506.js +1 -1
  197. package/.next/standalone/.next/server/chunks/6607.js +1 -0
  198. package/.next/standalone/.next/server/chunks/6737.js +1 -1
  199. package/.next/standalone/.next/server/chunks/6753.js +3 -3
  200. package/.next/standalone/.next/server/chunks/679.js +1 -1
  201. package/.next/standalone/.next/server/chunks/7368.js +1 -1
  202. package/.next/standalone/.next/server/chunks/7400.js +1 -0
  203. package/.next/standalone/.next/server/chunks/7530.js +1 -1
  204. package/.next/standalone/.next/server/chunks/7578.js +2 -2
  205. package/.next/standalone/.next/server/chunks/7789.js +1 -0
  206. package/.next/standalone/.next/server/chunks/8185.js +1 -0
  207. package/.next/standalone/.next/server/chunks/920.js +1 -1
  208. package/.next/standalone/.next/server/chunks/9213.js +1 -1
  209. package/.next/standalone/.next/server/chunks/9378.js +1 -1
  210. package/.next/standalone/.next/server/chunks/{3619.js → 9848.js} +2 -2
  211. package/.next/standalone/.next/server/chunks/9931.js +1 -1
  212. package/.next/standalone/.next/server/instrumentation.js +1 -1
  213. package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
  214. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  215. package/.next/standalone/.next/server/pages/404.html +2 -2
  216. package/.next/standalone/.next/server/pages/500.html +1 -1
  217. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  218. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  219. package/.next/standalone/.next/static/chunks/11595.f080a1d100972212.js +1 -0
  220. package/.next/standalone/.next/static/chunks/{29305-f587e7e81bc0b200.js → 17562-56f932146e9e6c94.js} +4 -4
  221. package/.next/standalone/.next/static/chunks/18751-3616e33050e9611e.js +1 -0
  222. package/.next/standalone/.next/static/chunks/26020-7b4756ba0aa906cf.js +1 -0
  223. package/.next/standalone/.next/static/chunks/33456.20313bd67a5c41cc.js +1 -0
  224. package/.next/standalone/.next/static/chunks/44437-d13183f50281116f.js +1 -0
  225. package/.next/standalone/.next/static/chunks/4860.3b555a398cdffb19.js +1 -0
  226. package/.next/standalone/.next/static/chunks/59713-426f81b6576173d8.js +1 -0
  227. package/.next/standalone/.next/static/chunks/60351-bdef539874e5027e.js +1 -0
  228. package/.next/standalone/.next/static/chunks/79919-1e7e294a06f2c4a0.js +1 -0
  229. package/.next/standalone/.next/static/chunks/94643-e54eff17e941a93b.js +1 -0
  230. package/.next/standalone/.next/static/chunks/99373.b8a95d1bec5ad4e7.js +1 -0
  231. package/.next/standalone/.next/static/chunks/99733-5a2e39f57fbda32d.js +1 -0
  232. package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-072a6b8f0a48b1b6.js +1 -0
  233. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-198a3ff89ae871b9.js +1 -0
  234. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-a506de82e8997714.js +1 -0
  235. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/{page-800a979f12b73f27.js → page-dc54fafa22d21863.js} +1 -1
  236. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/{page-34de35f75aa71f6d.js → page-6eb5d3cb036a78e0.js} +1 -1
  237. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-69c6f0190623e19b.js +1 -0
  238. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-2a52f747e6fac5a7.js +1 -0
  239. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-22cce567a85ea291.js +1 -0
  240. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/{page-349b0977f3c6209a.js → page-301f21a3ae52e318.js} +1 -1
  241. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-be43cb06112fce12.js → page-dd123990c14e9768.js} +1 -1
  242. package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-548231f8c9856489.js +1 -0
  243. package/.next/standalone/.next/static/chunks/app/onboarding/{page-c0090caae202eae5.js → page-5914ff3d878a3c34.js} +1 -1
  244. package/.next/standalone/.next/static/chunks/{webpack-cfb63dd1b416c92e.js → webpack-de8a36d232a91d6b.js} +1 -1
  245. package/.next/standalone/.next/static/css/44f13b43a3de716d.css +1 -0
  246. package/.next/standalone/package.json +1 -1
  247. package/.next/standalone/public/chorus-plugin/.claude-plugin/plugin.json +1 -1
  248. package/.next/standalone/public/chorus-plugin/agents/code-reviewer.md +63 -6
  249. package/.next/standalone/public/chorus-plugin/agents/proposal-reviewer.md +60 -6
  250. package/.next/standalone/public/chorus-plugin/agents/task-reviewer.md +75 -8
  251. package/.next/standalone/public/chorus-plugin/bin/chorus-api.sh +1 -1
  252. package/.next/standalone/public/chorus-plugin/bin/on-pre-spawn-agent.sh +22 -9
  253. package/.next/standalone/public/chorus-plugin/bin/on-subagent-start.sh +44 -29
  254. package/.next/standalone/public/chorus-plugin/bin/on-subagent-stop.sh +100 -29
  255. package/.next/standalone/public/chorus-plugin/bin/test-syntax.sh +6 -2
  256. package/.next/standalone/public/chorus-plugin/bin/tests/test-subagent-session-name.sh +599 -0
  257. package/.next/standalone/public/chorus-plugin/skills/brainstorm/SKILL.md +1 -1
  258. package/.next/standalone/public/chorus-plugin/skills/chorus/SKILL.md +1 -1
  259. package/.next/standalone/public/chorus-plugin/skills/chorus-cli/SKILL.md +1 -1
  260. package/.next/standalone/public/chorus-plugin/skills/develop/SKILL.md +1 -1
  261. package/.next/standalone/public/chorus-plugin/skills/docs/SKILL.md +1 -1
  262. package/.next/standalone/public/chorus-plugin/skills/idea/SKILL.md +1 -1
  263. package/.next/standalone/public/chorus-plugin/skills/openspec-aware/SKILL.md +1 -1
  264. package/.next/standalone/public/chorus-plugin/skills/orchestrate/SKILL.md +1 -1
  265. package/.next/standalone/public/chorus-plugin/skills/proposal/SKILL.md +1 -1
  266. package/.next/standalone/public/chorus-plugin/skills/quick-dev/SKILL.md +1 -1
  267. package/.next/standalone/public/chorus-plugin/skills/review/SKILL.md +1 -1
  268. package/.next/standalone/public/chorus-plugin/skills/spec-lite/SKILL.md +1 -1
  269. package/.next/standalone/public/chorus-plugin/skills/yolo/SKILL.md +1 -1
  270. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-code-reviewer.json +56 -1
  271. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-proposal-reviewer.json +79 -1
  272. package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-task-reviewer.json +56 -1
  273. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-brainstorm/SKILL.md +1 -1
  274. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-cli/SKILL.md +1 -1
  275. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-develop/SKILL.md +1 -1
  276. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-docs/SKILL.md +1 -1
  277. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-idea/SKILL.md +1 -1
  278. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-openspec-aware/SKILL.md +1 -1
  279. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-orchestrate/SKILL.md +1 -1
  280. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-proposal/SKILL.md +1 -1
  281. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-quick-dev/SKILL.md +1 -1
  282. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-review/SKILL.md +1 -1
  283. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-spec-lite/SKILL.md +1 -1
  284. package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-yolo/SKILL.md +1 -1
  285. package/.next/standalone/public/kiro-plugin/bin/chorus-api.sh +1 -1
  286. package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +60 -4
  287. package/.next/standalone/public/skill/proposal-reviewer-chorus/SKILL.md +58 -5
  288. package/.next/standalone/public/skill/task-reviewer-chorus/SKILL.md +72 -6
  289. package/README.ja.md +3 -1
  290. package/README.ko.md +3 -1
  291. package/README.md +3 -1
  292. package/README.zh.md +3 -1
  293. package/chorus.mjs +30 -2
  294. package/cli/child-exit.mjs +77 -0
  295. package/cli/claude-spawner.mjs +4 -1
  296. package/cli/codex-spawner.mjs +4 -1
  297. package/cli/control-handler.mjs +104 -6
  298. package/cli/daemon-rest-client.mjs +98 -29
  299. package/cli/daemon.mjs +5 -1
  300. package/cli/dsh-spawner.mjs +4 -1
  301. package/cli/kiro-spawner.mjs +4 -1
  302. package/cli/pi-spawner.mjs +4 -1
  303. package/package.json +1 -1
  304. package/.next/standalone/.next/server/chunks/109.js +0 -1
  305. package/.next/standalone/.next/server/chunks/1496.js +0 -1
  306. package/.next/standalone/.next/server/chunks/731.js +0 -1
  307. package/.next/standalone/.next/server/chunks/7857.js +0 -1
  308. package/.next/standalone/.next/static/chunks/11595.0afa1a540f681fb4.js +0 -1
  309. package/.next/standalone/.next/static/chunks/22705-324a191727ae45b7.js +0 -1
  310. package/.next/standalone/.next/static/chunks/33456.4a5f4712a7e78d8f.js +0 -1
  311. package/.next/standalone/.next/static/chunks/44216-3876e84f5b02d355.js +0 -1
  312. package/.next/standalone/.next/static/chunks/4860.5719e32b95be2d93.js +0 -1
  313. package/.next/standalone/.next/static/chunks/6528-a8a562ef7d26bb43.js +0 -1
  314. package/.next/standalone/.next/static/chunks/67439-7b339b28ed0ecfc6.js +0 -1
  315. package/.next/standalone/.next/static/chunks/79919-ae8bd8d8ec1e38ce.js +0 -1
  316. package/.next/standalone/.next/static/chunks/82203-4ce5926624df7ed0.js +0 -1
  317. package/.next/standalone/.next/static/chunks/94643-37ac7b8ef8ea5e75.js +0 -1
  318. package/.next/standalone/.next/static/chunks/99373.6c1509bfaf599741.js +0 -1
  319. package/.next/standalone/.next/static/chunks/99775-697e82ee04eac6b1.js +0 -1
  320. package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-2fda722cdace8147.js +0 -1
  321. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-b45c42c536eff64b.js +0 -1
  322. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-792aba7fd6b6daa3.js +0 -1
  323. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-a16002aa2a911619.js +0 -1
  324. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-e8030824994edf35.js +0 -1
  325. package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-4f7f1ddbaf79be8f.js +0 -1
  326. package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-6916e1abab42a6e6.js +0 -1
  327. package/.next/standalone/.next/static/css/75c761a5428611fa.css +0 -1
  328. /package/.next/standalone/.next/static/{IxKVu5zkFPTjSKAUR99yH → Pmji9kEq8T2lM6AKQkZji}/_buildManifest.js +0 -0
  329. /package/.next/standalone/.next/static/{IxKVu5zkFPTjSKAUR99yH → Pmji9kEq8T2lM6AKQkZji}/_ssgManifest.js +0 -0
@@ -114,14 +114,62 @@ Classify **every** finding as exactly one of:
114
114
 
115
115
  **Rules:** Pseudocode inconsistencies → **always NOTE**. Cross-document wording differences → **always NOTE**. Only semantic contradictions → BLOCKER.
116
116
 
117
+ Give every finding a stable ID: BLOCKER titles are `B<round>-<slug>`, NOTE entries are `N<round>-<slug>`, where <round> is the round that FIRST reported it — never renamed or renumbered in later rounds.
118
+ Round 2+ MUST also acknowledge every prior BLOCKER and every prior NOTE by ID with exactly one of three states — `fixed` / `still-open` / `not-verifiable` — plus what you actually re-ran or re-read. Silence is not a fix: only an explicit `fixed` closes a finding. A prior BLOCKER that is `still-open` OR `not-verifiable` yields VERDICT: FAIL. An unresolved NOTE never yields worse than PASS WITH NOTES.
119
+
117
120
  ---
118
121
 
122
+ ## What to report / what NOT to report
123
+
124
+ This list is specific to the proposal gate. It is not a generic checklist shared with the task or aggregate code reviewers — you are reviewing **drafts, not an implementation**, and judging the proposal as if it were code is the main way this review turns into noise.
125
+
126
+ **DO report:**
127
+ - Requirements that are not traceable to human-authored intent, and human-stated intent that no requirement carries.
128
+ - Acceptance criteria that are not machine-verifiable by a different agent.
129
+ - Task granularity problems and an unsound dependency DAG (wrong edges, cycles, a task that cannot start when its dependencies are done).
130
+ - A missing integration checkpoint once the DAG has 4+ tasks.
131
+ - Hallucination-risk specifics in the drafts (SDK versions, API paths, CLI flags, model IDs) → NOTE.
132
+
133
+ **DO NOT report:**
134
+ - **Never report something as missing without first confirming its absence with read-only Bash** (`ls` / `grep` / `rg` / `find` / `git ls-files`), and cite what you checked. An unverified "X is missing" is the single most common false BLOCKER.
135
+ - **Do not report document wording or formatting.** Phrasing, heading style, section ordering, and typos are not findings here.
136
+ - **Do not report that "the implementation detail isn't specific enough."** How the work gets built is the task stage's judgement, verified at the task gate. A proposal is not required to pre-specify implementation.
137
+ - **Do not propose alternative architectures.** Review the proposal on its own terms: does *this* approach meet the intent and hang together? A different design you would have preferred is not a finding.
138
+ - **Do not report future extensibility.** "This won't scale to a use case nobody asked for" is out of scope.
139
+
119
140
  ## Round 2+ Awareness
120
141
 
121
142
  You may receive the current review round number in your context.
122
143
 
123
144
  - **Round 1** — Full review at normal strictness.
124
- - **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth draft review. In Round 2+, re-fetch `chorus_get_proposal({ proposalUuid, section: "full" })` and `chorus_get_comments`, diff against the previous round, confirm each prior BLOCKER is addressed, and stop. If all previous BLOCKERs are resolved → `VERDICT: PASS` (or `VERDICT: PASS WITH NOTES` if old NOTEs remain).
145
+ - **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth draft review. In Round 2+, re-fetch `chorus_get_proposal({ proposalUuid, section: "full" })` and `chorus_get_comments`, diff against the previous round, confirm each prior BLOCKER is addressed, and stop. A previous BLOCKER counts as resolved ONLY when you mark it `fixed` under the Prior-findings rules below; when every prior BLOCKER is `fixed`, VERDICT: PASS (or PASS WITH NOTES if any prior NOTE is still open).
146
+
147
+ ## Prior findings: stable IDs and cross-round acknowledgement
148
+
149
+ **Stable IDs.** Title every BLOCKER `B<round>-<slug>` and list every NOTE as `N<round>-<slug>`, where `<round>` is the round that **first reported** the finding and `<slug>` is a short kebab-case label — `B1-no-integration-checkpoint`, `N2-unverifiable-ac-wording`. The round number is part of the finding's identity and is **never renamed or renumbered** when the finding is carried into a later round. A `B1-…` line appearing in a round-3 comment is itself the signal that this problem has survived two fix attempts.
150
+
151
+ **Acknowledgement.** In round 2 and later, list **every** prior BLOCKER and **every** prior NOTE by ID under a `**Prior findings:**` block, each with exactly one of these three states and with what you actually re-read or re-ran this round:
152
+
153
+ - `fixed` — re-verified this round; cite the draft section (or read-only command) and what it now says.
154
+ - `still-open` — re-checked, and the problem is still there.
155
+ - `not-verifiable` — could not check it this round; say why (the relevant draft was not returned, no shell for the check the finding needs). Never counts as fixed.
156
+
157
+ Those three states are the whole vocabulary — there is no fourth state, and the same three words apply to BLOCKERs and NOTEs alike.
158
+
159
+ Three rules govern what the states mean for the verdict:
160
+
161
+ - **Silence is not a fix.** Not re-reporting a finding does not close it. Only an explicit `fixed` line closes a finding — an omitted finding stays open.
162
+ - **A prior BLOCKER whose state is `still-open` or `not-verifiable` yields `VERDICT: FAIL`.** Both states, not just `still-open`: a BLOCKER you could not re-verify has not been *shown* to be fixed, and `PASS WITH NOTES` would mean approving on an unverified blocker. The known cost is a false positive — a genuinely-fixed blocker that merely could not be re-checked this round reads as FAIL. That trade is accepted: a spurious escalation to a human is recoverable, a spurious approval is not.
163
+ - **NOTEs never escalate.** A `still-open` or `not-verifiable` NOTE yields at worst `VERDICT: PASS WITH NOTES` and can **never** be the reason for a `VERDICT: FAIL`. Only BLOCKERs block.
164
+
165
+ **How the NOTE limit composes with the round-2+ rule above.** These are two separate rules and they never apply to the same NOTEs:
166
+
167
+ | | Newly-raised NOTEs | Carried-forward acknowledgement lines |
168
+ |---|---|---|
169
+ | Round 1 | at most 5 — past 5, drop the least relevant | none exist yet |
170
+ | Round 2+ | **zero** — Round awareness above already forbids new NOTEs | **all of them, written in full, never limited** |
171
+
172
+ So the limit of 5 governs newly-raised NOTEs **only**. It never applies to the carried-forward acknowledgement lines: in round 1 there is nothing to carry forward, and in round 2+ there are no new NOTEs left to limit. Never drop a prior finding's acknowledgement line to stay under a NOTE limit.
125
173
 
126
174
  ---
127
175
 
@@ -157,19 +205,24 @@ Do NOT invent other verdicts like "APPROVE" or "OK" — automation greps for the
157
205
 
158
206
  ## Output Format (Required)
159
207
 
160
- Keep total output **under ~800 characters** — be concise. No preamble, no trailing summary paragraph. PASS items: names only. NOTE items: one-line descriptions. BLOCKER items: full evidence.
208
+ BLOCKER evidence is unbounded, so never truncate it to shorten the comment; report at most 5 newly-raised NOTEs and drop the least relevant beyond that. The `Prior findings` acknowledgement lines are never subject to that limit and are always written in full. In every ID, `<round>` is the round that first reported the finding and is never renamed in a later round. No preamble, no trailing summary paragraph. PASS items: names only. NOTE items: one-line descriptions. BLOCKER items: full evidence.
161
209
 
162
210
  ```
163
211
  ### Review Summary
164
212
 
213
+ **Prior findings:** (round 2+ only — omit this block in round 1)
214
+ - B1-<slug>: fixed — `<what you re-ran or re-read>` → <result observed>
215
+ - B1-<other-slug>: still-open — `<what you re-ran or re-read>` → <problem still present>
216
+ - B2-<slug>: not-verifiable — <why you could not check it this round>
217
+ - N1-<slug>: still-open
165
218
  **PASS (N):** Check-1 name, Check-2 name, ...
166
219
 
167
220
  **NOTE (M):**
168
- - Note-1: [one-line description]
169
- - Note-2: [one-line description]
221
+ - N<round>-<slug>: [one-line description]
222
+ - N<round>-<slug>: [one-line description]
170
223
 
171
224
  **BLOCKER (K):**
172
- ### Blocker-1: name
225
+ ### B<round>-<slug>
173
226
  **Evidence:** [specific finding]
174
227
  **Expected:** [what should be there]
175
228
  **Actual:** [what is there or what is missing]
@@ -107,6 +107,19 @@ Pick 2-3 probes that fit the specific task — boundary values, missing fields,
107
107
 
108
108
  **Hallucination check:** Flag anything that looks LLM-fabricated as a **NOTE** — API signatures, CLI flags, config keys, model IDs, endpoint URLs, package names, or any external detail the developer likely wrote from memory rather than referencing docs.
109
109
 
110
+ **Code quality and correctness beyond the AC — checked by default**
111
+
112
+ The AC were written before the code existed: they describe what to build, never how well it was built. Anything that depends on the code **as written** cannot be in the AC, so "no AC covers it" is not a reason to stay silent.
113
+
114
+ - **Correctness without an AC.** Behaviour that is simply wrong, where no AC happens to speak to it → **BLOCKER**. You do not need an acceptance criterion to report a bug.
115
+ - **Reimplementation.** Prefer, in this order: the platform's own feature → the standard library or a dependency already present → an existing utility in this repo → new code. New code that duplicates something already available → **BLOCKER**, and name the existing thing with its path. "This could be shorter" with nothing named is not a finding.
116
+ - **Security in this task's own code.** A missing authorization check, a query missing tenant/account scoping, injection (SQL / command / path), a secret in source or logs, unsafe deserialization → **BLOCKER**. Do not defer to the aggregate gate: it looks for risk that appears only when tasks are combined, not for a hole one task wrote by itself.
117
+ - **Tests that cannot fail.** Ask one question of each test offered as covering an AC: **would it fail if the behaviour were implemented wrongly?** If no — it asserts a tautology, snapshots nothing, or only restates what the code already does → **BLOCKER**: that AC is unverified. Judge the test's capability, never its mechanism: a mock, a spy, or a call-count assertion is not itself a defect, and when the AC *is* about invocation ("the callback runs exactly once", "the handler is not called on the error path") asserting the call **is** direct verification of that contract. Thin-but-real tests → NOTE.
118
+ - **Silent failure.** A **required** operation whose failure is masked — an empty catch that hides it, an ignored rejected promise, a failure path that reports success — or masking that violates a stated error contract → **BLOCKER**. Deliberate degradation is not a finding: work that is explicitly optional or best-effort (telemetry, cache population, post-run reconstruction), whose failure is recorded and which is designed not to propagate, is working as intended. Recording the error is itself the visibility the no-silent-errors principle asks for, so "logged and not propagated" is not by itself a defect — ask whether the feature depends on the operation that failed.
119
+ - **Maintainability, leftovers, diff hygiene → NOTE:** a function doing several unrelated things, deep nesting, copy-pasted blocks inside this diff, unnamed magic values; unused imports/exports, commented-out code, debug logging, TODOs this task introduced; changes unrelated to this task bundled into the same diff; `any` or unchecked nullables on the interface this task owns; a query inside a loop or an unbounded fetch. Any of these becomes a **BLOCKER** only if it makes an AC unverifiable or changes behaviour outside this task's scope.
120
+
121
+ **Severity rule.** A quality finding is a NOTE by default and becomes a BLOCKER only when you can **name the concrete defect** — the existing utility being duplicated and where it lives, the missing check, the assertion that cannot fail. Taste never blocks: if you cannot point at it, it is a NOTE or it is nothing. Report the cheapest concrete change, never a redesign.
122
+
110
123
  ### Step 6: Intent Alignment
111
124
 
112
125
  Resolve the originating Idea (this task's proposal → `inputUuids[0]`) and read its body + human-answered elaboration + human-authored comments (`answeredBy.type` / `author.type == "user"`; agent-authored entries are audit context, not intent). Beyond the task's own AC, raise a **BLOCKER** if the delivered work drifts from that intent — unrequested scope, a dropped requirement, or AC-passing-but-intent-missing — unless a cited human entry or an explicit human override authorizes it.
@@ -140,16 +153,64 @@ Classify **every** finding as exactly one of:
140
153
  - Style / naming suggestions.
141
154
  - Hallucination-risk specifics (SDK versions, API paths, CLI flags, model IDs).
142
155
 
143
- **Rules:** Pseudocode inconsistencies → **always NOTE**. Cross-document wording differences → **always NOTE**. Only functional / behavioral issues → BLOCKER.
156
+ **Rules:** Style, naming, and pseudocode inconsistencies → **always NOTE**. Functional, security, and verification-integrity issues → BLOCKER. A quality finding blocks only when you can name the concrete defect.
157
+
158
+ Give every finding a stable ID: BLOCKER titles are `B<round>-<slug>`, NOTE entries are `N<round>-<slug>`, where <round> is the round that FIRST reported it — never renamed or renumbered in later rounds.
159
+ Round 2+ MUST also acknowledge every prior BLOCKER and every prior NOTE by ID with exactly one of three states — `fixed` / `still-open` / `not-verifiable` — plus what you actually re-ran or re-read. Silence is not a fix: only an explicit `fixed` closes a finding. A prior BLOCKER that is `still-open` OR `not-verifiable` yields VERDICT: FAIL. An unresolved NOTE never yields worse than PASS WITH NOTES.
144
160
 
145
161
  ---
146
162
 
163
+ ## What to report / what NOT to report
164
+
165
+ This list is specific to the task gate. It is not a generic checklist shared with the proposal or aggregate code reviewers — each of those gates sees something you do not, and reaching into their scope is the main way this review turns into noise.
166
+
167
+ **DO report:**
168
+ - The result of running this task's tests/build, quoting the real output — exact command, exit code, the relevant lines.
169
+ - **Match your evidence to the KIND of claim; never lower a finding's severity just because you could not run something.** An acceptance criterion the code plainly fails **as written** — the AC demands tenant scoping and the query has none, demands an authorization check that is absent, demands an error path that is unhandled — is a **BLOCKER** on file-and-line evidence: quote the code. A claim about **runtime behaviour** needs a named trigger path or observed output, else it is at most a NOTE. Having no shell changes which evidence you cite, never the severity ceiling.
170
+ - Judgements made against **this task's AC and this task's diff**, and nothing wider — with one explicit exception: the intent-alignment step above. Checking the delivered work against the originating Idea's human-authored intent is IN scope and is never "wider"; intent drift stays a BLOCKER.
171
+ - An acceptance criterion that is not actually covered by the implementation → BLOCKER.
172
+ - Behaviour that contradicts the approved proposal documents the task was built from.
173
+
174
+ **DO NOT report:**
175
+ - **Never report something as missing without first confirming its absence with read-only Bash** (`ls` / `grep` / `rg` / `find` / `git ls-files`), and cite the command you ran. An unverified "X is missing" is the single most common false BLOCKER.
176
+ - **Do not re-litigate decisions inside an already-approved proposal.** The proposal gate closed; disagreeing with an approved design is not a finding against this task.
177
+ - **Do not report pre-existing problems this task never touched** — unless this task's change makes one reachable, worse, or newly load-bearing, which makes it this change's problem and in scope. If the task's diff did not introduce it, it is not this review's finding.
178
+ - **Do not report gaps that belong to a different task** — the aggregate code reviewer owns inter-task gaps and will see it at the feature level. Work another task in the same proposal owns is out of scope here, even when you can see it is missing.
179
+ - **Never raise a BLOCKER for absent end-to-end integration tests.** Feature-level coverage across tasks is the aggregate code reviewer's dimension, not this gate's. This task's own AC is the standard here.
180
+
147
181
  ## Round 2+ Awareness
148
182
 
149
183
  You may receive the current review round number in your context.
150
184
 
151
185
  - **Round 1** — Full review at normal strictness.
152
- - **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth review. In Round 2+, re-read only the specific files and re-run only the specific tests/commands tied to previous BLOCKERs — do not re-scan unrelated code, do not rerun the full suite, and do not probe new areas. If all previous BLOCKERs are resolved → `VERDICT: PASS` (or `VERDICT: PASS WITH NOTES` if old NOTEs remain). Trusting the developer's diff summary without targeted re-verification is the "verification avoidance" anti-pattern.
186
+ - **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth review. In Round 2+, re-read only the specific files and re-run only the specific tests/commands tied to prior findings (BLOCKERs and NOTEs alike — a prior NOTE you may not re-read is a NOTE you can never close) — do not re-scan unrelated code, do not rerun the full suite, and do not probe new areas. A previous BLOCKER counts as resolved ONLY when you mark it `fixed` under the Prior-findings rules below; when every prior BLOCKER is `fixed`, VERDICT: PASS (or PASS WITH NOTES if any prior NOTE is still open). Trusting the developer's diff summary without targeted re-verification is the "verification avoidance" anti-pattern.
187
+
188
+ ## Prior findings: stable IDs and cross-round acknowledgement
189
+
190
+ **Stable IDs.** Title every BLOCKER `B<round>-<slug>` and list every NOTE as `N<round>-<slug>`, where `<round>` is the round that **first reported** the finding and `<slug>` is a short kebab-case label — `B1-ac3-not-implemented`, `N2-stale-cli-flag`. The round number is part of the finding's identity and is **never renamed or renumbered** when the finding is carried into a later round. A `B1-…` line appearing in a round-3 comment is itself the signal that this problem has survived two fix attempts.
191
+
192
+ **Acknowledgement.** In round 2 and later, list **every** prior BLOCKER and **every** prior NOTE by ID under a `**Prior findings:**` block, each with exactly one of these three states and with the command you actually re-ran this round:
193
+
194
+ - `fixed` — re-verified this round; cite the command and its result.
195
+ - `still-open` — re-checked, and the problem is still there.
196
+ - `not-verifiable` — could not check it this round; say why (missing dependency, no database, environment read-only). Never counts as fixed.
197
+
198
+ Those three states are the whole vocabulary — there is no fourth state, and the same three words apply to BLOCKERs and NOTEs alike.
199
+
200
+ Three rules govern what the states mean for the verdict:
201
+
202
+ - **Silence is not a fix.** Not re-reporting a finding does not close it. Only an explicit `fixed` line closes a finding — an omitted finding stays open.
203
+ - **A prior BLOCKER whose state is `still-open` or `not-verifiable` yields `VERDICT: FAIL`.** Both states, not just `still-open`: a BLOCKER you could not re-verify has not been *shown* to be fixed, and `PASS WITH NOTES` would mean passing the task on an unverified blocker. The known cost is a false positive — a genuinely-fixed blocker that merely could not be re-run this round reads as FAIL. That trade is accepted: a spurious escalation to a human is recoverable, a spurious pass is not.
204
+ - **NOTEs never escalate.** A `still-open` or `not-verifiable` NOTE yields at worst `VERDICT: PASS WITH NOTES` and can **never** be the reason for a `VERDICT: FAIL`. Only BLOCKERs block.
205
+
206
+ **How the NOTE limit composes with the round-2+ rule above.** These are two separate rules and they never apply to the same NOTEs:
207
+
208
+ | | Newly-raised NOTEs | Carried-forward acknowledgement lines |
209
+ |---|---|---|
210
+ | Round 1 | at most 5 — past 5, drop the least relevant | none exist yet |
211
+ | Round 2+ | **zero** — Round awareness above already forbids new NOTEs | **all of them, written in full, never limited** |
212
+
213
+ So the limit of 5 governs newly-raised NOTEs **only**. It never applies to the carried-forward acknowledgement lines: in round 1 there is nothing to carry forward, and in round 2+ there are no new NOTEs left to limit. Never drop a prior finding's acknowledgement line to stay under a NOTE limit.
153
214
 
154
215
  ---
155
216
 
@@ -177,19 +238,24 @@ Do NOT invent other verdicts like "APPROVE" or "OK" — automation greps for the
177
238
 
178
239
  ## Output Format (Required)
179
240
 
180
- Keep total output **under ~800 characters** — be concise. No preamble, no trailing summary paragraph. PASS items: names only. NOTE items: one-line descriptions. BLOCKER items: full evidence (command + output + expected vs actual).
241
+ BLOCKER evidence is unbounded, so never truncate it to shorten the comment; report at most 5 newly-raised NOTEs and drop the least relevant beyond that. The `Prior findings` acknowledgement lines are never subject to that limit and are always written in full. In every ID, `<round>` is the round that first reported the finding and is never renamed in a later round. No preamble, no trailing summary paragraph. PASS items: names only. NOTE items: one-line descriptions. BLOCKER items: full evidence (command + output + expected vs actual).
181
242
 
182
243
  ```
183
244
  ### Review Summary
184
245
 
246
+ **Prior findings:** (round 2+ only — omit this block in round 1)
247
+ - B1-<slug>: fixed — `<what you re-ran or re-read>` → <result observed>
248
+ - B1-<other-slug>: still-open — `<what you re-ran or re-read>` → <problem still present>
249
+ - B2-<slug>: not-verifiable — <why you could not check it this round>
250
+ - N1-<slug>: still-open
185
251
  **PASS (N):** AC-1 name, AC-2 name, ...
186
252
 
187
253
  **NOTE (M):**
188
- - Note-1: [one-line description]
189
- - Note-2: [one-line description]
254
+ - N<round>-<slug>: [one-line description]
255
+ - N<round>-<slug>: [one-line description]
190
256
 
191
257
  **BLOCKER (K):**
192
- ### Blocker-1: name
258
+ ### B<round>-<slug>
193
259
  **Command run:** [exact command executed]
194
260
  **Output observed:** [actual output — copy-paste, not paraphrased]
195
261
  **Evidence:** [specific finding with file paths, line numbers]
package/README.ja.md CHANGED
@@ -38,6 +38,8 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
38
38
 
39
39
  ## 最近の更新
40
40
 
41
+ **[v0.19.0](https://chorus-ai.dev/blog/chorus-v0.19.0-release/)** — Cloudflare を参考にレビューの範囲を明確化し、問題の根拠を省略せず、固定 ID で再レビュー時も追跡。タスクレビューでは受け入れ基準に加え、コード品質も標準で確認します。
42
+
41
43
  **[v0.18.0](https://chorus-ai.dev/blog/chorus-v0.18.0-release/)** — OpenSpec を補う、軽量で Git ネイティブなローカル Spec 管理として `spec-lite` を内蔵しました。live session anchor により、デーモンエージェントからの返信が、起点となったエージェントの既存 Idea セッションへ戻ります。
42
44
 
43
45
  **[v0.17.2](https://chorus-ai.dev/blog/chorus-v0.17.2-release/)** — Pi が正式配布とデーモンウェイクに対応し、`chorus agents run` でローカルのエージェントプロファイルをすぐ切り替えられます。
@@ -63,7 +65,7 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
63
65
  2 つのコマンドだけです — データベースも Docker も設定ファイルも不要です。
64
66
 
65
67
  ```bash
66
- npm install -g @chorus-aidlc/chorus@0.18.0
68
+ npm install -g @chorus-aidlc/chorus@0.19.0
67
69
  chorus
68
70
  ```
69
71
 
package/README.ko.md CHANGED
@@ -38,6 +38,8 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
38
38
 
39
39
  ## 최근 업데이트
40
40
 
41
+ **[v0.19.0](https://chorus-ai.dev/blog/chorus-v0.19.0-release/)** — Cloudflare를 참고해 리뷰 범위를 명확히 하고, 문제의 근거를 온전히 남기며, 고정 ID로 재검토까지 추적합니다. 태스크 리뷰는 인수 기준 외의 코드 품질도 기본으로 검사합니다.
42
+
41
43
  **[v0.18.0](https://chorus-ai.dev/blog/chorus-v0.18.0-release/)** — OpenSpec을 보완하는 가볍고 Git 친화적인 로컬 Spec 관리 방식으로 `spec-lite`를 내장했습니다. live session anchor를 통해 데몬 에이전트의 응답이 작업을 시작한 에이전트의 기존 Idea 세션으로 돌아갑니다.
42
44
 
43
45
  **[v0.17.2](https://chorus-ai.dev/blog/chorus-v0.17.2-release/)** — Pi를 정식 패키지와 데몬 웨이크로 사용할 수 있으며, `chorus agents run`으로 로컬 에이전트 프로파일을 빠르게 전환할 수 있습니다.
@@ -63,7 +65,7 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
63
65
  두 개의 명령이면 됩니다. 데이터베이스도, Docker도, 설정 파일도 필요 없습니다.
64
66
 
65
67
  ```bash
66
- npm install -g @chorus-aidlc/chorus@0.18.0
68
+ npm install -g @chorus-aidlc/chorus@0.19.0
67
69
  chorus
68
70
  ```
69
71
 
package/README.md CHANGED
@@ -38,6 +38,8 @@ The labels under each stage are the **permissions** an actor needs there — gra
38
38
 
39
39
  ## What's New
40
40
 
41
+ **[v0.19.0](https://chorus-ai.dev/blog/chorus-v0.19.0-release/)** — Cloudflare-inspired reviewer rules: clearer scope, complete blocker evidence, and stable finding IDs across rounds. Task reviews now check code quality beyond acceptance criteria.
42
+
41
43
  **[v0.18.0](https://chorus-ai.dev/blog/chorus-v0.18.0-release/)** — Built-in `spec-lite` adds a lightweight, Git-native local spec workflow alongside OpenSpec. Live session anchors let daemon agents return replies to the initiating agent's existing Idea session.
42
44
 
43
45
  **[v0.17.2](https://chorus-ai.dev/blog/chorus-v0.17.2-release/)** — Pi is now a published, wakeable Chorus agent, and `chorus agents run` switches local agent profiles with one command.
@@ -63,7 +65,7 @@ The labels under each stage are the **permissions** an actor needs there — gra
63
65
  Two commands. No database, no Docker, no config files.
64
66
 
65
67
  ```bash
66
- npm install -g @chorus-aidlc/chorus@0.18.0
68
+ npm install -g @chorus-aidlc/chorus@0.19.0
67
69
  chorus
68
70
  ```
69
71
 
package/README.zh.md CHANGED
@@ -29,6 +29,8 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
29
29
 
30
30
  ## 最近更新
31
31
 
32
+ **[v0.19.0](https://chorus-ai.dev/zh/blog/chorus-v0.19.0-release/)**:借鉴 Cloudflare,明确 reviewer 职责、保留完整证据,用稳定 ID 逐轮追踪问题。任务审查默认检查验收标准之外的代码质量。
33
+
32
34
  **[v0.18.0](https://chorus-ai.dev/zh/blog/chorus-v0.18.0-release/)** — 内置 `spec-lite`,作为 OpenSpec 之外更轻量、可直接进 Git 的本地 Spec 管理方案。live session anchor 让 daemon Agent 的回复回到发起者已有的 Idea 会话。
33
35
 
34
36
  **[v0.17.2](https://chorus-ai.dev/zh/blog/chorus-v0.17.2-release/)** — Pi 现在可以正式安装并由 daemon 唤醒,`chorus agents run` 还能一条命令切换本地 Agent profile。
@@ -54,7 +56,7 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
54
56
  两条命令即可,无需数据库、无需 Docker、无需配置文件。
55
57
 
56
58
  ```bash
57
- npm install -g @chorus-aidlc/chorus@0.18.0
59
+ npm install -g @chorus-aidlc/chorus@0.19.0
58
60
  chorus
59
61
  ```
60
62
 
package/chorus.mjs CHANGED
@@ -315,11 +315,39 @@ function isPortOccupied(host, tcpPort, timeoutMs = 1000) {
315
315
  });
316
316
  }
317
317
 
318
+ // Publicly known placeholder secrets (GitHub #559). Must stay identical to
319
+ // KNOWN_INSECURE_SECRETS in src/lib/secret-check.ts and
320
+ // CHORUS_KNOWN_INSECURE_SECRETS in docker/ensure-secret.sh (parity-tested).
321
+ const KNOWN_INSECURE_SECRETS = [
322
+ "chorus-docker-secret-change-in-production",
323
+ "chorus-local-secret",
324
+ "your-secret-key-change-in-production",
325
+ "change-me-to-a-random-secret",
326
+ ];
327
+
318
328
  function ensureSecret() {
319
329
  const secretPath = join(dataDir, ".secret");
320
- if (process.env.NEXTAUTH_SECRET) return;
330
+ const fromEnv = process.env.NEXTAUTH_SECRET;
331
+ if (fromEnv) {
332
+ if (!KNOWN_INSECURE_SECRETS.includes(fromEnv.trim())) return;
333
+ // A pasted placeholder is treated exactly like "unset": fall through to the
334
+ // persisted / generated secret instead of signing JWTs with a public value.
335
+ console.error(
336
+ "WARNING: NEXTAUTH_SECRET is set to a publicly known placeholder (GitHub #559); ignoring it and using the persisted secret in " +
337
+ secretPath
338
+ );
339
+ }
321
340
  if (existsSync(secretPath)) {
322
- process.env.NEXTAUTH_SECRET = readFileSync(secretPath, "utf8").trim();
341
+ // Fail closed, matching docker/ensure-secret.sh: a persisted file that is
342
+ // empty or holds a publicly known placeholder must never be exported.
343
+ const persisted = readFileSync(secretPath, "utf8").trim();
344
+ if (!persisted || KNOWN_INSECURE_SECRETS.includes(persisted)) {
345
+ console.error(
346
+ `ERROR: the secret persisted at ${secretPath} is ${persisted ? "a publicly known placeholder" : "empty"} (GitHub #559); refusing to start — delete the file to regenerate, or set NEXTAUTH_SECRET explicitly.`
347
+ );
348
+ process.exit(1);
349
+ }
350
+ process.env.NEXTAUTH_SECRET = persisted;
323
351
  return;
324
352
  }
325
353
  const secret = createHash("sha256")
@@ -0,0 +1,77 @@
1
+ // cli/child-exit.mjs
2
+ // One shared settlement path for every spawner's child process, so the five
3
+ // backends (pi / claude / codex / kiro / dsh) cannot drift on "when is the wake
4
+ // over?".
5
+ //
6
+ // WHY THIS EXISTS — `close` is not the same event as "the agent finished".
7
+ // Node emits `exit` when the child process itself is reaped, but `close` only
8
+ // once every stdio stream the child was given has been closed. A child that
9
+ // leaves a DETACHED DESCENDANT behind (a backgrounded server, a `nohup`'d
10
+ // helper) hands that descendant the SAME inherited pipes, so the pipes stay
11
+ // open after the child is long gone and `close` may never fire. A spawner that
12
+ // waits only for `close` therefore keeps reporting a finished wake as still
13
+ // `running` — the phantom `running` turn. Settling on `exit` fixes that.
14
+ //
15
+ // !!! THE GRACE IS NOT A WAKE TIMEOUT AND NOT A WATCHDOG !!!
16
+ // `stdioGraceMs` only starts counting AFTER the child process has ALREADY
17
+ // EXITED, and it bounds one thing only: how long we wait for that dead
18
+ // process's pipes to drain so a final stdout chunk is still parsed. It places
19
+ // no limit whatsoever on how long an agent may run — a wake that runs for
20
+ // hours is never interrupted, cancelled or "timed out" by this module. No
21
+ // wake-duration limit is introduced anywhere here; do not repurpose this timer
22
+ // into one.
23
+
24
+ /** Grace for an already-exited process's pipes to drain. NOT a wake timeout. */
25
+ export const DEFAULT_STDIO_GRACE_MS = 2000;
26
+
27
+ /**
28
+ * Resolve once with the child's exit code as soon as the process is KNOWN to be gone.
29
+ *
30
+ * • `close` first → resolve immediately (today's behaviour, zero regression).
31
+ * • `exit` first → wait up to `stdioGraceMs` for `close` (so a last stdout chunk
32
+ * is still parsed), then resolve with the exit code anyway.
33
+ *
34
+ * Settles exactly once and NEVER rejects. The grace timer is `unref`'d so it can
35
+ * never hold the daemon's event loop open.
36
+ *
37
+ * @param {import("node:child_process").ChildProcess} child
38
+ * @param {{ stdioGraceMs?: number, logger?: { warn?: (msg: string) => void }, label?: string }} [options]
39
+ * @returns {Promise<number | null>} the exit code (`null` when the child was signalled)
40
+ */
41
+ export function awaitChildSettled(child, options = {}) {
42
+ const { stdioGraceMs = DEFAULT_STDIO_GRACE_MS, logger, label = "child" } = options;
43
+
44
+ return new Promise((resolve) => {
45
+ let settled = false;
46
+ let timer = null;
47
+
48
+ const settle = (code) => {
49
+ if (settled) return;
50
+ settled = true;
51
+ if (timer) {
52
+ clearTimeout(timer);
53
+ timer = null;
54
+ }
55
+ resolve(code ?? null);
56
+ };
57
+
58
+ child.on?.("close", (code) => settle(code));
59
+
60
+ child.on?.("exit", (code) => {
61
+ if (settled || timer) return;
62
+ // The process is gone; give its (possibly descendant-held) pipes a bounded
63
+ // moment to drain, then settle regardless. See the header: not a timeout.
64
+ timer = setTimeout(() => {
65
+ timer = null;
66
+ if (settled) return;
67
+ logger?.warn?.(
68
+ `[Chorus] ${label} exited (code ${code ?? null}) but stdio stayed open for ` +
69
+ `${stdioGraceMs}ms; settling on exit`
70
+ );
71
+ settle(code);
72
+ }, stdioGraceMs);
73
+ // Never keep the daemon's event loop alive for a dead process's pipes.
74
+ timer?.unref?.();
75
+ });
76
+ });
77
+ }
@@ -28,6 +28,7 @@ import { validateAgentCliConfig, overlayAgentEnv, getAgentEnv, assertConfiguredS
28
28
  import { existsSync, statSync } from "node:fs";
29
29
  import { homedir } from "node:os";
30
30
  import { win32 as pathWin32, posix as pathPosix, join as pathJoin } from "node:path";
31
+ import { awaitChildSettled } from "./child-exit.mjs";
31
32
 
32
33
  const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
33
34
 
@@ -447,7 +448,9 @@ export class ClaudeSpawner {
447
448
  resolve({ sessionId: observedSessionId, backendSessionId: id, exitCode: null, isNew });
448
449
  });
449
450
 
450
- child.on("close", (code) => {
451
+ // Settle on process exit, not only on stdio close: a detached descendant can
452
+ // inherit the pipes and keep `close` from ever firing (see cli/child-exit.mjs).
453
+ awaitChildSettled(child, { logger: this.logger, label: "claude" }).then((code) => {
451
454
  if (code !== 0) {
452
455
  this.logger.warn(`[Chorus] claude exited with code ${code}`);
453
456
  }
@@ -33,6 +33,7 @@ import { readFileSync, statSync } from "node:fs";
33
33
  import { homedir } from "node:os";
34
34
  import { join, win32 as pathWin32, posix as pathPosix } from "node:path";
35
35
  import { parseNdjsonChunk } from "./claude-spawner.mjs";
36
+ import { awaitChildSettled } from "./child-exit.mjs";
36
37
  import { getThreadId as defaultGetThreadId, setThreadId as defaultSetThreadId } from "./codex-session-map.mjs";
37
38
  import {
38
39
  getCodexUsageSnapshot as defaultGetUsageSnapshot,
@@ -370,7 +371,9 @@ export class CodexSpawner {
370
371
  resolve({ sessionId: anchor, backendSessionId: observedThreadId, exitCode: null, isNew });
371
372
  });
372
373
 
373
- child.on("close", (code) => {
374
+ // Settle on process exit, not only on stdio close: a detached descendant can
375
+ // inherit the pipes and keep `close` from ever firing (see cli/child-exit.mjs).
376
+ awaitChildSettled(child, { logger: this.logger, label: "codex" }).then((code) => {
374
377
  if (code !== 0) {
375
378
  this.logger.warn(`[Chorus] codex exited with code ${code}`);
376
379
  }
@@ -12,6 +12,17 @@
12
12
  // so a stale / recycled connection uuid can never make the daemon kill the wrong
13
13
  // subprocess (Tech Design "Risks": mis-kill after a reconnect).
14
14
  //
15
+ // When Check-2 fails for an `interrupt` (no live child here) the command is NOT
16
+ // silently dropped (fix-phantom-running-turn, Tech Design "D — a no-child interrupt
17
+ // reports the truth"): the handler logs the miss AND fire-and-forgets one
18
+ // `advanceTurn({ status: "interrupted", interruptedReason: "user" })` so a server-side
19
+ // `running` turn with no daemon child behind it converges instead of hanging forever.
20
+ // The session business key is derived without any lookup, and therefore only for the
21
+ // two control entity types where the derivation is an identity (`idea`,
22
+ // `daemon_session` → sessionId === entityUuid). `task` / `proposal` / `document` keep
23
+ // the pure-log behaviour: their session is anchored on the resource's DIRECT idea,
24
+ // which the daemon cannot resolve locally, and guessing would converge the wrong turn.
25
+ //
15
26
  // On a verified match it (a) sets a per-entity "interrupting" flag on the waker so
16
27
  // the waker reports the resulting exit as interrupted(reason="user") rather than a
17
28
  // crash, then (b) invokes the injected killer (process-killer.killProcessTree) on
@@ -25,6 +36,16 @@ import { killProcessTree } from "./process-killer.mjs";
25
36
 
26
37
  const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
27
38
 
39
+ /**
40
+ * Control entity types whose session business key is the entityUuid itself, so a
41
+ * no-child interrupt can report the turn terminal WITHOUT any REST lookup:
42
+ * • `idea` — the session anchor IS the direct idea uuid.
43
+ * • `daemon_session` — the ad-hoc session's own business id.
44
+ * Every other member of CONTROL_ENTITY_TYPES (`task`, `proposal`, `document`) is
45
+ * anchored on that resource's DIRECT idea, which is not derivable locally.
46
+ */
47
+ const SELF_ANCHORED_ENTITY_TYPES = new Set(["idea", "daemon_session"]);
48
+
28
49
  /**
29
50
  * Build the `onControl(event)` callback the SseListener invokes for a
30
51
  * `type:"control"` event.
@@ -56,6 +77,15 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
56
77
  * other still-pending turn along. Injected by the
57
78
  * daemon (`backfill.pendingTurnsOnly`); the
58
79
  * arg-less form (reconnect) still sweeps all.
80
+ * advanceTurn?: (params: { sessionId: string, status: string, interruptedReason?: string,
81
+ * entityType?: string|null, entityUuid?: string|null }) => any,
82
+ * The SAME `createTurnReporter(...)` instance the
83
+ * waker uses (injected by `cli/daemon.mjs`; no
84
+ * second transport, no new endpoint). Invoked
85
+ * fire-and-forget ONLY when an `interrupt` finds no
86
+ * live child for a self-anchored entity type, to
87
+ * close a server-side `running` turn that nothing
88
+ * else would ever close.
59
89
  * logger?: { info(m:string):void, warn(m:string):void, error(m:string):void },
60
90
  * }} deps
61
91
  * @returns {(event: any) => void} The onControl callback (synchronous, non-throwing).
@@ -67,6 +97,7 @@ export function createControlHandler(deps) {
67
97
  const sigintTimeoutMs = deps.sigintTimeoutMs;
68
98
  const redispatchResume = deps.redispatchResume;
69
99
  const deliverTurn = deps.deliverTurn;
100
+ const advanceTurn = deps.advanceTurn;
70
101
  const handleDirectoryRequest = deps.handleDirectoryRequest;
71
102
  const reportDirectoryRequest = deps.reportDirectoryRequest;
72
103
  const logger = deps.logger ?? NOOP_LOGGER;
@@ -202,11 +233,76 @@ export function createControlHandler(deps) {
202
233
  }
203
234
 
204
235
  // --- interrupt path: Check 2 — in-memory entity ownership (running child) ---
236
+ //
237
+ // The registry is keyed by the WAKE's own resource (`task:T`), while a
238
+ // conversation's control key is its session anchor (`idea:A`). A wake on a CHILD
239
+ // resource of idea A runs on session A (waker: `sessionId = directIdeaUuid`), so an
240
+ // `idea:A` interrupt must also find a running `task:T` / `proposal:P` / `document:D`
241
+ // entry whose `directIdeaUuid` is A — the same rule the UI's `executionMatchesSession`
242
+ // applies. Without this the exact-key lookup misses, we report a turn miss, the
243
+ // server's FIFO resolution grabs the SIBLING wake's `running` turn, and NOTHING is
244
+ // killed: the UI would say interrupted while the agent keeps working.
205
245
  const key = execKey(entityType, entityUuid);
206
- const entry = waker?.executions?.get(key);
246
+ let entry = waker?.executions?.get(key);
247
+ // The entity the kill actually targets — normally the command's own, but a sibling
248
+ // wake when the match below re-points it.
249
+ let killEntityType = entityType;
250
+ let killEntityUuid = entityUuid;
251
+ let killKey = key;
252
+ if ((!entry || entry.status !== "running" || !entry.child) && entityType === "idea") {
253
+ for (const candidate of waker?.executions?.values() ?? []) {
254
+ if (
255
+ candidate.status === "running" &&
256
+ candidate.child &&
257
+ candidate.directIdeaUuid === entityUuid
258
+ ) {
259
+ killEntityType = candidate.entityType;
260
+ killEntityUuid = candidate.entityUuid;
261
+ killKey = execKey(killEntityType, killEntityUuid);
262
+ logger.info(
263
+ `[Chorus] control: no direct child for ${key}, but sibling wake ${killKey} ` +
264
+ `runs on this session; interrupting that instead`
265
+ );
266
+ entry = candidate;
267
+ break;
268
+ }
269
+ }
270
+ }
207
271
  if (!entry || entry.status !== "running" || !entry.child) {
208
272
  // Either we never ran this entity, it's only queued (no child yet), or the
209
- // wake already finished (race: interrupt arrived after exit). Safe no-op.
273
+ // wake already finished (race: interrupt arrived after exit). There is nothing
274
+ // to kill — but the SERVER may still hold a `running` turn for this session
275
+ // that nothing else will ever close (the phantom-running-turn bug). Report it
276
+ // terminal so the UI converges. Only for the self-anchored entity types; for
277
+ // the rest we cannot know the session locally, so keep the old pure log.
278
+ if (SELF_ANCHORED_ENTITY_TYPES.has(entityType)) {
279
+ logger.info(
280
+ `[Chorus] control: no running subprocess for ${key} on this daemon; ` +
281
+ `reporting the turn as interrupted(user)`
282
+ );
283
+ // Fire-and-forget: createTurnReporter never throws and logs its own
284
+ // failures, but guard both the synchronous throw and the rejection so
285
+ // nothing escapes into the SSE loop. A server with no `running` turn
286
+ // answers not_found — a harmless no-op (losing race).
287
+ try {
288
+ Promise.resolve(
289
+ advanceTurn?.({
290
+ sessionId: entityUuid,
291
+ status: "interrupted",
292
+ interruptedReason: "user",
293
+ entityType,
294
+ entityUuid,
295
+ })
296
+ ).catch((err) => {
297
+ logger.warn(
298
+ `[Chorus] control: interrupted-turn report rejected for ${key}: ${err}`
299
+ );
300
+ });
301
+ } catch (err) {
302
+ logger.warn(`[Chorus] control: interrupted-turn report failed for ${key}: ${err}`);
303
+ }
304
+ return;
305
+ }
210
306
  logger.info(
211
307
  `[Chorus] control: no running subprocess for ${key} on this daemon; ignoring interrupt`
212
308
  );
@@ -215,18 +311,20 @@ export function createControlHandler(deps) {
215
311
 
216
312
  // --- Both checks passed: mark interrupting (so the waker reports reason=user),
217
313
  // then kill the tree. ---
218
- logger.info(`[Chorus] control: interrupting running subprocess for ${key} (pid=${entry.child.pid})`);
314
+ logger.info(`[Chorus] control: interrupting running subprocess for ${killKey} (pid=${entry.child.pid})`);
219
315
  try {
220
- waker.markInterrupting?.(entityType, entityUuid);
316
+ // Flag the entity whose wake we are actually killing — a sibling re-point must
317
+ // mark THAT wake interrupting, or its exit would be reported as a crash.
318
+ waker.markInterrupting?.(killEntityType, killEntityUuid);
221
319
  } catch (err) {
222
- logger.warn(`[Chorus] control: markInterrupting failed for ${key}: ${err}`);
320
+ logger.warn(`[Chorus] control: markInterrupting failed for ${killKey}: ${err}`);
223
321
  }
224
322
 
225
323
  // Fire-and-forget the kill: the waker observes the child's exit and reports
226
324
  // the interrupted state. The killer never throws, but guard the promise
227
325
  // anyway so a rejection can't surface as an unhandled rejection.
228
326
  Promise.resolve(killer(entry.child, { sigintTimeoutMs, logger })).catch((err) => {
229
- logger.warn(`[Chorus] control: killProcessTree rejected for ${key}: ${err}`);
327
+ logger.warn(`[Chorus] control: killProcessTree rejected for ${killKey}: ${err}`);
230
328
  });
231
329
  } catch (err) {
232
330
  // Absolute backstop — a control event must never crash the SSE loop.