@telora/daemon 0.23.14 → 0.23.16

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 (250) hide show
  1. package/build-info.json +5 -3
  2. package/dist/backends/agent-backend.d.ts +8 -1
  3. package/dist/backends/agent-backend.d.ts.map +1 -1
  4. package/dist/backends/claude/claude-backend.d.ts.map +1 -1
  5. package/dist/backends/claude/claude-backend.js +4 -0
  6. package/dist/backends/claude/claude-backend.js.map +1 -1
  7. package/dist/backends/claude/one-shot-model.d.ts +11 -0
  8. package/dist/backends/claude/one-shot-model.d.ts.map +1 -1
  9. package/dist/backends/claude/one-shot-model.js +7 -4
  10. package/dist/backends/claude/one-shot-model.js.map +1 -1
  11. package/dist/backends/claude/one-shot-session.d.ts +15 -0
  12. package/dist/backends/claude/one-shot-session.d.ts.map +1 -0
  13. package/dist/backends/claude/one-shot-session.js +120 -0
  14. package/dist/backends/claude/one-shot-session.js.map +1 -0
  15. package/dist/backends/codex/codex-backend.d.ts.map +1 -1
  16. package/dist/backends/codex/codex-backend.js +10 -0
  17. package/dist/backends/codex/codex-backend.js.map +1 -1
  18. package/dist/ci/candidate-ref.d.ts +28 -0
  19. package/dist/ci/candidate-ref.d.ts.map +1 -0
  20. package/dist/ci/candidate-ref.js +81 -0
  21. package/dist/ci/candidate-ref.js.map +1 -0
  22. package/dist/ci/ci-sensor-loop.d.ts.map +1 -1
  23. package/dist/ci/ci-sensor-loop.js +2 -1
  24. package/dist/ci/ci-sensor-loop.js.map +1 -1
  25. package/dist/ci/ci-status-git.d.ts +9 -0
  26. package/dist/ci/ci-status-git.d.ts.map +1 -1
  27. package/dist/ci/ci-status-git.js +16 -2
  28. package/dist/ci/ci-status-git.js.map +1 -1
  29. package/dist/ci/ci-status.d.ts.map +1 -1
  30. package/dist/ci/ci-status.js +5 -1
  31. package/dist/ci/ci-status.js.map +1 -1
  32. package/dist/completion/state-cascade/state-cascade.d.ts +14 -1
  33. package/dist/completion/state-cascade/state-cascade.d.ts.map +1 -1
  34. package/dist/completion/state-cascade/state-cascade.js +26 -1
  35. package/dist/completion/state-cascade/state-cascade.js.map +1 -1
  36. package/dist/completion/team-exit/merge-phase.d.ts +11 -10
  37. package/dist/completion/team-exit/merge-phase.d.ts.map +1 -1
  38. package/dist/completion/team-exit/merge-phase.js +10 -10
  39. package/dist/completion/team-exit/merge-phase.js.map +1 -1
  40. package/dist/completion/team-teardown/team-lifecycle.d.ts +4 -3
  41. package/dist/completion/team-teardown/team-lifecycle.d.ts.map +1 -1
  42. package/dist/completion/team-teardown/team-lifecycle.js +8 -8
  43. package/dist/completion/team-teardown/team-lifecycle.js.map +1 -1
  44. package/dist/composition/execution-git-context.d.ts.map +1 -1
  45. package/dist/composition/execution-git-context.js +2 -0
  46. package/dist/composition/execution-git-context.js.map +1 -1
  47. package/dist/composition/execution-merge-context.d.ts +11 -3
  48. package/dist/composition/execution-merge-context.d.ts.map +1 -1
  49. package/dist/composition/execution-merge-context.js +60 -12
  50. package/dist/composition/execution-merge-context.js.map +1 -1
  51. package/dist/composition/process-close-context.js +3 -3
  52. package/dist/composition/process-close-context.js.map +1 -1
  53. package/dist/composition/state-cascade-context.d.ts.map +1 -1
  54. package/dist/composition/state-cascade-context.js +10 -2
  55. package/dist/composition/state-cascade-context.js.map +1 -1
  56. package/dist/composition/team-lifecycle-context.js +3 -3
  57. package/dist/composition/team-lifecycle-context.js.map +1 -1
  58. package/dist/composition/verification-context.d.ts.map +1 -1
  59. package/dist/composition/verification-context.js +4 -23
  60. package/dist/composition/verification-context.js.map +1 -1
  61. package/dist/config/model-resolution.d.ts +25 -1
  62. package/dist/config/model-resolution.d.ts.map +1 -1
  63. package/dist/config/model-resolution.js +26 -1
  64. package/dist/config/model-resolution.js.map +1 -1
  65. package/dist/delivery/delivery-merge-ops.d.ts +2 -0
  66. package/dist/delivery/delivery-merge-ops.d.ts.map +1 -1
  67. package/dist/delivery/delivery-merge-ops.js +2 -2
  68. package/dist/delivery/delivery-merge-ops.js.map +1 -1
  69. package/dist/delivery/delivery-reconciler.d.ts +9 -0
  70. package/dist/delivery/delivery-reconciler.d.ts.map +1 -1
  71. package/dist/delivery/delivery-reconciler.js +42 -31
  72. package/dist/delivery/delivery-reconciler.js.map +1 -1
  73. package/dist/focus/focus-executor.d.ts.map +1 -1
  74. package/dist/focus/focus-executor.js +1 -0
  75. package/dist/focus/focus-executor.js.map +1 -1
  76. package/dist/focus/focus-poller-spawn.d.ts.map +1 -1
  77. package/dist/focus/focus-poller-spawn.js +3 -1
  78. package/dist/focus/focus-poller-spawn.js.map +1 -1
  79. package/dist/focus/focus-spawn-decision.d.ts.map +1 -1
  80. package/dist/focus/focus-spawn-decision.js +1 -0
  81. package/dist/focus/focus-spawn-decision.js.map +1 -1
  82. package/dist/git/index.d.ts.map +1 -1
  83. package/dist/git/index.js +2 -1
  84. package/dist/git/index.js.map +1 -1
  85. package/dist/git/merge.d.ts +12 -2
  86. package/dist/git/merge.d.ts.map +1 -1
  87. package/dist/git/merge.js +32 -33
  88. package/dist/git/merge.js.map +1 -1
  89. package/dist/merge/approval-gate-state.d.ts.map +1 -1
  90. package/dist/merge/approval-gate-state.js +8 -7
  91. package/dist/merge/approval-gate-state.js.map +1 -1
  92. package/dist/merge/candidate-rework.d.ts +44 -0
  93. package/dist/merge/candidate-rework.d.ts.map +1 -0
  94. package/dist/merge/candidate-rework.js +152 -0
  95. package/dist/merge/candidate-rework.js.map +1 -0
  96. package/dist/merge/completion-hold-record.d.ts +20 -0
  97. package/dist/merge/completion-hold-record.d.ts.map +1 -0
  98. package/dist/merge/completion-hold-record.js +130 -0
  99. package/dist/merge/completion-hold-record.js.map +1 -0
  100. package/dist/merge/completion-merge-driver.d.ts +96 -0
  101. package/dist/merge/completion-merge-driver.d.ts.map +1 -0
  102. package/dist/merge/completion-merge-driver.js +94 -0
  103. package/dist/merge/completion-merge-driver.js.map +1 -0
  104. package/dist/merge/completion-merge-gate.d.ts +71 -0
  105. package/dist/merge/completion-merge-gate.d.ts.map +1 -0
  106. package/dist/merge/completion-merge-gate.js +185 -0
  107. package/dist/merge/completion-merge-gate.js.map +1 -0
  108. package/dist/merge/completion-merge-pending.d.ts +30 -0
  109. package/dist/merge/completion-merge-pending.d.ts.map +1 -0
  110. package/dist/merge/completion-merge-pending.js +75 -0
  111. package/dist/merge/completion-merge-pending.js.map +1 -0
  112. package/dist/merge/focus-merge.d.ts +21 -6
  113. package/dist/merge/focus-merge.d.ts.map +1 -1
  114. package/dist/merge/focus-merge.js +65 -45
  115. package/dist/merge/focus-merge.js.map +1 -1
  116. package/dist/merge/focus-worktree-removal.d.ts +6 -6
  117. package/dist/merge/focus-worktree-removal.d.ts.map +1 -1
  118. package/dist/merge/focus-worktree-removal.js +10 -6
  119. package/dist/merge/focus-worktree-removal.js.map +1 -1
  120. package/dist/merge/merge-back-conflict.d.ts.map +1 -1
  121. package/dist/merge/merge-back-conflict.js +2 -0
  122. package/dist/merge/merge-back-conflict.js.map +1 -1
  123. package/dist/merge/merge-back-followup.d.ts.map +1 -1
  124. package/dist/merge/merge-back-followup.js +7 -0
  125. package/dist/merge/merge-back-followup.js.map +1 -1
  126. package/dist/merge/merge-back-loop.d.ts +36 -14
  127. package/dist/merge/merge-back-loop.d.ts.map +1 -1
  128. package/dist/merge/merge-back-loop.js +109 -66
  129. package/dist/merge/merge-back-loop.js.map +1 -1
  130. package/dist/merge/merge-gate-coverage.d.ts +9 -61
  131. package/dist/merge/merge-gate-coverage.d.ts.map +1 -1
  132. package/dist/merge/merge-gate-coverage.js +33 -167
  133. package/dist/merge/merge-gate-coverage.js.map +1 -1
  134. package/dist/nexus/escalation-bridge.d.ts.map +1 -1
  135. package/dist/nexus/escalation-bridge.js +2 -1
  136. package/dist/nexus/escalation-bridge.js.map +1 -1
  137. package/dist/nexus/file-escalation.d.ts.map +1 -1
  138. package/dist/nexus/file-escalation.js +5 -1
  139. package/dist/nexus/file-escalation.js.map +1 -1
  140. package/dist/queries/api-client/shared.js +1 -1
  141. package/dist/queries/deliveries/deliveries.d.ts.map +1 -1
  142. package/dist/queries/deliveries/deliveries.js +1 -0
  143. package/dist/queries/deliveries/deliveries.js.map +1 -1
  144. package/dist/queries/delivery-gate-state/delivery-gate-state.js +1 -1
  145. package/dist/queries/delivery-gate-state/verify-own-holds.d.ts +10 -3
  146. package/dist/queries/delivery-gate-state/verify-own-holds.d.ts.map +1 -1
  147. package/dist/queries/delivery-gate-state/verify-own-holds.js +2 -0
  148. package/dist/queries/delivery-gate-state/verify-own-holds.js.map +1 -1
  149. package/dist/queries/escalations/cause-key.d.ts.map +1 -1
  150. package/dist/queries/escalations/cause-key.js +1 -0
  151. package/dist/queries/escalations/cause-key.js.map +1 -1
  152. package/dist/queries/escalations/escalations.d.ts.map +1 -1
  153. package/dist/queries/escalations/escalations.js +2 -1
  154. package/dist/queries/escalations/escalations.js.map +1 -1
  155. package/dist/queries/focuses/focus-discovery.d.ts +14 -0
  156. package/dist/queries/focuses/focus-discovery.d.ts.map +1 -1
  157. package/dist/queries/focuses/focus-discovery.js +4 -0
  158. package/dist/queries/focuses/focus-discovery.js.map +1 -1
  159. package/dist/queries/focuses/focuses.d.ts +12 -2
  160. package/dist/queries/focuses/focuses.d.ts.map +1 -1
  161. package/dist/queries/focuses/focuses.js +24 -3
  162. package/dist/queries/focuses/focuses.js.map +1 -1
  163. package/dist/queries/org-config/local-models.d.ts.map +1 -1
  164. package/dist/queries/org-config/local-models.js +2 -1
  165. package/dist/queries/org-config/local-models.js.map +1 -1
  166. package/dist/queries/wire-schemas/schemas.d.ts +48 -0
  167. package/dist/queries/wire-schemas/schemas.d.ts.map +1 -1
  168. package/dist/queries/wire-schemas/schemas.js +15 -0
  169. package/dist/queries/wire-schemas/schemas.js.map +1 -1
  170. package/dist/spawn/model-routing.d.ts +13 -8
  171. package/dist/spawn/model-routing.d.ts.map +1 -1
  172. package/dist/spawn/model-routing.js +14 -8
  173. package/dist/spawn/model-routing.js.map +1 -1
  174. package/dist/spawn/review-hold-park.d.ts.map +1 -1
  175. package/dist/spawn/review-hold-park.js +1 -0
  176. package/dist/spawn/review-hold-park.js.map +1 -1
  177. package/dist/spawn/spawn-decision.d.ts +7 -0
  178. package/dist/spawn/spawn-decision.d.ts.map +1 -1
  179. package/dist/spawn/spawn-decision.js.map +1 -1
  180. package/dist/supervision/agent-resolvable-retirement.d.ts +1 -1
  181. package/dist/supervision/agent-resolvable-retirement.d.ts.map +1 -1
  182. package/dist/supervision/agent-resolvable-retirement.js +2 -1
  183. package/dist/supervision/agent-resolvable-retirement.js.map +1 -1
  184. package/dist/supervision/escalation-filing.js +1 -1
  185. package/dist/supervision/incident-correlation.d.ts +3 -0
  186. package/dist/supervision/incident-correlation.d.ts.map +1 -1
  187. package/dist/supervision/incident-correlation.js +4 -0
  188. package/dist/supervision/incident-correlation.js.map +1 -1
  189. package/dist/supervision/null-role-spawn.d.ts.map +1 -1
  190. package/dist/supervision/null-role-spawn.js +1 -0
  191. package/dist/supervision/null-role-spawn.js.map +1 -1
  192. package/dist/supervision/spawn-cooldown.js +1 -1
  193. package/dist/supervision/stop-rows-work-holds.d.ts +4 -4
  194. package/dist/supervision/stop-rows-work-holds.d.ts.map +1 -1
  195. package/dist/supervision/stop-rows-work-holds.js +17 -15
  196. package/dist/supervision/stop-rows-work-holds.js.map +1 -1
  197. package/dist/testing/fixtures/api-client.js +1 -1
  198. package/dist/testing/fixtures/index.d.ts.map +1 -1
  199. package/dist/testing/fixtures/index.js +3 -1
  200. package/dist/testing/fixtures/index.js.map +1 -1
  201. package/dist/testing/fixtures/judge-session.d.ts +14 -0
  202. package/dist/testing/fixtures/judge-session.d.ts.map +1 -0
  203. package/dist/testing/fixtures/judge-session.js +10 -0
  204. package/dist/testing/fixtures/judge-session.js.map +1 -0
  205. package/dist/types/focus.d.ts +9 -0
  206. package/dist/types/focus.d.ts.map +1 -1
  207. package/dist/types/index.js +1 -1
  208. package/dist/verify/effect-reconciliation/judge-invoker.d.ts +14 -4
  209. package/dist/verify/effect-reconciliation/judge-invoker.d.ts.map +1 -1
  210. package/dist/verify/effect-reconciliation/judge-invoker.js +30 -12
  211. package/dist/verify/effect-reconciliation/judge-invoker.js.map +1 -1
  212. package/dist/verify/effect-reconciliation/verify-reconciliation.d.ts +18 -5
  213. package/dist/verify/effect-reconciliation/verify-reconciliation.d.ts.map +1 -1
  214. package/dist/verify/effect-reconciliation/verify-reconciliation.js +75 -18
  215. package/dist/verify/effect-reconciliation/verify-reconciliation.js.map +1 -1
  216. package/dist/verify/effect-reconciliation/verify-restatement.js +1 -1
  217. package/dist/verify/engine/verification-deps.js +1 -1
  218. package/dist/verify/engine/verification-engine.js +1 -1
  219. package/dist/verify/gate-config/verification-config.js +1 -1
  220. package/dist/verify/inspection-strategies/verification-strategies.js +1 -1
  221. package/dist/verify/inspection-strategies/verification-strategies.js.map +1 -1
  222. package/dist/verify/outcome-routing/incurable-model-hold.d.ts +9 -3
  223. package/dist/verify/outcome-routing/incurable-model-hold.d.ts.map +1 -1
  224. package/dist/verify/outcome-routing/incurable-model-hold.js +18 -5
  225. package/dist/verify/outcome-routing/incurable-model-hold.js.map +1 -1
  226. package/dist/verify/outcome-routing/repeating-model-hold.d.ts +30 -0
  227. package/dist/verify/outcome-routing/repeating-model-hold.d.ts.map +1 -0
  228. package/dist/verify/outcome-routing/repeating-model-hold.js +135 -0
  229. package/dist/verify/outcome-routing/repeating-model-hold.js.map +1 -0
  230. package/dist/verify/outcome-routing/verification-history-reset.d.ts.map +1 -1
  231. package/dist/verify/outcome-routing/verification-history-reset.js +1 -0
  232. package/dist/verify/outcome-routing/verification-history-reset.js.map +1 -1
  233. package/dist/verify/outcome-routing/verification-model-unavailable-hold.d.ts +10 -4
  234. package/dist/verify/outcome-routing/verification-model-unavailable-hold.d.ts.map +1 -1
  235. package/dist/verify/outcome-routing/verification-model-unavailable-hold.js +24 -6
  236. package/dist/verify/outcome-routing/verification-model-unavailable-hold.js.map +1 -1
  237. package/dist/verify/run-selection/default-on-guards.js +1 -1
  238. package/dist/verify/run-selection/pre-review-gate-dispatch.d.ts +4 -3
  239. package/dist/verify/run-selection/pre-review-gate-dispatch.d.ts.map +1 -1
  240. package/dist/verify/run-selection/pre-review-gate-dispatch.js +23 -7
  241. package/dist/verify/run-selection/pre-review-gate-dispatch.js.map +1 -1
  242. package/dist/verify/run-selection/verification-default-on.js +1 -1
  243. package/dist/verify/run-selection/verification-default-on.js.map +1 -1
  244. package/dist/worktree/provision.d.ts.map +1 -1
  245. package/dist/worktree/provision.js +1 -0
  246. package/dist/worktree/provision.js.map +1 -1
  247. package/dist/worktree/safety.d.ts.map +1 -1
  248. package/dist/worktree/safety.js +1 -0
  249. package/dist/worktree/safety.js.map +1 -1
  250. package/package.json +3 -3
