@telora/daemon 0.22.84 → 0.22.87

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 (264) hide show
  1. package/build-info.json +4 -3
  2. package/dist/ci/ci-escalation.d.ts +17 -1
  3. package/dist/ci/ci-escalation.d.ts.map +1 -1
  4. package/dist/ci/ci-escalation.js +51 -3
  5. package/dist/ci/ci-escalation.js.map +1 -1
  6. package/dist/ci/ci-red-attribution.d.ts +85 -0
  7. package/dist/ci/ci-red-attribution.d.ts.map +1 -0
  8. package/dist/ci/ci-red-attribution.js +108 -0
  9. package/dist/ci/ci-red-attribution.js.map +1 -0
  10. package/dist/ci/ci-sensor-loop.d.ts +84 -80
  11. package/dist/ci/ci-sensor-loop.d.ts.map +1 -1
  12. package/dist/ci/ci-sensor-loop.js +132 -129
  13. package/dist/ci/ci-sensor-loop.js.map +1 -1
  14. package/dist/completion/coverage-stabilized.d.ts.map +1 -1
  15. package/dist/completion/coverage-stabilized.js +1 -1
  16. package/dist/completion/coverage-stabilized.js.map +1 -1
  17. package/dist/completion/escalations.d.ts +40 -5
  18. package/dist/completion/escalations.d.ts.map +1 -1
  19. package/dist/completion/escalations.js +19 -11
  20. package/dist/completion/escalations.js.map +1 -1
  21. package/dist/completion/event-escalations.d.ts +12 -1
  22. package/dist/completion/event-escalations.d.ts.map +1 -1
  23. package/dist/completion/event-escalations.js +73 -37
  24. package/dist/completion/event-escalations.js.map +1 -1
  25. package/dist/completion/event.d.ts +4 -1
  26. package/dist/completion/event.d.ts.map +1 -1
  27. package/dist/completion/event.js +1 -1
  28. package/dist/completion/event.js.map +1 -1
  29. package/dist/completion/human-only-act.d.ts +1 -1
  30. package/dist/completion/human-only-act.js +1 -1
  31. package/dist/completion/machine-remediable-demotion.d.ts +28 -1
  32. package/dist/completion/machine-remediable-demotion.d.ts.map +1 -1
  33. package/dist/completion/machine-remediable-demotion.js +9 -6
  34. package/dist/completion/machine-remediable-demotion.js.map +1 -1
  35. package/dist/completion/read-only-pristine.d.ts.map +1 -1
  36. package/dist/completion/read-only-pristine.js +4 -0
  37. package/dist/completion/read-only-pristine.js.map +1 -1
  38. package/dist/completion/review-exit-deps.js +1 -1
  39. package/dist/completion/review-exit-deps.js.map +1 -1
  40. package/dist/completion/review-exit-escalations.d.ts +10 -0
  41. package/dist/completion/review-exit-escalations.d.ts.map +1 -1
  42. package/dist/completion/review-exit-escalations.js +38 -3
  43. package/dist/completion/review-exit-escalations.js.map +1 -1
  44. package/dist/completion/review-exit-phase.d.ts.map +1 -1
  45. package/dist/completion/review-exit-phase.js +8 -7
  46. package/dist/completion/review-exit-phase.js.map +1 -1
  47. package/dist/completion/review-exit-shortfall.d.ts +5 -1
  48. package/dist/completion/review-exit-shortfall.d.ts.map +1 -1
  49. package/dist/completion/review-exit-shortfall.js +8 -3
  50. package/dist/completion/review-exit-shortfall.js.map +1 -1
  51. package/dist/completion/status-advance-phase.d.ts +2 -0
  52. package/dist/completion/status-advance-phase.d.ts.map +1 -1
  53. package/dist/completion/status-advance-phase.js +2 -1
  54. package/dist/completion/status-advance-phase.js.map +1 -1
  55. package/dist/completion/terminated-work-reconcile.js +2 -2
  56. package/dist/completion/terminated-work-reconcile.js.map +1 -1
  57. package/dist/delivery/delivery-advance-block.d.ts +3 -3
  58. package/dist/delivery/delivery-advance-block.d.ts.map +1 -1
  59. package/dist/delivery/delivery-advance-block.js +13 -8
  60. package/dist/delivery/delivery-advance-block.js.map +1 -1
  61. package/dist/delivery/delivery-lifecycle.d.ts +10 -0
  62. package/dist/delivery/delivery-lifecycle.d.ts.map +1 -1
  63. package/dist/delivery/delivery-lifecycle.js +12 -6
  64. package/dist/delivery/delivery-lifecycle.js.map +1 -1
  65. package/dist/delivery/delivery-merge-ops.d.ts.map +1 -1
  66. package/dist/delivery/delivery-merge-ops.js +39 -21
  67. package/dist/delivery/delivery-merge-ops.js.map +1 -1
  68. package/dist/delivery/external-hold.d.ts +8 -2
  69. package/dist/delivery/external-hold.d.ts.map +1 -1
  70. package/dist/delivery/external-hold.js +12 -5
  71. package/dist/delivery/external-hold.js.map +1 -1
  72. package/dist/delivery/operator-hold.d.ts +6 -1
  73. package/dist/delivery/operator-hold.d.ts.map +1 -1
  74. package/dist/delivery/operator-hold.js +31 -10
  75. package/dist/delivery/operator-hold.js.map +1 -1
  76. package/dist/delivery/paused-revival.d.ts +6 -0
  77. package/dist/delivery/paused-revival.d.ts.map +1 -1
  78. package/dist/delivery/paused-revival.js +3 -1
  79. package/dist/delivery/paused-revival.js.map +1 -1
  80. package/dist/directive/directive-dispatch.d.ts.map +1 -1
  81. package/dist/directive/directive-dispatch.js +6 -3
  82. package/dist/directive/directive-dispatch.js.map +1 -1
  83. package/dist/directive/directive-queue.d.ts.map +1 -1
  84. package/dist/directive/directive-queue.js +4 -1
  85. package/dist/directive/directive-queue.js.map +1 -1
  86. package/dist/drift/staleness-sensor.d.ts +14 -0
  87. package/dist/drift/staleness-sensor.d.ts.map +1 -1
  88. package/dist/drift/staleness-sensor.js +30 -1
  89. package/dist/drift/staleness-sensor.js.map +1 -1
  90. package/dist/focus/focus-executor.d.ts.map +1 -1
  91. package/dist/focus/focus-executor.js +6 -8
  92. package/dist/focus/focus-executor.js.map +1 -1
  93. package/dist/focus/focus-loop-registry.d.ts.map +1 -1
  94. package/dist/focus/focus-loop-registry.js +23 -13
  95. package/dist/focus/focus-loop-registry.js.map +1 -1
  96. package/dist/focus/focus-respawn-guard.d.ts.map +1 -1
  97. package/dist/focus/focus-respawn-guard.js +21 -4
  98. package/dist/focus/focus-respawn-guard.js.map +1 -1
  99. package/dist/focus/listener-auto-advance.d.ts.map +1 -1
  100. package/dist/focus/listener-auto-advance.js +10 -6
  101. package/dist/focus/listener-auto-advance.js.map +1 -1
  102. package/dist/focus/verify-open-issues.d.ts.map +1 -1
  103. package/dist/focus/verify-open-issues.js +21 -1
  104. package/dist/focus/verify-open-issues.js.map +1 -1
  105. package/dist/focus-stage-lifecycle/wedge-watchdog.d.ts.map +1 -1
  106. package/dist/focus-stage-lifecycle/wedge-watchdog.js +35 -14
  107. package/dist/focus-stage-lifecycle/wedge-watchdog.js.map +1 -1
  108. package/dist/loops/index.d.ts.map +1 -1
  109. package/dist/loops/index.js +2 -1
  110. package/dist/loops/index.js.map +1 -1
  111. package/dist/merge/focus-merge.d.ts +1 -1
  112. package/dist/merge/focus-merge.d.ts.map +1 -1
  113. package/dist/merge/focus-merge.js +5 -1
  114. package/dist/merge/focus-merge.js.map +1 -1
  115. package/dist/merge/merge-back-loop.d.ts +2 -1
  116. package/dist/merge/merge-back-loop.d.ts.map +1 -1
  117. package/dist/merge/merge-back-loop.js +15 -12
  118. package/dist/merge/merge-back-loop.js.map +1 -1
  119. package/dist/merge/merge-conflict-escalation.d.ts.map +1 -1
  120. package/dist/merge/merge-conflict-escalation.js +4 -0
  121. package/dist/merge/merge-conflict-escalation.js.map +1 -1
  122. package/dist/nexus/return.d.ts +14 -15
  123. package/dist/nexus/return.d.ts.map +1 -1
  124. package/dist/nexus/return.js +41 -31
  125. package/dist/nexus/return.js.map +1 -1
  126. package/dist/prompt-sections/execution-sections.d.ts +13 -5
  127. package/dist/prompt-sections/execution-sections.d.ts.map +1 -1
  128. package/dist/prompt-sections/execution-sections.js +78 -18
  129. package/dist/prompt-sections/execution-sections.js.map +1 -1
  130. package/dist/prompt-sections/routing-decider-sections.d.ts +60 -0
  131. package/dist/prompt-sections/routing-decider-sections.d.ts.map +1 -0
  132. package/dist/prompt-sections/routing-decider-sections.js +197 -0
  133. package/dist/prompt-sections/routing-decider-sections.js.map +1 -0
  134. package/dist/queries/agent-resolvable-aging.d.ts +4 -3
  135. package/dist/queries/agent-resolvable-aging.d.ts.map +1 -1
  136. package/dist/queries/agent-resolvable-aging.js +5 -4
  137. package/dist/queries/agent-resolvable-aging.js.map +1 -1
  138. package/dist/queries/agent-resolvable-promotion.d.ts +172 -124
  139. package/dist/queries/agent-resolvable-promotion.d.ts.map +1 -1
  140. package/dist/queries/agent-resolvable-promotion.js +332 -307
  141. package/dist/queries/agent-resolvable-promotion.js.map +1 -1
  142. package/dist/queries/agent-resolvable-retirement.d.ts +105 -0
  143. package/dist/queries/agent-resolvable-retirement.d.ts.map +1 -0
  144. package/dist/queries/agent-resolvable-retirement.js +227 -0
  145. package/dist/queries/agent-resolvable-retirement.js.map +1 -0
  146. package/dist/queries/cause-key.d.ts +109 -0
  147. package/dist/queries/cause-key.d.ts.map +1 -1
  148. package/dist/queries/cause-key.js +93 -1
  149. package/dist/queries/cause-key.js.map +1 -1
  150. package/dist/queries/deliveries.d.ts +14 -0
  151. package/dist/queries/deliveries.d.ts.map +1 -1
  152. package/dist/queries/deliveries.js +20 -2
  153. package/dist/queries/deliveries.js.map +1 -1
  154. package/dist/queries/delivery-gate-state.d.ts +130 -5
  155. package/dist/queries/delivery-gate-state.d.ts.map +1 -1
  156. package/dist/queries/delivery-gate-state.js +111 -2
  157. package/dist/queries/delivery-gate-state.js.map +1 -1
  158. package/dist/queries/escalation-consumption.d.ts +95 -15
  159. package/dist/queries/escalation-consumption.d.ts.map +1 -1
  160. package/dist/queries/escalation-consumption.js +162 -24
  161. package/dist/queries/escalation-consumption.js.map +1 -1
  162. package/dist/queries/escalation-dispositions.d.ts +19 -7
  163. package/dist/queries/escalation-dispositions.d.ts.map +1 -1
  164. package/dist/queries/escalation-dispositions.js +7 -0
  165. package/dist/queries/escalation-dispositions.js.map +1 -1
  166. package/dist/queries/escalation-suppression.d.ts +63 -19
  167. package/dist/queries/escalation-suppression.d.ts.map +1 -1
  168. package/dist/queries/escalation-suppression.js +64 -35
  169. package/dist/queries/escalation-suppression.js.map +1 -1
  170. package/dist/queries/escalations.d.ts +127 -70
  171. package/dist/queries/escalations.d.ts.map +1 -1
  172. package/dist/queries/escalations.js +170 -188
  173. package/dist/queries/escalations.js.map +1 -1
  174. package/dist/queries/filing-observation.d.ts +82 -0
  175. package/dist/queries/filing-observation.d.ts.map +1 -0
  176. package/dist/queries/filing-observation.js +157 -0
  177. package/dist/queries/filing-observation.js.map +1 -0
  178. package/dist/queries/holds.d.ts +69 -2
  179. package/dist/queries/holds.d.ts.map +1 -1
  180. package/dist/queries/holds.js +106 -11
  181. package/dist/queries/holds.js.map +1 -1
  182. package/dist/queries/incident-correlation.d.ts +291 -0
  183. package/dist/queries/incident-correlation.d.ts.map +1 -0
  184. package/dist/queries/incident-correlation.js +408 -0
  185. package/dist/queries/incident-correlation.js.map +1 -0
  186. package/dist/queries/routing-measurement.d.ts +48 -1
  187. package/dist/queries/routing-measurement.d.ts.map +1 -1
  188. package/dist/queries/routing-measurement.js +64 -2
  189. package/dist/queries/routing-measurement.js.map +1 -1
  190. package/dist/queries/routing-quality.d.ts +8 -0
  191. package/dist/queries/routing-quality.d.ts.map +1 -1
  192. package/dist/queries/routing-quality.js +12 -3
  193. package/dist/queries/routing-quality.js.map +1 -1
  194. package/dist/queries/shared.js +1 -1
  195. package/dist/shell/crash-recovery.d.ts.map +1 -1
  196. package/dist/shell/crash-recovery.js +6 -6
  197. package/dist/shell/crash-recovery.js.map +1 -1
  198. package/dist/shell/install-probe-tick.d.ts.map +1 -1
  199. package/dist/shell/install-probe-tick.js +3 -1
  200. package/dist/shell/install-probe-tick.js.map +1 -1
  201. package/dist/spawn/model-routing.d.ts +3 -2
  202. package/dist/spawn/model-routing.d.ts.map +1 -1
  203. package/dist/spawn/model-routing.js +4 -2
  204. package/dist/spawn/model-routing.js.map +1 -1
  205. package/dist/spawn/respawn-cycle-escalation.d.ts +10 -2
  206. package/dist/spawn/respawn-cycle-escalation.d.ts.map +1 -1
  207. package/dist/spawn/respawn-cycle-escalation.js +16 -2
  208. package/dist/spawn/respawn-cycle-escalation.js.map +1 -1
  209. package/dist/spawn/routing-decider-spawn.d.ts +93 -0
  210. package/dist/spawn/routing-decider-spawn.d.ts.map +1 -0
  211. package/dist/spawn/routing-decider-spawn.js +185 -0
  212. package/dist/spawn/routing-decider-spawn.js.map +1 -0
  213. package/dist/spawn/routing-decider.d.ts +42 -0
  214. package/dist/spawn/routing-decider.d.ts.map +1 -0
  215. package/dist/spawn/routing-decider.js +95 -0
  216. package/dist/spawn/routing-decider.js.map +1 -0
  217. package/dist/spawn/shared.d.ts +8 -0
  218. package/dist/spawn/shared.d.ts.map +1 -1
  219. package/dist/spawn/shared.js +1 -1
  220. package/dist/spawn/shared.js.map +1 -1
  221. package/dist/spawn/spawn-decision.d.ts +23 -16
  222. package/dist/spawn/spawn-decision.d.ts.map +1 -1
  223. package/dist/spawn/spawn-decision.js +27 -11
  224. package/dist/spawn/spawn-decision.js.map +1 -1
  225. package/dist/spawn/worktree-session.d.ts +19 -7
  226. package/dist/spawn/worktree-session.d.ts.map +1 -1
  227. package/dist/spawn/worktree-session.js +36 -8
  228. package/dist/spawn/worktree-session.js.map +1 -1
  229. package/dist/testing/fixtures/index.js +1 -1
  230. package/dist/types/index.js +1 -1
  231. package/dist/verify/failure-signature.d.ts +91 -0
  232. package/dist/verify/failure-signature.d.ts.map +1 -0
  233. package/dist/verify/failure-signature.js +233 -0
  234. package/dist/verify/failure-signature.js.map +1 -0
  235. package/dist/verify/shortfall-repeat.d.ts +12 -9
  236. package/dist/verify/shortfall-repeat.d.ts.map +1 -1
  237. package/dist/verify/shortfall-repeat.js +38 -14
  238. package/dist/verify/shortfall-repeat.js.map +1 -1
  239. package/dist/verify/stall-detectors.d.ts +19 -43
  240. package/dist/verify/stall-detectors.d.ts.map +1 -1
  241. package/dist/verify/stall-detectors.js +26 -101
  242. package/dist/verify/stall-detectors.js.map +1 -1
  243. package/dist/verify/unreviewed-settle-detector.d.ts +8 -0
  244. package/dist/verify/unreviewed-settle-detector.d.ts.map +1 -1
  245. package/dist/verify/unreviewed-settle-detector.js +15 -1
  246. package/dist/verify/unreviewed-settle-detector.js.map +1 -1
  247. package/dist/verify/verification-deps-default.d.ts.map +1 -1
  248. package/dist/verify/verification-deps-default.js +14 -2
  249. package/dist/verify/verification-deps-default.js.map +1 -1
  250. package/dist/verify/verification-evidence-unavailable-feedback.d.ts.map +1 -1
  251. package/dist/verify/verification-evidence-unavailable-feedback.js +8 -2
  252. package/dist/verify/verification-evidence-unavailable-feedback.js.map +1 -1
  253. package/dist/verify/verification-feedback.d.ts +62 -14
  254. package/dist/verify/verification-feedback.d.ts.map +1 -1
  255. package/dist/verify/verification-feedback.js +101 -28
  256. package/dist/verify/verification-feedback.js.map +1 -1
  257. package/dist/verify/verify-gate-stall.d.ts +116 -0
  258. package/dist/verify/verify-gate-stall.d.ts.map +1 -0
  259. package/dist/verify/verify-gate-stall.js +169 -0
  260. package/dist/verify/verify-gate-stall.js.map +1 -0
  261. package/dist/verify/verify-restatement.d.ts.map +1 -1
  262. package/dist/verify/verify-restatement.js +2 -1
  263. package/dist/verify/verify-restatement.js.map +1 -1
  264. package/package.json +2 -2
