reflectt-node 0.1.7 → 0.1.11

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 (220) hide show
  1. package/README.md +13 -0
  2. package/defaults/TEAM-ROLES.yaml +317 -5
  3. package/defaults/gitignore.template +23 -0
  4. package/dist/agent-config.d.ts +51 -0
  5. package/dist/agent-config.d.ts.map +1 -0
  6. package/dist/agent-config.js +129 -0
  7. package/dist/agent-config.js.map +1 -0
  8. package/dist/agent-config.test.d.ts +2 -0
  9. package/dist/agent-config.test.d.ts.map +1 -0
  10. package/dist/agent-config.test.js +91 -0
  11. package/dist/agent-config.test.js.map +1 -0
  12. package/dist/agent-memories.d.ts +58 -0
  13. package/dist/agent-memories.d.ts.map +1 -0
  14. package/dist/agent-memories.js +168 -0
  15. package/dist/agent-memories.js.map +1 -0
  16. package/dist/agent-memories.test.d.ts +2 -0
  17. package/dist/agent-memories.test.d.ts.map +1 -0
  18. package/dist/agent-memories.test.js +327 -0
  19. package/dist/agent-memories.test.js.map +1 -0
  20. package/dist/agent-messaging.d.ts +50 -0
  21. package/dist/agent-messaging.d.ts.map +1 -0
  22. package/dist/agent-messaging.js +103 -0
  23. package/dist/agent-messaging.js.map +1 -0
  24. package/dist/agent-messaging.test.d.ts +2 -0
  25. package/dist/agent-messaging.test.d.ts.map +1 -0
  26. package/dist/agent-messaging.test.js +105 -0
  27. package/dist/agent-messaging.test.js.map +1 -0
  28. package/dist/agent-runs.d.ts +158 -0
  29. package/dist/agent-runs.d.ts.map +1 -0
  30. package/dist/agent-runs.js +514 -0
  31. package/dist/agent-runs.js.map +1 -0
  32. package/dist/agent-runs.test.d.ts +2 -0
  33. package/dist/agent-runs.test.d.ts.map +1 -0
  34. package/dist/agent-runs.test.js +386 -0
  35. package/dist/agent-runs.test.js.map +1 -0
  36. package/dist/approval-queue.test.d.ts +2 -0
  37. package/dist/approval-queue.test.d.ts.map +1 -0
  38. package/dist/approval-queue.test.js +118 -0
  39. package/dist/approval-queue.test.js.map +1 -0
  40. package/dist/artifact-store.d.ts +55 -0
  41. package/dist/artifact-store.d.ts.map +1 -0
  42. package/dist/artifact-store.js +128 -0
  43. package/dist/artifact-store.js.map +1 -0
  44. package/dist/artifact-store.test.d.ts +2 -0
  45. package/dist/artifact-store.test.d.ts.map +1 -0
  46. package/dist/artifact-store.test.js +119 -0
  47. package/dist/artifact-store.test.js.map +1 -0
  48. package/dist/boardHealthWorker.d.ts +32 -0
  49. package/dist/boardHealthWorker.d.ts.map +1 -1
  50. package/dist/boardHealthWorker.js +69 -2
  51. package/dist/boardHealthWorker.js.map +1 -1
  52. package/dist/buildInfo.d.ts.map +1 -1
  53. package/dist/buildInfo.js +47 -10
  54. package/dist/buildInfo.js.map +1 -1
  55. package/dist/canvas-input.test.d.ts +2 -0
  56. package/dist/canvas-input.test.d.ts.map +1 -0
  57. package/dist/canvas-input.test.js +96 -0
  58. package/dist/canvas-input.test.js.map +1 -0
  59. package/dist/canvas-render.test.d.ts +2 -0
  60. package/dist/canvas-render.test.d.ts.map +1 -0
  61. package/dist/canvas-render.test.js +95 -0
  62. package/dist/canvas-render.test.js.map +1 -0
  63. package/dist/capabilities/browser.d.ts +75 -0
  64. package/dist/capabilities/browser.d.ts.map +1 -0
  65. package/dist/capabilities/browser.js +172 -0
  66. package/dist/capabilities/browser.js.map +1 -0
  67. package/dist/channels.d.ts +1 -1
  68. package/dist/chat.d.ts +4 -0
  69. package/dist/chat.d.ts.map +1 -1
  70. package/dist/chat.js +6 -2
  71. package/dist/chat.js.map +1 -1
  72. package/dist/cli.js +41 -14
  73. package/dist/cli.js.map +1 -1
  74. package/dist/cloud.d.ts +2 -0
  75. package/dist/cloud.d.ts.map +1 -1
  76. package/dist/cloud.js +151 -64
  77. package/dist/cloud.js.map +1 -1
  78. package/dist/continuity-loop.d.ts.map +1 -1
  79. package/dist/continuity-loop.js +297 -29
  80. package/dist/continuity-loop.js.map +1 -1
  81. package/dist/cost-enforcement.d.ts +38 -0
  82. package/dist/cost-enforcement.d.ts.map +1 -0
  83. package/dist/cost-enforcement.js +84 -0
  84. package/dist/cost-enforcement.js.map +1 -0
  85. package/dist/db.d.ts.map +1 -1
  86. package/dist/db.js +131 -0
  87. package/dist/db.js.map +1 -1
  88. package/dist/deploy-monitor.d.ts +18 -0
  89. package/dist/deploy-monitor.d.ts.map +1 -0
  90. package/dist/deploy-monitor.js +165 -0
  91. package/dist/deploy-monitor.js.map +1 -0
  92. package/dist/e2e-loop-proof.test.d.ts +2 -0
  93. package/dist/e2e-loop-proof.test.d.ts.map +1 -0
  94. package/dist/e2e-loop-proof.test.js +104 -0
  95. package/dist/e2e-loop-proof.test.js.map +1 -0
  96. package/dist/email-sms-send.test.d.ts +2 -0
  97. package/dist/email-sms-send.test.d.ts.map +1 -0
  98. package/dist/email-sms-send.test.js +96 -0
  99. package/dist/email-sms-send.test.js.map +1 -0
  100. package/dist/events.d.ts +1 -1
  101. package/dist/events.d.ts.map +1 -1
  102. package/dist/events.js +2 -0
  103. package/dist/events.js.map +1 -1
  104. package/dist/executionSweeper.d.ts +1 -0
  105. package/dist/executionSweeper.d.ts.map +1 -1
  106. package/dist/executionSweeper.js +43 -7
  107. package/dist/executionSweeper.js.map +1 -1
  108. package/dist/files.d.ts.map +1 -1
  109. package/dist/files.js +17 -3
  110. package/dist/files.js.map +1 -1
  111. package/dist/fingerprint.d.ts +30 -0
  112. package/dist/fingerprint.d.ts.map +1 -0
  113. package/dist/fingerprint.js +117 -0
  114. package/dist/fingerprint.js.map +1 -0
  115. package/dist/github-webhook-attribution.d.ts +38 -0
  116. package/dist/github-webhook-attribution.d.ts.map +1 -0
  117. package/dist/github-webhook-attribution.js +123 -0
  118. package/dist/github-webhook-attribution.js.map +1 -0
  119. package/dist/github-webhook-chat.d.ts +75 -0
  120. package/dist/github-webhook-chat.d.ts.map +1 -0
  121. package/dist/github-webhook-chat.js +108 -0
  122. package/dist/github-webhook-chat.js.map +1 -0
  123. package/dist/handoff-state.test.d.ts +2 -0
  124. package/dist/handoff-state.test.d.ts.map +1 -0
  125. package/dist/handoff-state.test.js +102 -0
  126. package/dist/handoff-state.test.js.map +1 -0
  127. package/dist/health.d.ts +9 -0
  128. package/dist/health.d.ts.map +1 -1
  129. package/dist/health.js +18 -0
  130. package/dist/health.js.map +1 -1
  131. package/dist/host-error-correlation.d.ts +65 -0
  132. package/dist/host-error-correlation.d.ts.map +1 -0
  133. package/dist/host-error-correlation.js +123 -0
  134. package/dist/host-error-correlation.js.map +1 -0
  135. package/dist/inbox.d.ts.map +1 -1
  136. package/dist/inbox.js +4 -0
  137. package/dist/inbox.js.map +1 -1
  138. package/dist/index.js +76 -11
  139. package/dist/index.js.map +1 -1
  140. package/dist/notificationDedupeGuard.d.ts +4 -0
  141. package/dist/notificationDedupeGuard.d.ts.map +1 -1
  142. package/dist/notificationDedupeGuard.js +8 -4
  143. package/dist/notificationDedupeGuard.js.map +1 -1
  144. package/dist/presence.d.ts +37 -5
  145. package/dist/presence.d.ts.map +1 -1
  146. package/dist/presence.js +127 -16
  147. package/dist/presence.js.map +1 -1
  148. package/dist/pulse.d.ts +7 -0
  149. package/dist/pulse.d.ts.map +1 -1
  150. package/dist/pulse.js +15 -0
  151. package/dist/pulse.js.map +1 -1
  152. package/dist/review-sla.d.ts +9 -0
  153. package/dist/review-sla.d.ts.map +1 -0
  154. package/dist/review-sla.js +51 -0
  155. package/dist/review-sla.js.map +1 -0
  156. package/dist/review-state.d.ts +9 -0
  157. package/dist/review-state.d.ts.map +1 -0
  158. package/dist/review-state.js +17 -0
  159. package/dist/review-state.js.map +1 -0
  160. package/dist/routing-enforcement.test.d.ts +2 -0
  161. package/dist/routing-enforcement.test.d.ts.map +1 -0
  162. package/dist/routing-enforcement.test.js +86 -0
  163. package/dist/routing-enforcement.test.js.map +1 -0
  164. package/dist/run-retention.test.d.ts +2 -0
  165. package/dist/run-retention.test.d.ts.map +1 -0
  166. package/dist/run-retention.test.js +57 -0
  167. package/dist/run-retention.test.js.map +1 -0
  168. package/dist/run-stream.test.d.ts +2 -0
  169. package/dist/run-stream.test.d.ts.map +1 -0
  170. package/dist/run-stream.test.js +70 -0
  171. package/dist/run-stream.test.js.map +1 -0
  172. package/dist/schedule.d.ts +60 -0
  173. package/dist/schedule.d.ts.map +1 -0
  174. package/dist/schedule.js +176 -0
  175. package/dist/schedule.js.map +1 -0
  176. package/dist/server.d.ts.map +1 -1
  177. package/dist/server.js +1714 -88
  178. package/dist/server.js.map +1 -1
  179. package/dist/suppression-ledger.d.ts.map +1 -1
  180. package/dist/suppression-ledger.js +12 -3
  181. package/dist/suppression-ledger.js.map +1 -1
  182. package/dist/system-loop-state.d.ts +1 -1
  183. package/dist/system-loop-state.d.ts.map +1 -1
  184. package/dist/system-loop-state.js +1 -0
  185. package/dist/system-loop-state.js.map +1 -1
  186. package/dist/tasks.d.ts +9 -1
  187. package/dist/tasks.d.ts.map +1 -1
  188. package/dist/tasks.js +238 -41
  189. package/dist/tasks.js.map +1 -1
  190. package/dist/todoHoardingGuard.d.ts +17 -0
  191. package/dist/todoHoardingGuard.d.ts.map +1 -1
  192. package/dist/todoHoardingGuard.js +25 -2
  193. package/dist/todoHoardingGuard.js.map +1 -1
  194. package/dist/types.d.ts +1 -1
  195. package/dist/types.d.ts.map +1 -1
  196. package/dist/usage-tracking.d.ts +26 -0
  197. package/dist/usage-tracking.d.ts.map +1 -1
  198. package/dist/usage-tracking.js +91 -4
  199. package/dist/usage-tracking.js.map +1 -1
  200. package/dist/webhook-storage.d.ts +50 -0
  201. package/dist/webhook-storage.d.ts.map +1 -0
  202. package/dist/webhook-storage.js +102 -0
  203. package/dist/webhook-storage.js.map +1 -0
  204. package/dist/webhook-storage.test.d.ts +2 -0
  205. package/dist/webhook-storage.test.d.ts.map +1 -0
  206. package/dist/webhook-storage.test.js +86 -0
  207. package/dist/webhook-storage.test.js.map +1 -0
  208. package/dist/workflow-templates.d.ts +44 -0
  209. package/dist/workflow-templates.d.ts.map +1 -0
  210. package/dist/workflow-templates.js +154 -0
  211. package/dist/workflow-templates.js.map +1 -0
  212. package/dist/workflow-templates.test.d.ts +2 -0
  213. package/dist/workflow-templates.test.d.ts.map +1 -0
  214. package/dist/workflow-templates.test.js +76 -0
  215. package/dist/workflow-templates.test.js.map +1 -0
  216. package/package.json +3 -1
  217. package/public/dashboard.js +130 -37
  218. package/public/design-tokens-platform.md +118 -0
  219. package/public/design-tokens.css +195 -0
  220. package/public/docs.md +145 -2