@@ -0,0 +1,152 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/merge/candidate-rework.test.ts,
3
+ // packages/daemon/src/merge/completion-conflict-rework.test.ts,
4
+ // packages/daemon/src/merge/completion-rework-armed.test.ts
5
+ // PINNED-BY-END
6
+ /**
7
+ * A completion merge that cannot proceed returns its focus to coding as re-work:
8
+ * a red (or verdict-less) integration candidate, a final merge of the
9
+ * integration tip that conflicts (aborted, never resolved by the daemon), or a
10
+ * conflict-deciding merge after the approved head. ONE Bug on the delivery that
11
+ * owns the work, and that done delivery re-opened through the single-writer
12
+ * reconciler (done -> verify_failed, the `integrationCandidateRed` fact). No
13
+ * escalation is filed: the failure is the focus's own work, read by its next
14
+ * coding pass. A conflict's Bug names the paths and the integration commits the
15
+ * branch lacks, the same work order the coding spawn's reconcile section gives
16
+ * (prompt-sections/integration-reconcile-section.ts).
17
+ *
18
+ * OWNER: the delivery named by the `Telora-Delivery` trailer of the newest
19
+ * non-merge commit on the branch that is one of the focus's done deliveries;
20
+ * else the most recently updated done delivery. One OPEN Bug per candidate commit
21
+ * and cause: its title carries the sha, an open one is not filed again, and when
22
+ * every earlier one is closed (the team closed it, yet the same commit is still
23
+ * failing) a numbered new attempt is filed, so the delivery always re-opens.
24
+ * The outcome says what was APPLIED; only a re-open or already-open work counts
25
+ * as returning the focus to coding.
26
+ *
27
+ * @module merge/candidate-rework
28
+ */
29
+ import { DELIVERY_STATUS } from '@telora/daemon-core';
30
+ import { resolveReconciledWrite } from '../delivery/delivery-reconciler-apply.js';
31
+ import { candidateBranchForFocus } from '../ci/candidate-ref.js';
32
+ import { createLogger } from '../log/daemon-log.js';
33
+ const log = createLogger({ module: 'completion-merge' });
34
+ /** The Bug's title; carries the commit so one failure files one Bug. Pure. */
35
+ export function candidateReworkTitle(sha, cause) {
36
+ const short = sha.slice(0, 9);
37
+ if (cause === 'conflict')
38
+ return `Final merge of integration into ${short} conflicts`;
39
+ if (cause === 'unreviewed_merge')
40
+ return `Merge at ${short} decided a conflict no review judged`;
41
+ return `Integration candidate ${short} failed CI`;
42
+ }
43
+ function listed(items, empty) {
44
+ return items.length > 0 ? items.slice(0, 30).map((i) => `- ${i}`) : [`- ${empty}`];
45
+ }
46
+ function conflictDescription(subject, sha, conflict) {
47
+ const integration = conflict?.integrationBranch ?? 'integration';
48
+ return [
49
+ `Merging the ${integration} tip into the focus head ${sha} CONFLICTS. The daemon aborted the merge: deciding a ` +
50
+ 'conflict changes code after the review approved HEAD, and CI only judges reviewed trees.',
51
+ '',
52
+ 'Conflicting paths:',
53
+ ...listed(conflict?.conflictPaths ?? [], 'could not be read -- run the merge to see them'),
54
+ '',
55
+ `Commits on ${integration} the branch lacks:`,
56
+ ...listed(conflict?.missingCommits ?? [], 'could not be read'),
57
+ '',
58
+ `MERGE origin/${integration} into ${subject.branchName} (never rebase: the shas carry the Telora-Delivery ` +
59
+ 'trailers and the per-commit verify verdicts), resolve each path, and commit. The resolved head then passes ' +
60
+ 'the gate and review before the completion merge is tried again.',
61
+ ];
62
+ }
63
+ /** The Bug's description. Pure. */
64
+ export function candidateReworkDescription(subject, sha, cause, conflict) {
65
+ if (cause === 'conflict')
66
+ return conflictDescription(subject, sha, conflict).join('\n');
67
+ if (cause === 'unreviewed_merge') {
68
+ return [
69
+ `The focus head ${sha} carries a merge after the approved head that decided a conflict (git's re-merge of it is ` +
70
+ 'not empty), so its code was never reviewed and CI must not judge it as a candidate.',
71
+ '',
72
+ 'Check the merge resolution on the branch, fix it if it is wrong, and commit; the head then passes the gate and ' +
73
+ 'review before the completion merge is tried again.',
74
+ ].join('\n');
75
+ }
76
+ const what = cause === 'red'
77
+ ? `CI's full suite FAILED on the focus's integration candidate ${sha} (the focus branch merged with the integration tip).`
78
+ : `CI published no verdict for the focus's integration candidate ${sha} within the wait window.`;
79
+ return [
80
+ what,
81
+ '',
82
+ `Integration does not move until a candidate is green. Read the failing run with \`ci-logs\` (its ref is ` +
83
+ `refs/heads/${candidateBranchForFocus(subject.focusId)}), fix it on ${subject.branchName}, and commit; ` +
84
+ 'the next review and candidate run judge the fix.',
85
+ ].join('\n');
86
+ }
87
+ /** Which done delivery owns the re-work. Pure. */
88
+ export function chooseReworkOwner(deliveries, trailers) {
89
+ const done = deliveries.filter((d) => d.executionStatus === DELIVERY_STATUS.DONE);
90
+ for (const t of trailers) {
91
+ const owner = done.find((d) => d.id === t);
92
+ if (owner)
93
+ return owner;
94
+ }
95
+ return [...done].sort((a, b) => (b.updatedAt ?? '').localeCompare(a.updatedAt ?? ''))[0] ?? null;
96
+ }
97
+ const CLOSED_ISSUE_STATUSES = new Set(['Done', 'Verified']);
98
+ /** The Bug to file for this candidate, or null when one is still open. Pure. */
99
+ export function nextReworkTitle(issues, base) {
100
+ const family = issues.filter((i) => i.title === base || i.title.startsWith(`${base} (attempt `));
101
+ if (family.some((i) => !CLOSED_ISSUE_STATUSES.has(i.status)))
102
+ return null;
103
+ return family.length === 0 ? base : `${base} (attempt ${family.length + 1})`;
104
+ }
105
+ /** Re-open the done owner when the reconciler, given its issues, moves it off done. */
106
+ async function reopenOwner(owner, issues, deps) {
107
+ const decision = resolveReconciledWrite({
108
+ input: {
109
+ currentStatus: DELIVERY_STATUS.DONE,
110
+ issues: issues.map((i) => ({ status: i.status, issueType: i.issueType, ...(i.deferrable ? { deferrable: true } : {}) })),
111
+ gitState: { worktreeCommitted: true },
112
+ guardVerdict: null,
113
+ reviewState: null,
114
+ integrationCandidateRed: true,
115
+ },
116
+ });
117
+ if (decision.target === DELIVERY_STATUS.DONE)
118
+ return false;
119
+ const stageId = await deps.resolveStageId(owner.id, decision.target);
120
+ await deps.updateDeliveryStatus(owner.id, decision.target, stageId, undefined, undefined, {
121
+ organizationId: deps.organizationId,
122
+ fromStatus: DELIVERY_STATUS.DONE,
123
+ });
124
+ return true;
125
+ }
126
+ /**
127
+ * File the candidate's Bug on its owner and re-open that delivery; say what was
128
+ * applied. Throws on a failed read or write (the driver retries).
129
+ */
130
+ export async function routeCandidateRework(subject, sha, cause, conflict, deps) {
131
+ const deliveries = await deps.getFocusDeliveries(subject.focusId);
132
+ if (deliveries.some((d) => d.executionStatus !== DELIVERY_STATUS.DONE && d.executionStatus !== DELIVERY_STATUS.CANCELLED))
133
+ return 'already_open';
134
+ const owner = chooseReworkOwner(deliveries, deps.listBranchDeliveryTrailers(subject.repoPath, subject.branchName));
135
+ if (owner === null) {
136
+ log.warn(`[completion-merge] "${subject.focusName}": no done delivery to carry the re-work for candidate ${sha.slice(0, 9)}`);
137
+ return 'not_reopened';
138
+ }
139
+ let issues = await deps.getDeliveryIssues(owner.id);
140
+ const title = nextReworkTitle(issues, candidateReworkTitle(sha, cause));
141
+ if (title !== null) {
142
+ await deps.createIssue(owner.id, title, candidateReworkDescription(subject, sha, cause, conflict), 'Bug', 'P0');
143
+ issues = await deps.getDeliveryIssues(owner.id);
144
+ }
145
+ if (!(await reopenOwner(owner, issues, deps))) {
146
+ log.warn(`[completion-merge] "${subject.focusName}": "${owner.name}" stays done -- the reconciler re-opened nothing for ${sha.slice(0, 9)}`);
147
+ return 'not_reopened';
148
+ }
149
+ log.info(`[completion-merge] "${subject.focusName}": re-opened "${owner.name}" with the candidate's Bug`);
150
+ return 'reopened';
151
+ }
152
+ //# sourceMappingURL=candidate-rework.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidate-rework.js","sourceRoot":"","sources":["../../src/merge/candidate-rework.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /** The record file for a focus; `dir` defaults to the global state dir. Exported for tests. */
2
+ export declare function completionHoldPath(productId: string, focusId: string, dir?: string): string;
3
+ /**
4
+ * The instant the focus's completion merge was first held, stamping `now` when
5
+ * no record exists yet. Null when the record is unreadable or cannot be written.
6
+ */
7
+ export declare function stampCompletionHold(productId: string, focusId: string, now: number, dir?: string): number | null;
8
+ /** The candidate-wait file for a focus. Exported for tests. */
9
+ export declare function candidateWaitPath(productId: string, focusId: string, dir?: string): string;
10
+ /**
11
+ * When the focus's candidate `sha` was first stamped, stamping `now` when the
12
+ * record is absent, names another sha, or is CORRUPT (repaired: a malformed
13
+ * record would otherwise stop the no-verdict window from ever expiring). Null
14
+ * only when the record cannot be written; the driver then counts from its own
15
+ * first sighting.
16
+ */
17
+ export declare function stampCandidateWait(productId: string, focusId: string, sha: string, now: number, dir?: string): number | null;
18
+ /** Forget the focus's first hold and candidate wait (it merged, or it is no longer complete). Best-effort. */
19
+ export declare function clearCompletionHold(productId: string, focusId: string, dir?: string): void;
20
+ //# sourceMappingURL=completion-hold-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-hold-record.d.ts","sourceRoot":"","sources":["../../src/merge/completion-hold-record.ts"],"names":[],"mappings":"AA4CA,+FAA+F;AAC/F,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,MAAM,CAEtG;AAgBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,MAAM,GAAG,IAAI,CAW3H;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,MAAM,CAErG;AAmBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,MAAM,GAAG,IAAI,CAavI;AAED,8GAA8G;AAC9G,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,IAAI,CAOrG"}
@@ -0,0 +1,130 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/merge/completion-hold-record.test.ts,
3
+ // packages/daemon/src/merge/completion-merge-driver.test.ts
4
+ // PINNED-BY-END
5
+ /**
6
+ * When a COMPLETED focus's integration merge was first held, recorded durably.
7
+ *
8
+ * Under completion-only merging (merge/completion-merge-gate.ts) a focus branch
9
+ * ahead of integration while its focus codes is normal; what can be stuck is a
10
+ * complete focus whose merge keeps being held. The stuck-branch surface
11
+ * (merge/merge-back-loop.ts) counts from THIS instant: the first merge-back tick
12
+ * that saw the focus complete and its merge held stamps it, every later tick
13
+ * reads it back, a successful merge or the focus re-opening (it is no longer
14
+ * complete) clears it. One file per (product, focus) under the global state dir,
15
+ * written atomically (temp + rename), so a daemon restart neither resets nor
16
+ * re-arms the clock -- and no delivery row write moves it (a row's updated_at
17
+ * would).
18
+ *
19
+ * The same directory holds the CANDIDATE WAIT: when the focus's integration
20
+ * candidate (a sha) was first pushed or seen waiting on CI, so the completion
21
+ * merge driver's no-verdict window (merge/completion-merge-driver.ts) survives a
22
+ * restart. A new candidate sha restarts it; clearing the hold clears it too.
23
+ *
24
+ * Host-local like the auto-approval record (merge/review-auto-approval-record.ts):
25
+ * the daemon that claims the product writes and reads it. A hold record that
26
+ * cannot be read or written yields null -- nothing is filed that tick, and it is
27
+ * logged. A corrupt candidate-wait record is repaired (rewritten), so the
28
+ * no-verdict window can always expire; an unwritable one yields null.
29
+ *
30
+ * @module merge/completion-hold-record
31
+ */
32
+ import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
33
+ import { resolve } from 'node:path';
34
+ import { resolveGlobalStateDir } from '../daemon-state/daemon-process.js';
35
+ import { createLogger } from '../log/daemon-log.js';
36
+ const log = createLogger({ module: 'completion-merge' });
37
+ function holdDir() {
38
+ return resolve(resolveGlobalStateDir(), 'completion-holds');
39
+ }
40
+ /** The record file for a focus; `dir` defaults to the global state dir. Exported for tests. */
41
+ export function completionHoldPath(productId, focusId, dir = holdDir()) {
42
+ return resolve(dir, `${productId}-${focusId}.json`.replace(/[^a-zA-Z0-9._-]/g, '_'));
43
+ }
44
+ function readFirstHeldAt(path) {
45
+ let raw;
46
+ try {
47
+ raw = readFileSync(path, 'utf8');
48
+ }
49
+ catch (err) {
50
+ if (err.code === 'ENOENT')
51
+ return 'absent';
52
+ throw err;
53
+ }
54
+ const parsed = JSON.parse(raw);
55
+ if (typeof parsed !== 'object' || parsed === null)
56
+ return null;
57
+ const at = parsed.firstHeldAt;
58
+ return typeof at === 'number' && Number.isFinite(at) ? at : null;
59
+ }
60
+ /**
61
+ * The instant the focus's completion merge was first held, stamping `now` when
62
+ * no record exists yet. Null when the record is unreadable or cannot be written.
63
+ */
64
+ export function stampCompletionHold(productId, focusId, now, dir = holdDir()) {
65
+ const path = completionHoldPath(productId, focusId, dir);
66
+ try {
67
+ const existing = readFirstHeldAt(path);
68
+ if (existing !== 'absent')
69
+ return existing;
70
+ writeAtomic(dir, path, { productId, focusId, firstHeldAt: now });
71
+ return now;
72
+ }
73
+ catch (err) {
74
+ log.warn(`[completion-merge] completion-hold record for focus ${focusId} unusable: ${err.message}`);
75
+ return null;
76
+ }
77
+ }
78
+ /** The candidate-wait file for a focus. Exported for tests. */
79
+ export function candidateWaitPath(productId, focusId, dir = holdDir()) {
80
+ return completionHoldPath(productId, `${focusId}-candidate`, dir);
81
+ }
82
+ function writeAtomic(dir, path, body) {
83
+ mkdirSync(dir, { recursive: true });
84
+ const tmp = `${path}.${process.pid}.tmp`;
85
+ writeFileSync(tmp, JSON.stringify(body));
86
+ renameSync(tmp, path);
87
+ }
88
+ /** The candidate a readable wait record names, or null when absent, unreadable or malformed. */
89
+ function readCandidateWait(path) {
90
+ try {
91
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
92
+ return typeof parsed === 'object' && parsed !== null ? parsed : null;
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ /**
99
+ * When the focus's candidate `sha` was first stamped, stamping `now` when the
100
+ * record is absent, names another sha, or is CORRUPT (repaired: a malformed
101
+ * record would otherwise stop the no-verdict window from ever expiring). Null
102
+ * only when the record cannot be written; the driver then counts from its own
103
+ * first sighting.
104
+ */
105
+ export function stampCandidateWait(productId, focusId, sha, now, dir = holdDir()) {
106
+ const path = candidateWaitPath(productId, focusId, dir);
107
+ const existing = readCandidateWait(path);
108
+ if (existing !== null && existing.sha === sha && typeof existing.since === 'number' && Number.isFinite(existing.since)) {
109
+ return existing.since;
110
+ }
111
+ try {
112
+ writeAtomic(dir, path, { productId, focusId, sha, since: now });
113
+ return now;
114
+ }
115
+ catch (err) {
116
+ log.warn(`[completion-merge] candidate-wait record for focus ${focusId} cannot be written: ${err.message}`);
117
+ return null;
118
+ }
119
+ }
120
+ /** Forget the focus's first hold and candidate wait (it merged, or it is no longer complete). Best-effort. */
121
+ export function clearCompletionHold(productId, focusId, dir = holdDir()) {
122
+ try {
123
+ rmSync(completionHoldPath(productId, focusId, dir), { force: true });
124
+ rmSync(candidateWaitPath(productId, focusId, dir), { force: true });
125
+ }
126
+ catch (err) {
127
+ log.warn(`[completion-merge] completion-hold record for focus ${focusId} could not be cleared: ${err.message}`);
128
+ }
129
+ }
130
+ //# sourceMappingURL=completion-hold-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-hold-record.js","sourceRoot":"","sources":["../../src/merge/completion-hold-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The one driver of a held completion merge: the merge-back loop hands it the
3
+ * gate's hold (merge/completion-merge-gate.ts) and it takes the step that
4
+ * advances the focus toward integration.
5
+ *
6
+ * merge_out -> merge the integration tip into the focus branch ONCE, with
7
+ * git's automatic merge (merge/focus-merge.ts
8
+ * attemptCompletionMergeOut). A clean merge stays and is the
9
+ * next candidate. A merge that conflicts is aborted and is
10
+ * re-work: deciding a conflict changes code after the review
11
+ * approved HEAD, and CI must only judge reviewed trees, so the
12
+ * team resolves it and its head passes the gate and review.
13
+ * review_merge -> a merge after the approved head already decided a conflict:
14
+ * re-work, so review judges that head.
15
+ * push_candidate -> push the head to the focus's candidate branch so CI runs the
16
+ * full suite on exactly that commit (ci/candidate-ref.ts).
17
+ * wait_ci -> nothing, until CANDIDATE_CI_VERDICT_WAIT_MS has passed with
18
+ * no verdict; then the missing verdict is re-work like a red.
19
+ * The wait is counted from a DURABLE stamp of the candidate
20
+ * (merge/completion-hold-record.ts), so a daemon restart
21
+ * neither restarts nor forgets the window.
22
+ * rework -> return the focus to coding: one Bug on the owning delivery,
23
+ * re-opened to verify_failed (merge/candidate-rework.ts). No
24
+ * escalation is filed.
25
+ *
26
+ * Integration never moves here; a green candidate is admitted by the gate and
27
+ * fast-forwarded by the caller's normal merge.
28
+ *
29
+ * @module merge/completion-merge-driver
30
+ */
31
+ import type { CompletionMergeStep } from './completion-merge-gate.js';
32
+ /** How long a pushed candidate may sit with no published verdict before it is re-work. */
33
+ export declare const CANDIDATE_CI_VERDICT_WAIT_MS: number;
34
+ /** The focus branch a step acts on. */
35
+ export interface CompletionMergeSubject {
36
+ focusId: string;
37
+ focusName: string;
38
+ repoPath: string;
39
+ branchName: string;
40
+ }
41
+ /** Why a candidate is returned to the focus as re-work. */
42
+ export type CandidateReworkCause = 'red' | 'no_verdict' | 'conflict' | 'unreviewed_merge';
43
+ /** What a conflicting final merge left for the team: the paths, and the integration commits the branch lacks. */
44
+ export interface CompletionMergeConflict {
45
+ integrationBranch: string;
46
+ conflictPaths: string[];
47
+ /** `<sha9> <subject>`, newest first; [] when unreadable. */
48
+ missingCommits: string[];
49
+ }
50
+ /**
51
+ * What routing the re-work APPLIED: the done owner re-opened by a status write,
52
+ * work already open on the focus (nothing to re-open), or nothing re-opened (no
53
+ * owner, or the reconciler kept it done). Only the first two return the focus to coding.
54
+ */
55
+ export type CandidateReworkOutcome = 'reopened' | 'already_open' | 'not_reopened';
56
+ /** One completion merge-out: merged clean (or already current), conflicted (aborted), or could not run. */
57
+ export type CompletionMergeOutOutcome = {
58
+ kind: 'merged';
59
+ } | {
60
+ kind: 'conflict';
61
+ conflict: CompletionMergeConflict;
62
+ } | {
63
+ kind: 'error';
64
+ message: string;
65
+ };
66
+ /** The driver's effects; bound at the composition root (composition/execution-merge-context.ts). */
67
+ export interface CompletionMergeDriverDeps {
68
+ /** One automatic merge of the integration tip into the focus branch; a conflict is aborted, never resolved. */
69
+ mergeOut: () => Promise<CompletionMergeOutOutcome>;
70
+ /** Push `sha` to the focus's candidate branch; false when the push failed. */
71
+ pushCandidate: (repoPath: string, focusId: string, sha: string) => boolean;
72
+ /**
73
+ * When the focus's candidate `sha` was first pushed or seen waiting, stamping
74
+ * `now` when no stamp names `sha`. Durable across restarts (a corrupt record is
75
+ * repaired); null when the record cannot be written -- the driver then counts
76
+ * the wait from its own in-memory first sighting, so a missing verdict still
77
+ * becomes re-work.
78
+ */
79
+ candidateWaitSince: (sha: string, now: number) => number | null;
80
+ /** Return the focus to coding as re-work for the candidate at `sha`. */
81
+ routeRework: (subject: CompletionMergeSubject, sha: string, cause: CandidateReworkCause, conflict: CompletionMergeConflict | null) => Promise<CandidateReworkOutcome>;
82
+ now: () => number;
83
+ }
84
+ /** Reset the driver's memory -- tests start from a clean slate. */
85
+ export declare function __resetCompletionMergeDriverForTests(): void;
86
+ /** What a step did: whether it returned the focus to coding (the caller then files no stuck observation). */
87
+ export interface CompletionMergeStepResult {
88
+ reworked: boolean;
89
+ }
90
+ /**
91
+ * Take the step a held completion merge names, and say whether it returned the
92
+ * focus to coding. Never throws: a failed step is retried next tick (and did not
93
+ * return the focus).
94
+ */
95
+ export declare function driveCompletionMergeStep(subject: CompletionMergeSubject, step: CompletionMergeStep, headSha: string, deps: CompletionMergeDriverDeps): Promise<CompletionMergeStepResult>;
96
+ //# sourceMappingURL=completion-merge-driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-merge-driver.d.ts","sourceRoot":"","sources":["../../src/merge/completion-merge-driver.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAKtE,0FAA0F;AAC1F,eAAO,MAAM,4BAA4B,QAAqB,CAAC;AAE/D,uCAAuC;AACvC,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,2DAA2D;AAC3D,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,YAAY,GAAG,UAAU,GAAG,kBAAkB,CAAC;AAE1F,iHAAiH;AACjH,MAAM,WAAW,uBAAuB;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,4DAA4D;IAC5D,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,cAAc,GAAG,cAAc,CAAC;AAElF,2GAA2G;AAC3G,MAAM,MAAM,yBAAyB,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,oGAAoG;AACpG,MAAM,WAAW,yBAAyB;IACxC,+GAA+G;IAC/G,QAAQ,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACnD,8EAA8E;IAC9E,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3E;;;;;;OAMG;IACH,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAChE,wEAAwE;IACxE,WAAW,EAAE,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,uBAAuB,GAAG,IAAI,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACtK,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAUD,mEAAmE;AACnE,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAED,6GAA6G;AAC7G,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAuDD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,sBAAsB,EAC/B,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,yBAAyB,CAAC,CAgBpC"}
@@ -0,0 +1,94 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/completion/team-exit/teardown-merge-gate.test.ts,
3
+ // packages/daemon/src/merge/candidate-rework.test.ts,
4
+ // packages/daemon/src/merge/completion-conflict-rework.test.ts,
5
+ // packages/daemon/src/merge/completion-merge-driver.test.ts,
6
+ // packages/daemon/src/merge/completion-rework-armed.test.ts,
7
+ // packages/daemon/src/merge/merge-back-loop.test.ts
8
+ // PINNED-BY-END
9
+ import { createLogger } from '../log/daemon-log.js';
10
+ const log = createLogger({ module: 'completion-merge' });
11
+ /** How long a pushed candidate may sit with no published verdict before it is re-work. */
12
+ export const CANDIDATE_CI_VERDICT_WAIT_MS = 3 * 60 * 60 * 1000;
13
+ /**
14
+ * The wait's fallback clock: when this process first saw each candidate waiting,
15
+ * read only when the durable record cannot be written. Re-work routing keeps no
16
+ * memory of its own: routeRework is idempotent (an open Bug is not refiled, a
17
+ * re-opened focus is incomplete, so the gate stops naming the step).
18
+ */
19
+ const fallbackWaitSince = new Map();
20
+ /** Reset the driver's memory -- tests start from a clean slate. */
21
+ export function __resetCompletionMergeDriverForTests() {
22
+ fallbackWaitSince.clear();
23
+ }
24
+ function key(subject, sha) {
25
+ return `${subject.focusId}:${sha}`;
26
+ }
27
+ const CAUSE_TEXT = {
28
+ red: 'is RED in CI',
29
+ no_verdict: 'got no CI verdict',
30
+ conflict: 'conflicts with the integration tip',
31
+ unreviewed_merge: 'carries a conflict-deciding merge no review judged',
32
+ };
33
+ async function rework(subject, sha, cause, conflict, deps) {
34
+ const outcome = await deps.routeRework(subject, sha, cause, conflict);
35
+ if (outcome === 'not_reopened') {
36
+ log.warn(`[completion-merge] "${subject.focusName}": ${sha.slice(0, 9)} ${CAUSE_TEXT[cause]} but no work was re-opened -- retried next tick`);
37
+ return { reworked: false };
38
+ }
39
+ log.info(`[completion-merge] "${subject.focusName}": ${sha.slice(0, 9)} ${CAUSE_TEXT[cause]} -- returned to the focus as re-work (${outcome})`);
40
+ return { reworked: true };
41
+ }
42
+ const NOTHING = { reworked: false };
43
+ async function mergeOut(subject, headSha, deps) {
44
+ const outcome = await deps.mergeOut();
45
+ if (outcome.kind === 'conflict')
46
+ return rework(subject, headSha, 'conflict', outcome.conflict, deps);
47
+ if (outcome.kind === 'error')
48
+ log.warn(`[completion-merge] "${subject.focusName}": merge-out could not run: ${outcome.message}`);
49
+ return NOTHING;
50
+ }
51
+ /** The in-memory first sighting of a candidate waiting, for when the durable record is unusable. */
52
+ function fallbackSince(subject, sha, now) {
53
+ const k = key(subject, sha);
54
+ const since = fallbackWaitSince.get(k) ?? now;
55
+ fallbackWaitSince.set(k, since);
56
+ log.warn(`[completion-merge] "${subject.focusName}": the candidate-wait record is unusable; counting ${sha.slice(0, 9)}'s wait from this process's first sighting`);
57
+ return since;
58
+ }
59
+ /** wait_ci: re-work once the durable wait for `headSha` has run past the window. */
60
+ async function waitForVerdict(subject, headSha, deps) {
61
+ const now = deps.now();
62
+ const since = deps.candidateWaitSince(headSha, now) ?? fallbackSince(subject, headSha, now);
63
+ if (now - since < CANDIDATE_CI_VERDICT_WAIT_MS)
64
+ return NOTHING;
65
+ return rework(subject, headSha, 'no_verdict', null, deps);
66
+ }
67
+ /**
68
+ * Take the step a held completion merge names, and say whether it returned the
69
+ * focus to coding. Never throws: a failed step is retried next tick (and did not
70
+ * return the focus).
71
+ */
72
+ export async function driveCompletionMergeStep(subject, step, headSha, deps) {
73
+ try {
74
+ if (step === 'merge_out')
75
+ return await mergeOut(subject, headSha, deps);
76
+ if (step === 'review_merge')
77
+ return await rework(subject, headSha, 'unreviewed_merge', null, deps);
78
+ if (step === 'rework')
79
+ return await rework(subject, headSha, 'red', null, deps);
80
+ if (step === 'push_candidate') {
81
+ const pushed = deps.pushCandidate(subject.repoPath, subject.focusId, headSha);
82
+ if (pushed && deps.candidateWaitSince(headSha, deps.now()) === null)
83
+ fallbackSince(subject, headSha, deps.now());
84
+ log.info(`[completion-merge] "${subject.focusName}": ${pushed ? 'pushed' : 'could not push'} integration candidate ${headSha.slice(0, 9)} for CI`);
85
+ return NOTHING;
86
+ }
87
+ return await waitForVerdict(subject, headSha, deps);
88
+ }
89
+ catch (err) {
90
+ log.warn(`[completion-merge] "${subject.focusName}": ${step} for ${headSha.slice(0, 9)} failed: ${err.message}`);
91
+ return NOTHING;
92
+ }
93
+ }
94
+ //# sourceMappingURL=completion-merge-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-merge-driver.js","sourceRoot":"","sources":["../../src/merge/completion-merge-driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { CiRunStatus } from '../ci/ci-status.js';
2
+ import type { ApprovalGateState } from './approval-gate-state.js';
3
+ import { type BranchMergeGateTarget, type GatedAnchor, type MergeGateTarget, type UnmergedCommit } from './merge-gate-coverage.js';
4
+ /** The step that advances a held completion merge; driven by the merge-back loop only. */
5
+ export type CompletionMergeStep = 'merge_out' | 'review_merge' | 'push_candidate' | 'wait_ci' | 'rework';
6
+ /** A merge the gate holds (with why, and the step that advances it), or one it admits at an exact commit. */
7
+ export type MergeGateDecision = {
8
+ hold: string;
9
+ next?: CompletionMergeStep;
10
+ headSha?: string;
11
+ /** The gate's OWN delivery read found the focus incomplete: there is no completion hold to age. */
12
+ incomplete?: true;
13
+ } | {
14
+ hold: null;
15
+ admittedBy: string;
16
+ candidateSha: string;
17
+ };
18
+ /** One focus delivery, as the completion predicate reads it. */
19
+ export interface CompletionDeliveryFact {
20
+ name: string;
21
+ executionStatus: string | null;
22
+ }
23
+ /**
24
+ * Injected reads. The production binding (git, the product-api, the verdict
25
+ * record and the CI status refs) is built at the composition root
26
+ * (composition/execution-merge-context.ts).
27
+ */
28
+ export interface CompletionMergeGateDeps {
29
+ /** The focus's deliveries; throws when unreadable. */
30
+ getFocusDeliveries: (focusId: string) => Promise<CompletionDeliveryFact[]>;
31
+ /** integration..branch, newest first; null when git cannot list it. */
32
+ listUnmergedCommits: (repoPath: string, integrationBranch: string, branchName: string) => UnmergedCommit[] | null;
33
+ /** The anchor's full sha and its unmerged ancestry; null when git cannot resolve the sha. */
34
+ resolveAnchor: (repoPath: string, integrationBranch: string, sha: string) => Omit<GatedAnchor, 'source'> | null;
35
+ /** The commit the focus's newest current approval judged, null when none; throws when unreadable. */
36
+ readApprovedReviewSha: (target: MergeGateTarget) => Promise<string | null>;
37
+ /** The gate state at the commit an approval judged; throws when unreadable. */
38
+ judgeApprovalGate: (target: MergeGateTarget, sha: string) => Promise<ApprovalGateState>;
39
+ /** The branch's head sha; null when unreadable. */
40
+ resolveBranchHead: (repoPath: string, branchName: string) => string | null;
41
+ /** The integration tip the branch must contain (the remote tip when there is one); null when unreadable. */
42
+ resolveIntegrationTip: (target: MergeGateTarget) => string | null;
43
+ /** Whether `ancestor` is an ancestor-or-equal of `descendant`; false when git cannot tell. */
44
+ isAncestor: (repoPath: string, ancestor: string, descendant: string) => boolean;
45
+ /** The candidate commit's CI status (fail-closed: missing / unreadable -> 'unknown'). */
46
+ readCandidateStatus: (target: MergeGateTarget, sha: string) => CiRunStatus;
47
+ /** The sha the focus's candidate branch points at on the remote; null when none / unreadable. */
48
+ readPushedCandidateSha: (target: MergeGateTarget) => string | null;
49
+ }
50
+ /** Step 1: every delivery done (cancelled is not done), at least one delivery. Pure. */
51
+ export declare function focusCompletionHold(deliveries: readonly CompletionDeliveryFact[]): string | null;
52
+ /** The merges after the approved commit that git cannot prove clean (they decided a conflict, or edited). Pure. */
53
+ export declare function unreviewedMergesAfter(commits: readonly UnmergedCommit[], approval: GatedAnchor): UnmergedCommit[];
54
+ /**
55
+ * Step 2 over listed commits: everything after the approved commit must be a
56
+ * merge (an integration sync; one that is not clean is unreviewedMergesAfter's),
57
+ * and what the approval contains must be gated by it under the capture rule. Pure.
58
+ */
59
+ export declare function approvedHeadHold(commits: readonly UnmergedCommit[], approval: GatedAnchor): string | null;
60
+ /**
61
+ * Whether a merge of `target` holds (why, and the step that advances it) or is
62
+ * admitted (at which commit). Never throws: a failed read holds. Whether it holds
63
+ * is the merge_gate_coverage stop-registry row's decision.
64
+ */
65
+ export declare function readMergeGateDecision(target: MergeGateTarget, deps: CompletionMergeGateDeps): Promise<MergeGateDecision>;
66
+ /**
67
+ * The decision for a branch whose focus may be unknown. With no focus there is
68
+ * no completion to read, so the merge holds.
69
+ */
70
+ export declare function readMergeGateDecisionForBranch(target: BranchMergeGateTarget, deps: CompletionMergeGateDeps): Promise<MergeGateDecision>;
71
+ //# sourceMappingURL=completion-merge-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-merge-gate.d.ts","sourceRoot":"","sources":["../../src/merge/completion-merge-gate.ts"],"names":[],"mappings":"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"}