package/build-info.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "commitSha": "5c9fc3050",
3
- "builtAt": "2026-09-12T21:33:19.492Z",
2
+ "commitSha": "3d97b05fa",
3
+ "builtAt": "2026-09-13T12:14:24.490Z",
4
4
  "expectedMigrations": [
5
5
  "20250829113330_create_org_nodes_table.sql",
6
6
  "20250829113402_fix_function_security_search_path.sql",
@@ -785,6 +785,7 @@
785
785
  "20260909203246_review_complete_stamps_reviewed_through_sha.sql",
786
786
  "20260911015223_add_created_by_session_id_to_issues.sql",
787
787
  "20260911215819_org_default_pass_models.sql",
788
- "20260911232237_org_default_pass_models_setter.sql"
788
+ "20260911232237_org_default_pass_models_setter.sql",
789
+ "20260913005752_agent_escalations_resolution_class_floor.sql"
789
790
  ]
790
791
  }
@@ -1,3 +1,5 @@
1
+ import { createEscalation } from '../queries/escalations.js';
2
+ import { NO_HUMAN_ACT, type HumanAct } from '../queries/filing-observation.js';
1
3
  export declare const CD_PUSH_FAILED_KIND = "cd_push_failed";
2
4
  /**
3
5
  * Returns true when a CD push escalation should be filed for `result`.
@@ -15,6 +17,18 @@ export declare function shouldFileCdPushEscalation(pushToRemote: boolean, result
15
17
  success: boolean;
16
18
  error?: string;
17
19
  }): boolean;
20
+ /**
21
+ * Pure: the act only a human can perform for a CD push failure, or NO_HUMAN_ACT.
22
+ *
23
+ * Branch protection, the daemon host's git credential, and the host checkout's
24
+ * remote configuration all live outside the repo and outside any agent session,
25
+ * so each names a specific act. Every other push failure (non-fast-forward, a
26
+ * network blip, an unrecognized error) is retry / rebase work the machine owns:
27
+ * NO_HUMAN_ACT, so the filing chokepoint files it as an observation. Policy is
28
+ * checked before auth because a protection refusal commonly also prints
29
+ * "Permission denied".
30
+ */
31
+ export declare function cdPushHumanAct(pushError: string): HumanAct | typeof NO_HUMAN_ACT;
18
32
  export interface CdPushEscalationParams {
19
33
  organizationId: string;
20
34
  sessionId: string;
@@ -27,5 +41,7 @@ export interface CdPushEscalationParams {
27
41
  * File a `cd_push_failed` escalation. Best-effort — swallow the failure
28
42
  * so the caller's finally/cleanup path isn't disrupted by a logging hiccup.
29
43
  */
30
- export declare function fileCdPushEscalation(params: CdPushEscalationParams): Promise<void>;
44
+ export declare function fileCdPushEscalation(params: CdPushEscalationParams, deps?: {
45
+ createEscalation: typeof createEscalation;
46
+ }): Promise<void>;
31
47
  //# sourceMappingURL=ci-escalation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ci-escalation.d.ts","sourceRoot":"","sources":["../../src/ci/ci-escalation.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,OAAO,EACrB,MAAM,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAET;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAoCf"}
1
+ {"version":3,"file":"ci-escalation.d.ts","sourceRoot":"","sources":["../../src/ci/ci-escalation.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAM/E,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,OAAO,EACrB,MAAM,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAET;AAaD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,YAAY,CA0BhF;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,sBAAsB,EAC9B,IAAI,GAAE;IAAE,gBAAgB,EAAE,OAAO,gBAAgB,CAAA;CAAyB,GACzE,OAAO,CAAC,IAAI,CAAC,CAsCf"}
@@ -8,9 +8,14 @@
8
8
  * the push fails for any reason — no remote configured, auth failure,
9
9
  * non-fast-forward, network — the failure must surface as a visible
10
10
  * escalation rather than disappearing into the log.
11
+ *
12
+ * Routing: the filing reaches a human only when the push error names an act no
13
+ * agent session can perform (cdPushHumanAct). Otherwise it is filed as an
14
+ * observation the machine owns (see queries/filing-observation.ts).
11
15
  */
12
16
  import { ESCALATION_REASONS, ESCALATION_DISPOSITIONS } from '@telora/daemon-core';
13
17
  import { createEscalation } from '../queries/escalations.js';
18
+ import { NO_HUMAN_ACT } from '../queries/filing-observation.js';
14
19
  import { createLogger } from '../shell/log.js';
15
20
  const log = createLogger({ module: 'CD' });
16
21
  export const CD_PUSH_FAILED_KIND = 'cd_push_failed';
@@ -29,20 +34,63 @@ export const CD_PUSH_FAILED_KIND = 'cd_push_failed';
29
34
  export function shouldFileCdPushEscalation(pushToRemote, result) {
30
35
  return pushToRemote && !result.success && !!result.error && /push/i.test(result.error);
31
36
  }
37
+ /** The remote refused the push by POLICY (branch protection / a server-side hook). */
38
+ const PUSH_REFUSED_BY_POLICY_RE = /protected branch|branch \S+ is protected|branch protection|GH006|pre-receive hook declined|not allowed to push/i;
39
+ /** The remote refused the push by IDENTITY (the daemon host's credential). */
40
+ const PUSH_REFUSED_BY_AUTH_RE = /permission denied|authentication failed|could not read (?:username|password)|access denied|publickey|invalid credentials|not authorized|\b40[13]\b/i;
41
+ /** There is no remote to push to at all. */
42
+ const PUSH_NO_REMOTE_RE = /no origin remote configured/i;
43
+ /**
44
+ * Pure: the act only a human can perform for a CD push failure, or NO_HUMAN_ACT.
45
+ *
46
+ * Branch protection, the daemon host's git credential, and the host checkout's
47
+ * remote configuration all live outside the repo and outside any agent session,
48
+ * so each names a specific act. Every other push failure (non-fast-forward, a
49
+ * network blip, an unrecognized error) is retry / rebase work the machine owns:
50
+ * NO_HUMAN_ACT, so the filing chokepoint files it as an observation. Policy is
51
+ * checked before auth because a protection refusal commonly also prints
52
+ * "Permission denied".
53
+ */
54
+ export function cdPushHumanAct(pushError) {
55
+ if (PUSH_REFUSED_BY_POLICY_RE.test(pushError)) {
56
+ return {
57
+ kind: 'unreachable_capability',
58
+ act: "Allow the daemon's CD push to main through the remote's branch protection " +
59
+ '(or turn off cd.enabled for this product) -- the remote refused the push by policy.',
60
+ };
61
+ }
62
+ if (PUSH_REFUSED_BY_AUTH_RE.test(pushError)) {
63
+ return {
64
+ kind: 'unreachable_capability',
65
+ act: "Grant the daemon host's git credential push access to main on the remote -- " +
66
+ 'the push was rejected as unauthenticated or unauthorized.',
67
+ };
68
+ }
69
+ if (PUSH_NO_REMOTE_RE.test(pushError)) {
70
+ return {
71
+ kind: 'unreachable_capability',
72
+ act: "Configure an origin remote for this repository's checkout on the daemon host " +
73
+ '(or turn off cd.enabled for this product) -- CD has no remote to push to.',
74
+ };
75
+ }
76
+ return NO_HUMAN_ACT;
77
+ }
32
78
  /**
33
79
  * File a `cd_push_failed` escalation. Best-effort — swallow the failure
34
80
  * so the caller's finally/cleanup path isn't disrupted by a logging hiccup.
35
81
  */
36
- export async function fileCdPushEscalation(params) {
82
+ export async function fileCdPushEscalation(params, deps = { createEscalation }) {
37
83
  const { organizationId, sessionId, focusId, focusName, integrationBranch, pushError } = params;
38
84
  try {
39
- await createEscalation({
85
+ await deps.createEscalation({
40
86
  organizationId,
41
87
  sessionId,
42
88
  issueId: null,
43
89
  reasonType: ESCALATION_REASONS.ERROR_ENCOUNTERED,
44
- // Operator triage: auth / branch protection / network at the remote.
45
90
  disposition: ESCALATION_DISPOSITIONS.NEEDS_OPERATOR,
91
+ // A named act only for a remote-policy / credential / remote-config refusal;
92
+ // any other push failure is machine retry work (observation).
93
+ humanAct: cdPushHumanAct(pushError),
46
94
  anchor: { focusId, branch: integrationBranch },
47
95
  description: `CD push to remote failed after merging ${integrationBranch} into main.\n\n` +
48
96
  `**Focus:** ${focusName}\n` +
@@ -1 +1 @@
1
- {"version":3,"file":"ci-escalation.js","sourceRoot":"","sources":["../../src/ci/ci-escalation.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,0DAA0D;AAC1D,gBAAgB;AAEhB;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAG3C,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CACxC,YAAqB,EACrB,MAA4C;IAE5C,OAAO,YAAY,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzF,CAAC;AAWD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAA8B;IAE9B,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAC/F,IAAI,CAAC;QACH,MAAM,gBAAgB,CAAC;YACrB,cAAc;YACd,SAAS;YACT,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,kBAAkB,CAAC,iBAAiB;YAChD,qEAAqE;YACrE,WAAW,EAAE,uBAAuB,CAAC,cAAc;YACnD,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE;YAC9C,WAAW,EACT,0CAA0C,iBAAiB,iBAAiB;gBAC5E,cAAc,SAAS,IAAI;gBAC3B,iBAAiB,OAAO,IAAI;gBAC5B,cAAc,SAAS,MAAM;gBAC7B,oFAAoF;gBACpF,6DAA6D;YAC/D,YAAY,EAAE,+CAA+C;YAC7D,UAAU,EACR,uEAAuE;gBACvE,0DAA0D;YAC5D,cAAc,EAAE,mBAAmB;YACnC,2EAA2E;YAC3E,QAAQ,EAAE;gBACR,kBAAkB,EAAE,iBAAiB;gBACrC,UAAU,EAAE,SAAS;aACtB;SACF,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,6CAA6C,OAAO,MAAM,SAAS,IAAI,CAAC,CAAC;IACpF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CACN,2DAA2D,OAAO,GAAG,EACpE,GAAa,CAAC,OAAO,CACvB,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ci-escalation.js","sourceRoot":"","sources":["../../src/ci/ci-escalation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Attribution of a red integration run to the focus (and delivery) whose merge
3
+ * INTRODUCED the red tip -- or to nobody, when that cannot be determined.
4
+ *
5
+ * The red run's anchor is what the ci_run_red filing routes to and what the
6
+ * incident reducer groups it under, so a WRONG anchor is worse than none: it
7
+ * rides the fix into an unrelated focus's coding pass and correlates the red
8
+ * with that focus's unrelated symptoms. Hence the rule: attribute only when the
9
+ * tip's introduced work resolves to exactly ONE focus; otherwise return the
10
+ * unattributed anchor and let the caller file branch-only. There is no "any
11
+ * active focus" fallback -- that fallback was a guess.
12
+ *
13
+ * Which commits did the tip introduce? For a non-merge tip, the tip itself (its
14
+ * own `Telora-Delivery` trailer). For a MERGE tip, the commits reachable from the
15
+ * tip and not from its INTEGRATION-SIDE parent. Git records the branch a merge was
16
+ * made ON as the first parent, and integration receives merges in two shapes:
17
+ * - a merge made ON integration (mergeToIntegration's `--no-ff` "Merge agent
18
+ * work", the main->integration sync): ^1 is integration, the work is ^2's side.
19
+ * - a MERGE-BACK made on a focus branch (`git merge origin/integration`) that
20
+ * integration then FAST-FORWARDED to (mergeToIntegration tries `--ff-only`
21
+ * first): ^1 is the FOCUS branch, ^2 is the old integration tip, and the work
22
+ * is ^1's side.
23
+ * The merge-back shape is the common one (38 of 43 merge tips on integration from
24
+ * 2026-08-20 to 2026-09-12), and the former resolver walked `^1...tip` for it --
25
+ * i.e. the OTHER foci's integration commits the focus had just merged back -- so
26
+ * a red run was attributed to whichever focus last merged before the one that
27
+ * turned it red (e.g. tip d58280129 resolved to the migration-gate focus's
28
+ * 094e94351 instead of its own 4cf454a73). The merge-back shape is recognized by
29
+ * git's default merge subject naming the integration branch as the merged-in ref.
30
+ *
31
+ * Best-effort: any git/DB failure degrades to the unattributed anchor, never throws.
32
+ *
33
+ * @module ci-red-attribution
34
+ */
35
+ import type { DaemonConfig } from '../types/index.js';
36
+ /** The anchor a red integration run is filed against. Both null = branch-only. */
37
+ export interface CiRedRunAnchor {
38
+ focusId: string | null;
39
+ /** Set only when the introduced work of the attributed focus is ONE delivery. */
40
+ deliveryId: string | null;
41
+ }
42
+ /** The branch-only anchor: the red run could not be attributed to one focus. */
43
+ export declare const UNATTRIBUTED_RED_RUN: Readonly<CiRedRunAnchor>;
44
+ /** Injected IO for red-run attribution: git reads + the delivery->focus DB lookup. */
45
+ export interface RedRunAttributionDeps {
46
+ /** The commit's raw `Telora-Delivery` trailer value ('' when absent). */
47
+ readTrailer: (repoPath: string, sha: string) => string;
48
+ /** The commit's parent shas, in order (empty on failure). */
49
+ readParents: (repoPath: string, sha: string) => string[];
50
+ /** The commit's subject line ('' on failure). */
51
+ readSubject: (repoPath: string, sha: string) => string;
52
+ /** `git rev-list <range>` (empty on failure). */
53
+ listCommits: (repoPath: string, range: string) => string[];
54
+ /** delivery id -> owning focus id (null when unknown). */
55
+ focusForDelivery: (deliveryId: string) => Promise<string | null>;
56
+ }
57
+ export declare function readCommitParents(repoPath: string, sha: string): string[];
58
+ export declare function readCommitSubject(repoPath: string, sha: string): string;
59
+ /**
60
+ * Whether a merge commit's subject is git's default message for merging the
61
+ * INTEGRATION branch in (`Merge branch 'integration' ...` / `Merge
62
+ * remote-tracking branch 'origin/integration' ...`) -- the merge-back shape,
63
+ * whose SECOND parent is the integration side. PURE.
64
+ */
65
+ export declare function mergedInIntegration(subject: string, integrationBranch: string): boolean;
66
+ /**
67
+ * The integration-side parent of a merge tip: ^2 for a merge-back that integration
68
+ * fast-forwarded to, ^1 otherwise. Null for a non-merge. PURE.
69
+ */
70
+ export declare function integrationSideParent(parents: readonly string[], subject: string, integrationBranch: string): string | null;
71
+ /**
72
+ * Decide the anchor from the deliveries the tip introduced (delivery -> owning
73
+ * focus, null when unknown). Exactly one focus -> that focus, plus the delivery
74
+ * when it is the only one of that focus; zero or several foci -> unattributed.
75
+ * A delivery whose focus is unknown is ignored rather than guessed at. PURE.
76
+ */
77
+ export declare function decideRedRunAnchor(focusByDelivery: ReadonlyMap<string, string | null>): CiRedRunAnchor;
78
+ /**
79
+ * Resolve the anchor for a red run on `sha` (the integration tip). Order: (1) the
80
+ * tip's own trailer; (2) for a merge tip, the deliveries of the commits it
81
+ * introduced relative to its integration-side parent. Unattributable -> the
82
+ * branch-only anchor (never a fallback focus).
83
+ */
84
+ export declare function resolveRedRunAnchor(config: DaemonConfig, sha: string, deps?: RedRunAttributionDeps): Promise<CiRedRunAnchor>;
85
+ //# sourceMappingURL=ci-red-attribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-red-attribution.d.ts","sourceRoot":"","sources":["../../src/ci/ci-red-attribution.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAQtD,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iFAAiF;IACjF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,cAAc,CAAsD,CAAC;AAEjH,sFAAsF;AACtF,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,6DAA6D;IAC7D,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACzD,iDAAiD;IACjD,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,iDAAiD;IACjD,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAC3D,0DAA0D;IAC1D,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAClE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAIzE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGvE;AAsBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAKvF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GACxB,MAAM,GAAG,IAAI,CAGf;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,cAAc,CAQtG;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,qBAAmC,GACxC,OAAO,CAAC,cAAc,CAAC,CAwBzB"}
@@ -0,0 +1,108 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/ci/ci-owning-focus-resolve.test.ts
3
+ // PINNED-BY-END
4
+ import { runGitSync } from '../git/exec.js';
5
+ import { getDeliveryContext } from '../queries/deliveries.js';
6
+ import { readDeliveryTrailer, listRangeCommits } from '../resolvers/shared/git-diff.js';
7
+ import { createLogger } from '../shell/log.js';
8
+ const log = createLogger({ module: 'ci-red-attribution' });
9
+ /** The branch-only anchor: the red run could not be attributed to one focus. */
10
+ export const UNATTRIBUTED_RED_RUN = Object.freeze({ focusId: null, deliveryId: null });
11
+ export function readCommitParents(repoPath, sha) {
12
+ const result = runGitSync(['rev-list', '--parents', '-n', '1', `${sha}^{commit}`], repoPath);
13
+ if (!result.success)
14
+ return [];
15
+ return result.output.trim().split(/\s+/).filter((p) => p !== '').slice(1);
16
+ }
17
+ export function readCommitSubject(repoPath, sha) {
18
+ const result = runGitSync(['show', '-s', '--format=%s', `${sha}^{commit}`], repoPath);
19
+ return result.success ? result.output.trim() : '';
20
+ }
21
+ const defaultDeps = {
22
+ readTrailer: readDeliveryTrailer,
23
+ readParents: readCommitParents,
24
+ readSubject: readCommitSubject,
25
+ listCommits: listRangeCommits,
26
+ focusForDelivery: async (deliveryId) => (await getDeliveryContext(deliveryId))?.focus?.id ?? null,
27
+ };
28
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
29
+ /** A trailer value that names a delivery (the `none` sentinel and junk do not). */
30
+ function asDeliveryId(trailer) {
31
+ const value = trailer.trim();
32
+ return UUID_RE.test(value) ? value : null;
33
+ }
34
+ function escapeRegExp(value) {
35
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
36
+ }
37
+ /**
38
+ * Whether a merge commit's subject is git's default message for merging the
39
+ * INTEGRATION branch in (`Merge branch 'integration' ...` / `Merge
40
+ * remote-tracking branch 'origin/integration' ...`) -- the merge-back shape,
41
+ * whose SECOND parent is the integration side. PURE.
42
+ */
43
+ export function mergedInIntegration(subject, integrationBranch) {
44
+ const branch = escapeRegExp(integrationBranch);
45
+ // The ref prefix is a REMOTE name, so it is allowed only in the remote-tracking
46
+ // form; a local `Merge branch 'agent/integration'` is some other branch.
47
+ return new RegExp(`^Merge (?:remote-tracking branch '[^'/]+/${branch}'|branch '${branch}')`).test(subject);
48
+ }
49
+ /**
50
+ * The integration-side parent of a merge tip: ^2 for a merge-back that integration
51
+ * fast-forwarded to, ^1 otherwise. Null for a non-merge. PURE.
52
+ */
53
+ export function integrationSideParent(parents, subject, integrationBranch) {
54
+ if (parents.length < 2)
55
+ return null;
56
+ return (mergedInIntegration(subject, integrationBranch) ? parents[1] : parents[0]) ?? null;
57
+ }
58
+ /**
59
+ * Decide the anchor from the deliveries the tip introduced (delivery -> owning
60
+ * focus, null when unknown). Exactly one focus -> that focus, plus the delivery
61
+ * when it is the only one of that focus; zero or several foci -> unattributed.
62
+ * A delivery whose focus is unknown is ignored rather than guessed at. PURE.
63
+ */
64
+ export function decideRedRunAnchor(focusByDelivery) {
65
+ const foci = new Set();
66
+ for (const focusId of focusByDelivery.values())
67
+ if (focusId)
68
+ foci.add(focusId);
69
+ if (foci.size !== 1)
70
+ return { ...UNATTRIBUTED_RED_RUN };
71
+ const [focusId] = [...foci];
72
+ if (!focusId)
73
+ return { ...UNATTRIBUTED_RED_RUN };
74
+ const deliveries = [...focusByDelivery].filter(([, f]) => f === focusId).map(([d]) => d);
75
+ return { focusId, deliveryId: deliveries.length === 1 ? (deliveries[0] ?? null) : null };
76
+ }
77
+ /**
78
+ * Resolve the anchor for a red run on `sha` (the integration tip). Order: (1) the
79
+ * tip's own trailer; (2) for a merge tip, the deliveries of the commits it
80
+ * introduced relative to its integration-side parent. Unattributable -> the
81
+ * branch-only anchor (never a fallback focus).
82
+ */
83
+ export async function resolveRedRunAnchor(config, sha, deps = defaultDeps) {
84
+ try {
85
+ const own = asDeliveryId(deps.readTrailer(config.repoPath, sha));
86
+ if (own) {
87
+ const focusId = await deps.focusForDelivery(own);
88
+ if (focusId)
89
+ return { focusId, deliveryId: own };
90
+ }
91
+ const base = integrationSideParent(deps.readParents(config.repoPath, sha), deps.readSubject(config.repoPath, sha), config.integrationBranch);
92
+ if (!base)
93
+ return { ...UNATTRIBUTED_RED_RUN };
94
+ const focusByDelivery = new Map();
95
+ for (const commit of deps.listCommits(config.repoPath, `${base}..${sha}`)) {
96
+ const deliveryId = asDeliveryId(deps.readTrailer(config.repoPath, commit));
97
+ if (!deliveryId || focusByDelivery.has(deliveryId))
98
+ continue;
99
+ focusByDelivery.set(deliveryId, await deps.focusForDelivery(deliveryId));
100
+ }
101
+ return decideRedRunAnchor(focusByDelivery);
102
+ }
103
+ catch (err) {
104
+ log.debug(`red-run attribution failed for ${sha.slice(0, 12)}: ${err.message}`);
105
+ return { ...UNATTRIBUTED_RED_RUN };
106
+ }
107
+ }
108
+ //# sourceMappingURL=ci-red-attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-red-attribution.js","sourceRoot":"","sources":["../../src/ci/ci-red-attribution.ts"],"names":[],"mappings":"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"}
@@ -11,25 +11,28 @@
11
11
  * so the loop is unit-testable without a live remote or DB.
12
12
  *
13
13
  * The filing is a MACHINE receiver, not a human inbox line. Fixing a failing
14
- * lint/typecheck/test/build gate is CODING work, so the filing carries
15
- * disposition `agent_resolvable` (hidden from the operator inbox) anchored to a
16
- * FOCUS, so the daemon's focus-scoped agent_resolvable pickup
17
- * (reconcileAgentResolvableForFocus) rides it into that focus's next CODING pass
18
- * to be resolved. The ONLY path from here to a `needs_operator` filing is the
19
- * existing 24h agent_resolvable promotion backstop, after the machine has had
20
- * spawn cycles to clear it and has not -- never a direct operator filing.
14
+ * lint/typecheck/test/build gate is CODING work, so a focus-attributed filing
15
+ * carries disposition `agent_resolvable` (hidden from the operator inbox), and
16
+ * the daemon's focus-scoped pickup (reconcileAgentResolvableForFocus) rides it
17
+ * into that focus's next CODING pass. A BRANCH-ONLY filing (below) has no spawn
18
+ * to ride, so it is filed as a detector OBSERVATION (proposed needs_operator, no
19
+ * human act -- the fix is still coding work): with no focus anchor, the org-wide
20
+ * hand-off sweep (queries/agent-resolvable-promotion.ts) gives it to the routing
21
+ * decider agent on its next pass, and only that agent can make it human-facing.
22
+ * Neither path files a direct operator line (see ciRunRedEscalationParams).
21
23
  *
22
- * Anchor choice (decided, reversible): the tip's OWNING focus, resolved from the
23
- * tip commit's `Telora-Delivery` trailer -> delivery -> focus; falling back to
24
- * any currently-active focus for the product (a CI-gate fix is cross-cutting, so
25
- * any armed team can take it). If NO focus is armed at all there is no coding
26
- * pass to route the fix to, so the tick files nothing and retries next tick --
27
- * the fail-closed integration->main merge gate (resolveCiMergeGate, which reads
28
- * the git ref independently of this escalation) still holds main out on the red,
29
- * so nothing merges while the signal waits for a team. The recorded alternative,
30
- * a standing per-product "CI health" focus, would remove the fallback heuristic
31
- * but is a larger change (new focus lifecycle) and can replace this later with
32
- * no data migration.
24
+ * Anchor choice (decided, reversible): the focus -- and, when it is the only one,
25
+ * the delivery -- whose merge INTRODUCED the red tip (ci/ci-red-attribution.ts:
26
+ * the tip's own `Telora-Delivery` trailer, else the deliveries of the commits the
27
+ * merge brought onto integration, read against its integration-side parent). When
28
+ * that is not determinable (no attributable commit, or work from several foci)
29
+ * the filing anchors BRANCH-ONLY, with no focusId -- a wrong focus is worse than
30
+ * none, since it rides the fix into an unrelated team and correlates the red with
31
+ * that focus's unrelated symptoms. The former "any currently-active focus"
32
+ * fallback was that guess and is gone. A branch-only filing has no team to ride
33
+ * into, so the held merge gate is ALSO surfaced as a health event (TEL-6); the
34
+ * fail-closed integration->main merge gate (resolveCiMergeGate, which reads the
35
+ * git ref independently of this escalation) still holds main out on the red.
33
36
  *
34
37
  * The cause key is BRANCH-scoped (queries/cause-key.ciRunRedCauseKey): successive
35
38
  * red tips carrying the same unfixed breakage collapse onto ONE open filing
@@ -42,6 +45,9 @@
42
45
  */
43
46
  import type { DaemonConfig } from '../types/index.js';
44
47
  import { type CiStatusReader } from './ci-status.js';
48
+ import { type CiRedRunAnchor } from './ci-red-attribution.js';
49
+ import { type CreateEscalationParams } from '../queries/escalations.js';
50
+ import { type CallApiDeps } from '../queries/shared.js';
45
51
  /** Health-event code for a red integration run that has no team to route to. */
46
52
  export declare const MERGE_HELD_NO_RECEIVER_CODE = "merge.held_no_receiver";
47
53
  /** Test-only: clear the held-gate dedup state. */
@@ -93,18 +99,25 @@ export declare function ciRunRedEscalationDescription(params: {
93
99
  sha: string;
94
100
  branch: string;
95
101
  }): string;
102
+ /** Params a ci_run_red filing is built from. focusId/deliveryId null = branch-only. */
103
+ export interface CiRedFilingParams {
104
+ organizationId: string;
105
+ productId: string;
106
+ focusId: string | null;
107
+ deliveryId: string | null;
108
+ sha: string;
109
+ branch: string;
110
+ }
96
111
  /**
97
112
  * Structured metadata for a ci_run_red filing: the cause-key routing fields, the
98
- * posture it sets and that posture's termination condition, PLUS the self-
99
- * contained `diagnosis` route (see ciLogDiagnosisRoute) so a team inheriting the
100
- * escalation later reads the same log route the original filing carried. Pure and
101
- * exported so the metadata contract is unit-testable without mocking createEscalation.
113
+ * attributed anchor (focus_id / delivery_id, null when branch-only), the posture
114
+ * it sets and that posture's termination condition, PLUS the self-contained
115
+ * `diagnosis` route (see ciLogDiagnosisRoute) so a team inheriting the escalation
116
+ * later reads the same log route the original filing carried. Pure and exported
117
+ * so the metadata contract is unit-testable without mocking createEscalation.
102
118
  */
103
- export declare function ciRunRedEscalationMetadata(params: {
104
- sha: string;
105
- branch: string;
106
- productId: string;
107
- focusId: string;
119
+ export declare function ciRunRedEscalationMetadata(params: Omit<CiRedFilingParams, 'organizationId' | 'deliveryId'> & {
120
+ deliveryId?: string | null;
108
121
  }): Record<string, unknown>;
109
122
  /** Minimal open-escalation row shape the sensor's dedup / resolve reads. */
110
123
  interface CiEscalationRow {
@@ -115,23 +128,31 @@ interface CiEscalationRow {
115
128
  metadata?: Record<string, unknown> | null;
116
129
  }
117
130
  /**
118
- * Whether a re-file for THIS red sha must be suppressed. Two ways it is:
119
- * - an OPEN or DISMISSED row already carries the same cause key (sha+branch) --
120
- * the cause-keyed path with DISMISSAL MEMORY. This is what fixes the incident
121
- * where an operator dismissed a ci_run_red for a sha and the daemon re-filed
122
- * the SAME sha on the next scan: a dismissed cause_key now keeps it silent
123
- * until a NEW sha (a different cause key) goes red.
124
- * - a legacy OPEN product+kind row with no cause_key exists (deployment-window
125
- * back-compat for rows filed before this change).
126
- *
127
- * A new sha yields a different cause key with no matching open/dismissed row and
128
- * re-files; a later green run resolves the open row via resolveCiRedEscalations.
131
+ * An OPEN ci_run_red row for this product, including the two HAND-OFF rows that
132
+ * stand in for one:
133
+ * - a routing decider's human-facing filing (MCP escalate with sourceCauseKey):
134
+ * kind agent_filed, carrying metadata.original_cause_key `ci_run_red::...` and
135
+ * metadata.originalEscalationId but NO originalKind;
136
+ * - a historic promotion-backstop refile (the daemon no longer files these):
137
+ * re-kinded agent_resolvable_promoted, carrying metadata.originalKind.
138
+ * A row's originalKind, when it carries one, is authoritative for its origin; the
139
+ * original_cause_key prefix decides only for a row without it (the decider's).
140
+ * Covering both lets a later green resolve the human-facing row too (no stale
141
+ * inbox item once the red cleared), and keeps an open one suppressing a fresh
142
+ * branch-only observation. Exported for direct unit testing.
129
143
  */
144
+ export declare function isOpenCiRedForProduct(e: CiEscalationRow, productId: string): boolean;
130
145
  /**
131
146
  * Pure suppression predicate over already-fetched rows. A re-file for this red
132
- * sha is suppressed when an open/dismissed row carries the same cause key
133
- * (dismissal memory), or a legacy open product+kind row exists. Exported for
134
- * direct unit testing (no callApi mocking needed).
147
+ * sha is suppressed when an OPEN or DISMISSED row carries the same cause key
148
+ * (dismissal memory: an operator-dismissed branch stays silent until a new
149
+ * breakage resolves and re-reds it), an OPEN row carries it as a live absorbed
150
+ * symptom (the filing would only be "already carried" by the incident reducer --
151
+ * and a green tick must still see it open, so resolve-on-green retires it), or a
152
+ * legacy OPEN product+kind row with no cause_key exists (deployment-window
153
+ * back-compat). A later green run resolves the open row via
154
+ * resolveCiRedEscalations. Exported for direct unit testing (no callApi mocking
155
+ * needed).
135
156
  */
136
157
  export declare function isCiRedRefileSuppressed(rows: readonly CiEscalationRow[], params: {
137
158
  productId: string;
@@ -139,57 +160,40 @@ export declare function isCiRedRefileSuppressed(rows: readonly CiEscalationRow[]
139
160
  branch: string;
140
161
  }): boolean;
141
162
  /**
142
- * Resolve the focus a red integration run's fix should be routed to. Primary:
143
- * the tip commit's OWNING focus, via its `Telora-Delivery` trailer -> delivery ->
144
- * focus. When the tip is a MERGE commit it carries no trailer of its own -- so
145
- * before giving up, walk the commits the merge introduced (its own work is
146
- * `<sha>^1...<sha>`) and resolve the owning focus from the first commit that DOES
147
- * carry a trailer. Only then fall back to any currently-active focus for the
148
- * product (a CI-gate fix is cross-cutting, so any armed team can take it). Returns
149
- * null when nothing resolves -- there is no coding pass to route the fix to, so
150
- * the caller files nothing and retries next tick (the fail-closed merge gate
151
- * still holds main). Best-effort: any git/DB failure degrades to null, never throws.
163
+ * Resolve-on-green (the production resolveCiRedEscalations): resolve the product's
164
+ * open ci_run_red rows (and the hand-off rows standing in for one: a routing decider's
165
+ * human-facing filing, a historic promoted refile) auto_swept, then retire a ci_run_red
166
+ * absorbed as a symptom onto another open row of the product (incident contract
167
+ * rule 6), over the same read. Best-effort per row. Exported with a callApi seam
168
+ * for tests.
152
169
  */
170
+ export declare function defaultResolveCiRedEscalations(productId: string, deps?: CallApiDeps): Promise<number>;
153
171
  /**
154
- * Injected IO for owning-focus resolution -- git reads + DB lookups, so the
155
- * pure walk order is unit-testable over a real merge without mocking the module.
156
- */
157
- export interface OwningFocusResolverDeps {
158
- readTrailer: (repoPath: string, sha: string) => string;
159
- resolveMergeRange: (repoPath: string, sha: string) => string | null;
160
- listCommits: (repoPath: string, range: string) => string[];
161
- /** delivery id -> owning focus id (null when unknown). */
162
- focusForDelivery: (deliveryId: string) => Promise<string | null>;
163
- /** first currently-active focus id for the product (null when none). */
164
- firstActiveFocus: (config: DaemonConfig) => Promise<string | null>;
165
- }
166
- /**
167
- * Resolve the focus a red run's fix routes to. Order: (1) the tip's own
168
- * `Telora-Delivery` trailer; (2) when the tip is a MERGE (no own trailer), the
169
- * owning focus of the first trailered commit the merge introduced; (3) fallback
170
- * to any active focus. The arbitrary-active-focus fallback is reached ONLY when
171
- * no attributable commit exists at all. Best-effort: any git/DB failure degrades
172
- * to the fallback / null, never throws.
172
+ * The ci_run_red filing. Pure and exported so its routing is unit-testable (the
173
+ * poll-loop tests inject a mock fileCiRedEscalation).
174
+ *
175
+ * - Focus-attributed: agent_resolvable. Fixing a failing CI gate is CODING work;
176
+ * the focus whose merge turned integration red carries it into its next coding
177
+ * pass (the focus-scoped agent_resolvable pickup).
178
+ * - Branch-only: a plain agent_resolvable row reaches no spawn and is never
179
+ * promoted, so the red would sit invisible while the merge gate holds main. It
180
+ * is proposed needs_operator with an explicit NO_HUMAN_ACT (the fix is still
181
+ * coding work, not a human act), so the filing chokepoint files it as a
182
+ * detector OBSERVATION, which the anchorless promotion sweep surfaces next pass.
173
183
  */
174
- export declare function resolveOwningFocus(config: DaemonConfig, sha: string, deps?: OwningFocusResolverDeps): Promise<string | null>;
184
+ export declare function ciRunRedEscalationParams(params: CiRedFilingParams): CreateEscalationParams;
175
185
  /** Injected IO for the sensor tick. Defaults reach for the real implementations. */
176
186
  export interface CiSensorDeps {
177
187
  getCiStatus: CiStatusReader;
178
188
  resolveIntegrationTip: (config: DaemonConfig) => string | null;
179
- /** Resolve the focus a red run's fix routes to (tip-owner, fallback active). */
180
- resolveOwningFocus: (config: DaemonConfig, sha: string) => Promise<string | null>;
189
+ /** Attribute a red run to the focus/delivery whose merge introduced it (branch-only when not determinable). */
190
+ resolveRedRunAnchor: (config: DaemonConfig, sha: string) => Promise<CiRedRunAnchor>;
181
191
  hasOpenCiRedEscalation: (params: {
182
192
  productId: string;
183
193
  sha: string;
184
194
  branch: string;
185
195
  }) => Promise<boolean>;
186
- fileCiRedEscalation: (params: {
187
- organizationId: string;
188
- productId: string;
189
- focusId: string;
190
- sha: string;
191
- branch: string;
192
- }) => Promise<void>;
196
+ fileCiRedEscalation: (params: CiRedFilingParams) => Promise<void>;
193
197
  resolveCiRedEscalations: (productId: string) => Promise<number>;
194
198
  }
195
199
  export interface CiSensorTickCounts {
@@ -1 +1 @@
1
- {"version":3,"file":"ci-sensor-loop.d.ts","sourceRoot":"","sources":["../../src/ci/ci-sensor-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ci-sensor-loop.d.ts","sourceRoot":"","sources":["../../src/ci/ci-sensor-loop.ts"],"names":[],"mappings":"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"}