@@ -1 +1 @@
1
- {"version":3,"file":"suppression-ledger.d.ts","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjF,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,QAAQ,CAAC,EAAE,MAAM;IAI7B;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAY3E;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE;QACV,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,GAAG,sBAAsB;IAyD1B;;OAEG;IACH,QAAQ,IAAI,gBAAgB;IAqC5B;;OAEG;IACH,KAAK,IAAI,MAAM;IAOf;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAG9B;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAA"}
1
+ {"version":3,"file":"suppression-ledger.d.ts","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjF,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,QAAQ,CAAC,EAAE,MAAM;IAI7B;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAuB3E;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE;QACV,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,GAAG,sBAAsB;IAyD1B;;OAEG;IACH,QAAQ,IAAI,gBAAgB;IAqC5B;;OAEG;IACH,KAAK,IAAI,MAAM;IAOf;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAG9B;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAA"}
@@ -16,13 +16,22 @@ export class SuppressionLedger {
16
16
  * Content is normalized: timestamps, task IDs, and message IDs stripped.
17
17
  */
18
18
  computeDedupKey(category, channel, content) {
19
- const normalized = content
19
+ let normalized = content
20
20
  .trim()
21
21
  .toLowerCase()
22
22
  .replace(/\b(msg-|task-|tcomment-|ins-|ref-)\S+/g, '')
23
23
  .replace(/\d{13,}/g, '')
24
- .replace(/\s+/g, ' ')
25
- .slice(0, 300);
24
+ .replace(/\s+/g, ' ');
25
+ // For digest messages, aggressively strip volatile counts so that
26
+ // "32 todo · 2 doing" vs "31 todo · 3 doing" hashes identically.
27
+ // This prevents process restarts from re-emitting the same digest
28
+ // just because task counts shifted by 1-2.
29
+ if (category === 'digest') {
30
+ normalized = normalized
31
+ .replace(/\d+/g, 'N') // normalize all remaining numbers
32
+ .replace(/\bN+\b/g, 'N'); // collapse repeated N
33
+ }
34
+ normalized = normalized.slice(0, 300);
26
35
  const raw = `${category}:${channel}:${normalized}`;
27
36
  return createHash('sha256').update(raw).digest('hex').substring(0, 20);
28
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"suppression-ledger.js","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"suppression-ledger.js","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type SystemLoopName = 'idle_nudge' | 'cadence_watchdog' | 'mention_rescue' | 'reflection_pipeline' | 'board_health';
1
+ export type SystemLoopName = 'idle_nudge' | 'cadence_watchdog' | 'mention_rescue' | 'reflection_pipeline' | 'board_health' | 'deploy_monitor';
2
2
  export declare function recordSystemLoopTick(name: SystemLoopName, now?: number): void;
3
3
  export declare function getSystemLoopTicks(): Record<SystemLoopName, number>;
4
4
  //# sourceMappingURL=system-loop-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"system-loop-state.d.ts","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,cAAc,CAAA;AAElB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,SAAa,GAAG,IAAI,CAWjF;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAqBnE"}
1
+ {"version":3,"file":"system-loop-state.d.ts","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,cAAc,GACd,gBAAgB,CAAA;AAEpB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,SAAa,GAAG,IAAI,CAWjF;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAsBnE"}
@@ -23,6 +23,7 @@ export function getSystemLoopTicks() {
23
23
  mention_rescue: 0,
24
24
  reflection_pipeline: 0,
25
25
  board_health: 0,
26
+ deploy_monitor: 0,
26
27
  };
27
28
  try {
28
29
  const rows = db.prepare('SELECT name, last_tick_at FROM system_loop_ticks').all();
@@ -1 +1 @@
1
- {"version":3,"file":"system-loop-state.js","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAS/B,MAAM,UAAU,oBAAoB,CAAC,IAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACzE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,IAAI,CAAC;QACH,EAAE,CAAC,OAAO,CACR;;4EAEsE,CACvE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,GAAG,GAAmC;QAC1C,UAAU,EAAE,CAAC;QACb,gBAAgB,EAAE,CAAC;QACnB,cAAc,EAAE,CAAC;QACjB,mBAAmB,EAAE,CAAC;QACtB,YAAY,EAAE,CAAC;KAChB,CAAA;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,EAAmD,CAAA;QAClI,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAmB,CAAA;YAC7C,IAAI,IAAI,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC"}
1
+ {"version":3,"file":"system-loop-state.js","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAU/B,MAAM,UAAU,oBAAoB,CAAC,IAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACzE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,IAAI,CAAC;QACH,EAAE,CAAC,OAAO,CACR;;4EAEsE,CACvE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,GAAG,GAAmC;QAC1C,UAAU,EAAE,CAAC;QACb,gBAAgB,EAAE,CAAC;QACnB,cAAc,EAAE,CAAC;QACjB,mBAAmB,EAAE,CAAC;QACtB,YAAY,EAAE,CAAC;QACf,cAAc,EAAE,CAAC;KAClB,CAAA;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,EAAmD,CAAA;QAClI,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAmB,CAAA;YAC7C,IAAI,IAAI,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC"}
package/dist/tasks.d.ts CHANGED
@@ -32,6 +32,7 @@ declare class TaskManager {
32
32
  created: number;
33
33
  skipped: number;
34
34
  }>;
35
+ private appendTaskTombstone;
35
36
  /** Write a single task to SQLite + JSONL audit */
36
37
  private writeTaskToDb;
37
38
  /** Legacy bulk persist — now just writes all tasks from DB to JSONL */
@@ -73,6 +74,13 @@ declare class TaskManager {
73
74
  * fields without triggering full validation or history events.
74
75
  */
75
76
  patchTaskMetadata(id: string, metadataUpdates: Record<string, unknown>): boolean;
77
+ getTaskDeletionTombstone(inputId: string): {
78
+ taskId: string;
79
+ deletedAt: number;
80
+ deletedBy: string;
81
+ previousStatus: string;
82
+ title: string;
83
+ } | null;
76
84
  getTaskHistory(id: string): TaskHistoryEvent[];
77
85
  getTaskComments(id: string, options?: {
78
86
  includeSuppressed?: boolean;
@@ -105,7 +113,7 @@ declare class TaskManager {
105
113
  private parseLaneTransition;
106
114
  private applyLaneStateLock;
107
115
  updateTask(id: string, updates: Partial<Omit<Task, 'id' | 'createdAt' | 'createdBy'>>): Promise<Task | undefined>;
108
- deleteTask(id: string): Promise<boolean>;
116
+ deleteTask(id: string, actor?: string): Promise<boolean>;
109
117
  subscribe(callback: (task: Task, action: 'created' | 'updated' | 'deleted') => void): () => boolean;
110
118
  private notifySubscribers;
111
119
  private checkUnblockedTasks;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
package/dist/tasks.js CHANGED
@@ -9,6 +9,7 @@ import { getDb, importJsonlIfNeeded, safeJsonStringify, safeJsonParse } from './
9
9
  import { isTestHarnessTask, TEST_TASK_EXCLUDE_SQL } from './test-task-filter.js';
10
10
  import { assertDuplicateClosureHasCanonicalRefs } from './duplicateClosureGuard.js';
11
11
  import { getAgentAliases } from './assignment.js';
12
+ import { getAgentLane } from './lane-config.js';
12
13
  const TASKS_FILE = join(DATA_DIR, 'tasks.jsonl');
13
14
  const LEGACY_TASKS_FILE = join(LEGACY_DATA_DIR, 'tasks.jsonl');
14
15
  const RECURRING_TASKS_FILE = join(DATA_DIR, 'tasks.recurring.jsonl');
@@ -25,8 +26,14 @@ function importTasks(db, records) {
25
26
  tags, metadata, team_id, comment_count, due_at, scheduled_for
26
27
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
27
28
  `);
29
+ const del = db.prepare('DELETE FROM tasks WHERE id = ?');
28
30
  const insertMany = db.transaction((tasks) => {
29
31
  for (const record of tasks) {
32
+ const tombstone = record;
33
+ if (tombstone?.deleted === true && typeof tombstone.id === 'string' && tombstone.id.trim()) {
34
+ del.run(tombstone.id);
35
+ continue;
36
+ }
30
37
  const task = record;
31
38
  insert.run(task.id, task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, 0, // comment_count will be recalculated when comments are imported
32
39
  task.dueAt ?? null, task.scheduledFor ?? null);
@@ -336,12 +343,18 @@ class TaskManager {
336
343
  VALUES (?, ?, ?, ?, ?, ?)
337
344
  `);
338
345
  insert.run(event.id, event.taskId, event.type, event.actor, event.timestamp, safeJsonStringify(event.data));
346
+ }
347
+ catch (err) {
348
+ console.error('[Tasks] Failed to append task history (DB):', err);
349
+ throw err;
350
+ }
351
+ try {
339
352
  // Append to JSONL (audit log)
340
353
  await fs.mkdir(DATA_DIR, { recursive: true });
341
354
  await fs.appendFile(TASK_HISTORY_FILE, `${JSON.stringify(event)}\n`, 'utf-8');
342
355
  }
343
356
  catch (err) {
344
- console.error('[Tasks] Failed to append task history:', err);
357
+ console.error('[Tasks] Failed to append task history (JSONL):', err);
345
358
  }
346
359
  }
347
360
  async recordTaskHistoryEvent(taskId, type, actor, data) {
@@ -356,39 +369,48 @@ class TaskManager {
356
369
  await this.appendTaskHistory(event);
357
370
  }
358
371
  async appendTaskComment(comment) {
372
+ const db = getDb();
373
+ // DB writes must be atomic; otherwise callers may observe a "phantom" comment ID
374
+ // that never persisted (breaking review_handoff.comment_id).
375
+ const insert = db.prepare(`
376
+ INSERT INTO task_comments (
377
+ id, task_id, author, content, timestamp,
378
+ category, suppressed, suppressed_reason, suppressed_rule
379
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
380
+ `);
381
+ const updateTask = db.prepare(`
382
+ UPDATE tasks
383
+ SET
384
+ comment_count = (SELECT COUNT(*) FROM task_comments WHERE task_id = ?),
385
+ updated_at = ?
386
+ WHERE id = ?
387
+ `);
388
+ const touchUpdatedAt = db.prepare(`
389
+ UPDATE tasks
390
+ SET updated_at = MAX(updated_at, ?)
391
+ WHERE id = ?
392
+ `);
393
+ try {
394
+ const tx = db.transaction(() => {
395
+ insert.run(comment.id, comment.taskId, comment.author, comment.content, comment.timestamp, comment.category ?? null, comment.suppressed ? 1 : 0, comment.suppressedReason ?? null, comment.suppressedRule ?? null);
396
+ // Comments are material activity and should advance updated_at to avoid autonomy/heartbeat false positives.
397
+ updateTask.run(comment.taskId, comment.timestamp, comment.taskId);
398
+ touchUpdatedAt.run(comment.timestamp, comment.taskId);
399
+ });
400
+ tx();
401
+ }
402
+ catch (err) {
403
+ // Critical: propagate failures so API callers don't record unresolvable comment IDs.
404
+ console.error('[Tasks] Failed to append task comment (DB):', err);
405
+ throw err;
406
+ }
407
+ // Audit log is best-effort; DB is the source of truth.
359
408
  try {
360
- const db = getDb();
361
- // Write to SQLite (primary)
362
- const insert = db.prepare(`
363
- INSERT INTO task_comments (
364
- id, task_id, author, content, timestamp,
365
- category, suppressed, suppressed_reason, suppressed_rule
366
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
367
- `);
368
- insert.run(comment.id, comment.taskId, comment.author, comment.content, comment.timestamp, comment.category ?? null, comment.suppressed ? 1 : 0, comment.suppressedReason ?? null, comment.suppressedRule ?? null);
369
- // Update comment count + updated_at for the task.
370
- // Comments are material activity and should advance updated_at to avoid autonomy/heartbeat false positives.
371
- const updateTask = db.prepare(`
372
- UPDATE tasks
373
- SET
374
- comment_count = (SELECT COUNT(*) FROM task_comments WHERE task_id = ?),
375
- updated_at = ?
376
- WHERE id = ?
377
- `);
378
- updateTask.run(comment.taskId, comment.timestamp, comment.taskId);
379
- // Touch task updated_at so comment activity counts as task activity (autonomy, SLA, sorting)
380
- const touchUpdatedAt = db.prepare(`
381
- UPDATE tasks
382
- SET updated_at = MAX(updated_at, ?)
383
- WHERE id = ?
384
- `);
385
- touchUpdatedAt.run(comment.timestamp, comment.taskId);
386
- // Append to JSONL (audit log)
387
409
  await fs.mkdir(DATA_DIR, { recursive: true });
388
410
  await fs.appendFile(TASK_COMMENTS_FILE, `${JSON.stringify(comment)}\n`, 'utf-8');
389
411
  }
390
412
  catch (err) {
391
- console.error('[Tasks] Failed to append task comment:', err);
413
+ console.error('[Tasks] Failed to append task comment (JSONL):', err);
392
414
  }
393
415
  }
394
416
  async persistRecurringTasks() {
@@ -526,18 +548,48 @@ class TaskManager {
526
548
  }
527
549
  return { created, skipped };
528
550
  }
551
+ async appendTaskTombstone(task, deletedBy, deletedAt) {
552
+ try {
553
+ await fs.mkdir(DATA_DIR, { recursive: true });
554
+ await fs.appendFile(TASKS_FILE, `${JSON.stringify({
555
+ id: task.id,
556
+ deleted: true,
557
+ deletedAt,
558
+ deletedBy,
559
+ })}\n`, 'utf-8');
560
+ }
561
+ catch (err) {
562
+ console.error('[Tasks] Failed to append task tombstone:', err);
563
+ }
564
+ }
529
565
  /** Write a single task to SQLite + JSONL audit */
530
566
  writeTaskToDb(task) {
531
567
  try {
532
568
  const db = getDb();
533
569
  const commentCount = this.getTaskCommentCount(task.id);
534
- db.prepare(`
535
- INSERT OR REPLACE INTO tasks (
536
- id, title, description, status, assignee, reviewer, done_criteria,
537
- created_by, created_at, updated_at, priority, blocked_by, epic_id,
538
- tags, metadata, team_id, comment_count, due_at, scheduled_for
539
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
540
- `).run(task.id, task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, commentCount, task.dueAt ?? null, task.scheduledFor ?? null);
570
+ // Use UPDATE for existing tasks to avoid INSERT OR REPLACE which triggers
571
+ // ON DELETE CASCADE on foreign keys (task_comments, task_history), wiping
572
+ // all comments/history for the task. Only INSERT for genuinely new tasks.
573
+ const existing = db.prepare('SELECT 1 FROM tasks WHERE id = ?').get(task.id);
574
+ if (existing) {
575
+ db.prepare(`
576
+ UPDATE tasks SET
577
+ title = ?, description = ?, status = ?, assignee = ?, reviewer = ?,
578
+ done_criteria = ?, created_by = ?, created_at = ?, updated_at = ?,
579
+ priority = ?, blocked_by = ?, epic_id = ?, tags = ?, metadata = ?,
580
+ team_id = ?, comment_count = ?, due_at = ?, scheduled_for = ?
581
+ WHERE id = ?
582
+ `).run(task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, commentCount, task.dueAt ?? null, task.scheduledFor ?? null, task.id);
583
+ }
584
+ else {
585
+ db.prepare(`
586
+ INSERT INTO tasks (
587
+ id, title, description, status, assignee, reviewer, done_criteria,
588
+ created_by, created_at, updated_at, priority, blocked_by, epic_id,
589
+ tags, metadata, team_id, comment_count, due_at, scheduled_for
590
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
591
+ `).run(task.id, task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, commentCount, task.dueAt ?? null, task.scheduledFor ?? null);
592
+ }
541
593
  }
542
594
  catch (err) {
543
595
  console.error(`[Tasks] Failed to write task ${task.id} to SQLite:`, err);
@@ -750,6 +802,45 @@ class TaskManager {
750
802
  this.writeTaskToDb(updated);
751
803
  return true;
752
804
  }
805
+ getTaskDeletionTombstone(inputId) {
806
+ const db = getDb();
807
+ const raw = String(inputId || '').trim();
808
+ if (!raw)
809
+ return null;
810
+ // Try exact match first, then prefix match against task_history task_ids.
811
+ let taskId = raw;
812
+ const exactRow = db.prepare(`SELECT task_id, data FROM task_history WHERE task_id = ? AND type = 'deleted' ORDER BY timestamp DESC LIMIT 1`).get(raw);
813
+ if (!exactRow) {
814
+ // Prefix match: find task_ids in history that start with the input.
815
+ const prefixRows = db.prepare(`SELECT task_id FROM task_history WHERE task_id LIKE ? AND type = 'deleted' LIMIT 2`).all(raw + '%');
816
+ if (prefixRows.length !== 1)
817
+ return null;
818
+ taskId = prefixRows[0].task_id;
819
+ const prefixRow = db.prepare(`SELECT data FROM task_history WHERE task_id = ? AND type = 'deleted' ORDER BY timestamp DESC LIMIT 1`).get(taskId);
820
+ if (!prefixRow)
821
+ return null;
822
+ const prefixData = safeJsonParse(prefixRow.data);
823
+ if (!prefixData)
824
+ return null;
825
+ return {
826
+ taskId,
827
+ deletedAt: typeof prefixData.deletedAt === 'number' ? prefixData.deletedAt : 0,
828
+ deletedBy: typeof prefixData.deletedBy === 'string' ? prefixData.deletedBy : 'unknown',
829
+ previousStatus: typeof prefixData.previousStatus === 'string' ? prefixData.previousStatus : 'unknown',
830
+ title: typeof prefixData.title === 'string' ? prefixData.title : '',
831
+ };
832
+ }
833
+ const data = safeJsonParse(exactRow.data);
834
+ if (!data)
835
+ return null;
836
+ return {
837
+ taskId,
838
+ deletedAt: typeof data.deletedAt === 'number' ? data.deletedAt : 0,
839
+ deletedBy: typeof data.deletedBy === 'string' ? data.deletedBy : 'unknown',
840
+ previousStatus: typeof data.previousStatus === 'string' ? data.previousStatus : 'unknown',
841
+ title: typeof data.title === 'string' ? data.title : '',
842
+ };
843
+ }
753
844
  getTaskHistory(id) {
754
845
  const db = getDb();
755
846
  const rows = db.prepare('SELECT * FROM task_history WHERE task_id = ? ORDER BY timestamp ASC').all(id);
@@ -986,6 +1077,37 @@ class TaskManager {
986
1077
  return transition;
987
1078
  };
988
1079
  let transitionEvent;
1080
+ // ── Bounce gate: validating → doing ────────────────────────────────────
1081
+ // A task bouncing from validating back to doing is a signal of rework.
1082
+ // Track bounce_count in metadata. On the 3rd bounce (bounce_count >= 2),
1083
+ // require a documented reason before allowing the regression.
1084
+ if (task.status === 'validating' && nextStatus === 'doing') {
1085
+ const meta = (task.metadata || {});
1086
+ const currentBounce = typeof meta.bounce_count === 'number' ? meta.bounce_count : 0;
1087
+ const newBounceCount = currentBounce + 1;
1088
+ if (currentBounce >= 2) {
1089
+ // 3rd+ bounce: require documented reason
1090
+ if (!transition || typeof transition !== 'object') {
1091
+ throw new Error(`Bounce gate: this task has bounced ${currentBounce} times. ` +
1092
+ `Provide metadata.transition = { type: "bounce_back", reason: "..." } explaining the rework.`);
1093
+ }
1094
+ const bounceReason = transition.reason;
1095
+ if (typeof bounceReason !== 'string' || bounceReason.trim().length === 0) {
1096
+ throw new Error(`Bounce gate: metadata.transition.reason is required when re-opening a task that has bounced ${currentBounce} times.`);
1097
+ }
1098
+ }
1099
+ // Merge bounce_count into metadata, preserving existing task metadata
1100
+ // (task.metadata has eta etc; updates.metadata may have transition or be empty)
1101
+ const existingMeta = {
1102
+ ...(task.metadata || {}),
1103
+ ...(updates.metadata || {}),
1104
+ };
1105
+ updates.metadata = {
1106
+ ...existingMeta,
1107
+ bounce_count: newBounceCount,
1108
+ last_bounce_at: Date.now(),
1109
+ };
1110
+ }
989
1111
  if (task.status === 'doing' && nextStatus === 'blocked') {
990
1112
  const parsed = requireTransition('pause', ['reason'], 'doing->blocked transition');
991
1113
  transitionEvent = {
@@ -1125,20 +1247,51 @@ class TaskManager {
1125
1247
  }
1126
1248
  return updated;
1127
1249
  }
1128
- async deleteTask(id) {
1250
+ async deleteTask(id, actor = 'system') {
1129
1251
  const task = queryTask(id);
1130
1252
  if (!task)
1131
1253
  return false;
1132
- // Delete from SQLite
1254
+ const deletedAt = Date.now();
1255
+ const event = {
1256
+ id: `thevt-${deletedAt}-${Math.random().toString(36).substr(2, 9)}`,
1257
+ taskId: id,
1258
+ type: 'deleted',
1259
+ actor,
1260
+ timestamp: deletedAt,
1261
+ data: {
1262
+ deletedAt,
1263
+ deletedBy: actor,
1264
+ previousStatus: task.status,
1265
+ title: task.title,
1266
+ },
1267
+ };
1268
+ // Make the live-row delete visible immediately, even if a caller forgets to await deleteTask().
1269
+ // Keep history/comments as audit.
1133
1270
  try {
1134
1271
  const db = getDb();
1135
- db.prepare('DELETE FROM tasks WHERE id = ?').run(id);
1136
- db.prepare('DELETE FROM task_comments WHERE task_id = ?').run(id);
1137
- db.prepare('DELETE FROM task_history WHERE task_id = ?').run(id);
1272
+ const insertHistory = db.prepare(`
1273
+ INSERT INTO task_history (id, task_id, type, actor, timestamp, data)
1274
+ VALUES (?, ?, ?, ?, ?, ?)
1275
+ `);
1276
+ const delTask = db.prepare('DELETE FROM tasks WHERE id = ?');
1277
+ const tx = db.transaction(() => {
1278
+ insertHistory.run(event.id, event.taskId, event.type, event.actor, event.timestamp, safeJsonStringify(event.data));
1279
+ delTask.run(id);
1280
+ });
1281
+ tx();
1138
1282
  }
1139
1283
  catch (err) {
1140
1284
  console.error(`[Tasks] SQLite delete failed for ${id}:`, err);
1285
+ throw err;
1141
1286
  }
1287
+ try {
1288
+ await fs.mkdir(DATA_DIR, { recursive: true });
1289
+ await fs.appendFile(TASK_HISTORY_FILE, `${JSON.stringify(event)}\n`, 'utf-8');
1290
+ }
1291
+ catch (err) {
1292
+ console.error('[Tasks] Failed to append delete history (JSONL):', err);
1293
+ }
1294
+ await this.appendTaskTombstone(task, actor, deletedAt);
1142
1295
  await this.syncTaskDeleteToCloud(id);
1143
1296
  this.notifySubscribers(task, 'deleted');
1144
1297
  return true;
@@ -1237,6 +1390,50 @@ class TaskManager {
1237
1390
  // so we must treat that sentinel as unassigned for pull-based assignment.
1238
1391
  const todoUnassignedRows = db.prepare("SELECT * FROM tasks WHERE status = ? AND (assignee IS NULL OR TRIM(assignee) = '' OR LOWER(assignee) = 'unassigned')").all('todo');
1239
1392
  let tasks = todoUnassignedRows.map(rowToTask).filter(t => !isBlocked(t) && filterTestTask(t));
1393
+ // Filter out tasks with a recent handoff to another agent.
1394
+ // If metadata.last_transition.handoff_to exists and points to a different agent,
1395
+ // this task was explicitly routed away and should not be pulled by someone else.
1396
+ if (agent) {
1397
+ const requestingNames = new Set(getAgentAliases(agent));
1398
+ tasks = tasks.filter(t => {
1399
+ const meta = t.metadata;
1400
+ const handoffTo = meta?.last_transition?.handoff_to || meta?.transition?.handoff_to;
1401
+ if (!handoffTo || typeof handoffTo !== 'string')
1402
+ return true; // no handoff — anyone can pull
1403
+ return requestingNames.has(handoffTo.toLowerCase()); // only the handoff target can pull
1404
+ });
1405
+ }
1406
+ // Lane-aware filtering: prevent cross-lane task pulling.
1407
+ // If the requesting agent is in a lane, filter out unassigned tasks that have
1408
+ // a previous assignee in a DIFFERENT lane. This prevents idle agents from
1409
+ // pulling work that belongs to another lane's domain.
1410
+ if (agent) {
1411
+ // getAgentLane imported at top of file
1412
+ const requestingLane = getAgentLane(agent);
1413
+ if (requestingLane) {
1414
+ // Lane-neutral creators: system processes that create tasks for any lane
1415
+ const laneNeutralCreators = new Set(['system', 'insight-bridge', 'insight-task-bridge', 'sweeper', 'ryan']);
1416
+ tasks = tasks.filter(t => {
1417
+ const meta = t.metadata;
1418
+ // Signal 1: explicit previous assignee (strongest — task was actively worked by someone)
1419
+ const prevAssignee = meta?.previous_assignee || meta?.last_transition?.from_assignee;
1420
+ if (prevAssignee && typeof prevAssignee === 'string') {
1421
+ const prevLane = getAgentLane(prevAssignee.toLowerCase());
1422
+ if (prevLane && prevLane.name !== requestingLane.name)
1423
+ return false;
1424
+ }
1425
+ // Signal 2: createdBy agent in another lane (tasks created by an agent
1426
+ // are usually intended for their lane, unless created by system processes)
1427
+ const createdBy = t.createdBy ? t.createdBy.toLowerCase() : null;
1428
+ if (createdBy && !laneNeutralCreators.has(createdBy)) {
1429
+ const creatorLane = getAgentLane(createdBy);
1430
+ if (creatorLane && creatorLane.name !== requestingLane.name)
1431
+ return false;
1432
+ }
1433
+ return true; // no lane conflict — anyone can pull
1434
+ });
1435
+ }
1436
+ }
1240
1437
  if (agent) {
1241
1438
  const agentNames = getAgentAliases(agent);
1242
1439
  if (agentNames.length > 0) {