@telora/daemon 0.23.16 → 0.23.17

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 (69) hide show
  1. package/build-info.json +2 -2
  2. package/dist/ci/candidate-ref.d.ts +13 -0
  3. package/dist/ci/candidate-ref.d.ts.map +1 -1
  4. package/dist/ci/candidate-ref.js +18 -0
  5. package/dist/ci/candidate-ref.js.map +1 -1
  6. package/dist/composition/execution-merge-context.d.ts +7 -1
  7. package/dist/composition/execution-merge-context.d.ts.map +1 -1
  8. package/dist/composition/execution-merge-context.js +42 -6
  9. package/dist/composition/execution-merge-context.js.map +1 -1
  10. package/dist/composition/execution-recovery-context.d.ts.map +1 -1
  11. package/dist/composition/execution-recovery-context.js +2 -0
  12. package/dist/composition/execution-recovery-context.js.map +1 -1
  13. package/dist/focus/crash-recovery.d.ts +7 -0
  14. package/dist/focus/crash-recovery.d.ts.map +1 -1
  15. package/dist/focus/crash-recovery.js +26 -13
  16. package/dist/focus/crash-recovery.js.map +1 -1
  17. package/dist/merge/candidate-rework.d.ts +3 -3
  18. package/dist/merge/candidate-rework.d.ts.map +1 -1
  19. package/dist/merge/candidate-rework.js +30 -10
  20. package/dist/merge/candidate-rework.js.map +1 -1
  21. package/dist/merge/completion-hold-record.d.ts +16 -0
  22. package/dist/merge/completion-hold-record.d.ts.map +1 -1
  23. package/dist/merge/completion-hold-record.js +60 -1
  24. package/dist/merge/completion-hold-record.js.map +1 -1
  25. package/dist/merge/completion-judge.d.ts +44 -0
  26. package/dist/merge/completion-judge.d.ts.map +1 -0
  27. package/dist/merge/completion-judge.js +36 -0
  28. package/dist/merge/completion-judge.js.map +1 -0
  29. package/dist/merge/completion-local-judge.d.ts +90 -0
  30. package/dist/merge/completion-local-judge.d.ts.map +1 -0
  31. package/dist/merge/completion-local-judge.js +193 -0
  32. package/dist/merge/completion-local-judge.js.map +1 -0
  33. package/dist/merge/completion-merge-driver.d.ts +31 -7
  34. package/dist/merge/completion-merge-driver.d.ts.map +1 -1
  35. package/dist/merge/completion-merge-driver.js +36 -8
  36. package/dist/merge/completion-merge-driver.js.map +1 -1
  37. package/dist/merge/completion-merge-gate.d.ts +10 -2
  38. package/dist/merge/completion-merge-gate.d.ts.map +1 -1
  39. package/dist/merge/completion-merge-gate.js +65 -19
  40. package/dist/merge/completion-merge-gate.js.map +1 -1
  41. package/dist/merge/merge-back-loop.d.ts +9 -1
  42. package/dist/merge/merge-back-loop.d.ts.map +1 -1
  43. package/dist/merge/merge-back-loop.js +28 -1
  44. package/dist/merge/merge-back-loop.js.map +1 -1
  45. package/dist/queries/api-client/shared.js +1 -1
  46. package/dist/testing/fixtures/api-client.js +1 -1
  47. package/dist/testing/fixtures/completion-judge-stubs.d.ts +15 -0
  48. package/dist/testing/fixtures/completion-judge-stubs.d.ts.map +1 -0
  49. package/dist/testing/fixtures/completion-judge-stubs.js +32 -0
  50. package/dist/testing/fixtures/completion-judge-stubs.js.map +1 -0
  51. package/dist/testing/fixtures/index.js +1 -1
  52. package/dist/verify/deterministic-gate/verification-checkout.d.ts.map +1 -1
  53. package/dist/verify/deterministic-gate/verification-checkout.js +1 -0
  54. package/dist/verify/deterministic-gate/verification-checkout.js.map +1 -1
  55. package/dist/verify/deterministic-gate/verification-deterministic.d.ts.map +1 -1
  56. package/dist/verify/deterministic-gate/verification-deterministic.js +1 -0
  57. package/dist/verify/deterministic-gate/verification-deterministic.js.map +1 -1
  58. package/dist/verify/gate-config/verification-manifest.d.ts +21 -1
  59. package/dist/verify/gate-config/verification-manifest.d.ts.map +1 -1
  60. package/dist/verify/gate-config/verification-manifest.js +25 -1
  61. package/dist/verify/gate-config/verification-manifest.js.map +1 -1
  62. package/dist/verify/run-selection/verification-default-on.d.ts +2 -0
  63. package/dist/verify/run-selection/verification-default-on.d.ts.map +1 -1
  64. package/dist/verify/run-selection/verification-default-on.js +1 -1
  65. package/dist/verify/run-selection/verification-default-on.js.map +1 -1
  66. package/dist/worktree/focus-worktree-state.d.ts.map +1 -1
  67. package/dist/worktree/focus-worktree-state.js +1 -0
  68. package/dist/worktree/focus-worktree-state.js.map +1 -1
  69. package/package.json +2 -2
@@ -5,7 +5,7 @@
5
5
  // PINNED-BY-END
6
6
  /**
7
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
8
+ * a red integration candidate (CI's, or the daemon's local completion run's), a final merge of the
9
9
  * integration tip that conflicts (aborted, never resolved by the daemon), or a
10
10
  * conflict-deciding merge after the approved head. ONE Bug on the delivery that
11
11
  * owns the work, and that done delivery re-opened through the single-writer
@@ -28,6 +28,7 @@
28
28
  */
29
29
  import { DELIVERY_STATUS } from '@telora/daemon-core';
30
30
  import { resolveReconciledWrite } from '../delivery/delivery-reconciler-apply.js';
31
+ import { deliveryHoldsCompletion } from './completion-merge-gate.js';
31
32
  import { candidateBranchForFocus } from '../ci/candidate-ref.js';
32
33
  import { createLogger } from '../log/daemon-log.js';
33
34
  const log = createLogger({ module: 'completion-merge' });
@@ -38,6 +39,8 @@ export function candidateReworkTitle(sha, cause) {
38
39
  return `Final merge of integration into ${short} conflicts`;
39
40
  if (cause === 'unreviewed_merge')
40
41
  return `Merge at ${short} decided a conflict no review judged`;
42
+ if (cause === 'local_red')
43
+ return `Integration candidate ${short} failed the completion suite`;
41
44
  return `Integration candidate ${short} failed CI`;
42
45
  }
43
46
  function listed(items, empty) {
@@ -60,10 +63,29 @@ function conflictDescription(subject, sha, conflict) {
60
63
  'the gate and review before the completion merge is tried again.',
61
64
  ];
62
65
  }
66
+ function isConflict(detail) {
67
+ return detail !== null && 'conflictPaths' in detail;
68
+ }
69
+ function isLocalFailure(detail) {
70
+ return detail !== null && 'command' in detail;
71
+ }
72
+ function localFailureDescription(subject, sha, failure) {
73
+ return [
74
+ `The daemon ran the product's completion suite${failure ? ` (\`${failure.command}\`)` : ''} on the focus's integration ` +
75
+ `candidate ${sha} (the focus branch merged with the integration tip), and it FAILED` +
76
+ `${failure?.rationale ? `: ${failure.rationale}` : '.'}`,
77
+ '',
78
+ ...(failure?.logPath ? [`Full log on the daemon host: ${failure.logPath}`, ''] : []),
79
+ `Integration does not move until a candidate passes. Reproduce it on ${subject.branchName} (the candidate is its ` +
80
+ 'HEAD), fix it, and commit; the next review and completion run judge the fix.',
81
+ ];
82
+ }
63
83
  /** The Bug's description. Pure. */
64
- export function candidateReworkDescription(subject, sha, cause, conflict) {
84
+ export function candidateReworkDescription(subject, sha, cause, detail) {
65
85
  if (cause === 'conflict')
66
- return conflictDescription(subject, sha, conflict).join('\n');
86
+ return conflictDescription(subject, sha, isConflict(detail) ? detail : null).join('\n');
87
+ if (cause === 'local_red')
88
+ return localFailureDescription(subject, sha, isLocalFailure(detail) ? detail : null).join('\n');
67
89
  if (cause === 'unreviewed_merge') {
68
90
  return [
69
91
  `The focus head ${sha} carries a merge after the approved head that decided a conflict (git's re-merge of it is ` +
@@ -73,11 +95,8 @@ export function candidateReworkDescription(subject, sha, cause, conflict) {
73
95
  'review before the completion merge is tried again.',
74
96
  ].join('\n');
75
97
  }
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
98
  return [
80
- what,
99
+ `CI's full suite FAILED on the focus's integration candidate ${sha} (the focus branch merged with the integration tip).`,
81
100
  '',
82
101
  `Integration does not move until a candidate is green. Read the failing run with \`ci-logs\` (its ref is ` +
83
102
  `refs/heads/${candidateBranchForFocus(subject.focusId)}), fix it on ${subject.branchName}, and commit; ` +
@@ -127,9 +146,10 @@ async function reopenOwner(owner, issues, deps) {
127
146
  * File the candidate's Bug on its owner and re-open that delivery; say what was
128
147
  * applied. Throws on a failed read or write (the driver retries).
129
148
  */
130
- export async function routeCandidateRework(subject, sha, cause, conflict, deps) {
149
+ export async function routeCandidateRework(subject, sha, cause, detail, deps) {
131
150
  const deliveries = await deps.getFocusDeliveries(subject.focusId);
132
- if (deliveries.some((d) => d.executionStatus !== DELIVERY_STATUS.DONE && d.executionStatus !== DELIVERY_STATUS.CANCELLED))
151
+ // The gate's own predicate (completion-merge-gate.ts): a delivery that owes no work (planning, cancelled) is not open work.
152
+ if (deliveries.some((d) => deliveryHoldsCompletion(d.executionStatus)))
133
153
  return 'already_open';
134
154
  const owner = chooseReworkOwner(deliveries, deps.listBranchDeliveryTrailers(subject.repoPath, subject.branchName));
135
155
  if (owner === null) {
@@ -139,7 +159,7 @@ export async function routeCandidateRework(subject, sha, cause, conflict, deps)
139
159
  let issues = await deps.getDeliveryIssues(owner.id);
140
160
  const title = nextReworkTitle(issues, candidateReworkTitle(sha, cause));
141
161
  if (title !== null) {
142
- await deps.createIssue(owner.id, title, candidateReworkDescription(subject, sha, cause, conflict), 'Bug', 'P0');
162
+ await deps.createIssue(owner.id, title, candidateReworkDescription(subject, sha, cause, detail), 'Bug', 'P0');
143
163
  issues = await deps.getDeliveryIssues(owner.id);
144
164
  }
145
165
  if (!(await reopenOwner(owner, issues, deps))) {
@@ -1 +1 @@
1
- {"version":3,"file":"candidate-rework.js","sourceRoot":"","sources":["../../src/merge/candidate-rework.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"candidate-rework.js","sourceRoot":"","sources":["../../src/merge/candidate-rework.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,iEAAiE;AACjE,kEAAkE;AAClE,8DAA8D;AAC9D,gBAAgB;AAEhB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,eAAe,EAAwB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAUlF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAsCzD,8EAA8E;AAC9E,MAAM,UAAU,oBAAoB,CAAC,GAAW,EAAE,KAA2B;IAC3E,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9B,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,mCAAmC,KAAK,YAAY,CAAC;IACtF,IAAI,KAAK,KAAK,kBAAkB;QAAE,OAAO,YAAY,KAAK,sCAAsC,CAAC;IACjG,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,yBAAyB,KAAK,8BAA8B,CAAC;IAC/F,OAAO,yBAAyB,KAAK,YAAY,CAAC;AACpD,CAAC;AAED,SAAS,MAAM,CAAC,KAAwB,EAAE,KAAa;IACrD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,mBAAmB,CAAC,OAA+B,EAAE,GAAW,EAAE,QAAwC;IACjH,MAAM,WAAW,GAAG,QAAQ,EAAE,iBAAiB,IAAI,aAAa,CAAC;IACjE,OAAO;QACL,eAAe,WAAW,4BAA4B,GAAG,uDAAuD;YAC9G,0FAA0F;QAC5F,EAAE;QACF,oBAAoB;QACpB,GAAG,MAAM,CAAC,QAAQ,EAAE,aAAa,IAAI,EAAE,EAAE,gDAAgD,CAAC;QAC1F,EAAE;QACF,cAAc,WAAW,oBAAoB;QAC7C,GAAG,MAAM,CAAC,QAAQ,EAAE,cAAc,IAAI,EAAE,EAAE,mBAAmB,CAAC;QAC9D,EAAE;QACF,gBAAgB,WAAW,SAAS,OAAO,CAAC,UAAU,qDAAqD;YACzG,6GAA6G;YAC7G,iEAAiE;KACpE,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,MAAoC;IACtD,OAAO,MAAM,KAAK,IAAI,IAAI,eAAe,IAAI,MAAM,CAAC;AACtD,CAAC;AAED,SAAS,cAAc,CAAC,MAAoC;IAC1D,OAAO,MAAM,KAAK,IAAI,IAAI,SAAS,IAAI,MAAM,CAAC;AAChD,CAAC;AAED,SAAS,uBAAuB,CAAC,OAA+B,EAAE,GAAW,EAAE,OAAiC;IAC9G,OAAO;QACL,gDAAgD,OAAO,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,8BAA8B;YACtH,aAAa,GAAG,oEAAoE;YACpF,GAAG,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QAC1D,EAAE;QACF,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,gCAAgC,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,uEAAuE,OAAO,CAAC,UAAU,yBAAyB;YAChH,8EAA8E;KACjF,CAAC;AACJ,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,0BAA0B,CACxC,OAA+B,EAC/B,GAAW,EACX,KAA2B,EAC3B,MAAoC;IAEpC,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,mBAAmB,CAAC,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClH,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,uBAAuB,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3H,IAAI,KAAK,KAAK,kBAAkB,EAAE,CAAC;QACjC,OAAO;YACL,kBAAkB,GAAG,4FAA4F;gBAC/G,qFAAqF;YACvF,EAAE;YACF,iHAAiH;gBAC/G,oDAAoD;SACvD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IACD,OAAO;QACL,+DAA+D,GAAG,sDAAsD;QACxH,EAAE;QACF,0GAA0G;YACxG,cAAc,uBAAuB,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,OAAO,CAAC,UAAU,gBAAgB;YACxG,kDAAkD;KACrD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,iBAAiB,CAAC,UAA8C,EAAE,QAA2B;IAC3G,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,eAAe,CAAC,IAAI,CAAC,CAAC;IAClF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3C,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACnG,CAAC;AAED,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAEjF,gFAAgF;AAChF,MAAM,UAAU,eAAe,CAAC,MAAuC,EAAE,IAAY;IACnF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;IACjG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1E,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,aAAa,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC;AAC/E,CAAC;AAED,uFAAuF;AACvF,KAAK,UAAU,WAAW,CAAC,KAA8B,EAAE,MAAuC,EAAE,IAAyB;IAC3H,MAAM,QAAQ,GAAG,sBAAsB,CAAC;QACtC,KAAK,EAAE;YACL,aAAa,EAAE,eAAe,CAAC,IAAuB;YACtD,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACxH,QAAQ,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE;YACrC,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,IAAI;YACjB,uBAAuB,EAAE,IAAI;SAC9B;KACF,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,MAAM,KAAK,eAAe,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrE,MAAM,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE;QACxF,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,UAAU,EAAE,eAAe,CAAC,IAAI;KACjC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAA+B,EAC/B,GAAW,EACX,KAA2B,EAC3B,MAAoC,EACpC,IAAyB;IAEzB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,4HAA4H;IAC5H,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;QAAE,OAAO,cAAc,CAAC;IAC9F,MAAM,KAAK,GAAG,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACnH,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,GAAG,CAAC,IAAI,CAAC,uBAAuB,OAAO,CAAC,SAAS,0DAA0D,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9H,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IACxE,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,0BAA0B,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC9G,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC,uBAAuB,OAAO,CAAC,SAAS,OAAO,KAAK,CAAC,IAAI,wDAAwD,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7I,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,uBAAuB,OAAO,CAAC,SAAS,iBAAiB,KAAK,CAAC,IAAI,4BAA4B,CAAC,CAAC;IAC1G,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -15,6 +15,22 @@ export declare function candidateWaitPath(productId: string, focusId: string, di
15
15
  * first sighting.
16
16
  */
17
17
  export declare function stampCandidateWait(productId: string, focusId: string, sha: string, now: number, dir?: string): number | null;
18
+ /** Whether the focus's candidate `sha` was already re-pushed for a missing CI verdict (merge/completion-merge-driver.ts). */
19
+ export declare function readCandidateRepushed(productId: string, focusId: string, sha: string, dir?: string): boolean;
20
+ /**
21
+ * Record that `sha` was re-pushed at `now`: its wait window restarts from `now`
22
+ * and it is never re-pushed again. Best-effort (an unwritable record is logged;
23
+ * the driver's in-memory clock still bounds the wait).
24
+ */
25
+ export declare function markCandidateRepushed(productId: string, focusId: string, sha: string, now: number, dir?: string): void;
26
+ /** Whether a completion hold is recorded for the focus: its completed merge is still pending on this host. */
27
+ export declare function hasCompletionHold(productId: string, focusId: string, dir?: string): boolean;
28
+ /**
29
+ * The focus ids with a recorded completion hold for a product, read from the
30
+ * record directory. A crash-recovery pass reads this to keep the worktree of a
31
+ * focus whose completed merge is still pending (focus/crash-recovery.ts).
32
+ */
33
+ export declare function listCompletionHoldFocusIds(productId: string, dir?: string): string[];
18
34
  /** Forget the focus's first hold and candidate wait (it merged, or it is no longer complete). Best-effort. */
19
35
  export declare function clearCompletionHold(productId: string, focusId: string, dir?: string): void;
20
36
  //# sourceMappingURL=completion-hold-record.d.ts.map
@@ -1 +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"}
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,6HAA6H;AAC7H,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAGvH;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,IAAI,CAMjI;AAED,8GAA8G;AAC9G,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAOtG;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,MAAM,EAAE,CAoB/F;AAED,8GAA8G;AAC9G,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,IAAI,CAOrG"}
@@ -29,7 +29,7 @@
29
29
  *
30
30
  * @module merge/completion-hold-record
31
31
  */
32
- import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
32
+ import { mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
33
33
  import { resolve } from 'node:path';
34
34
  import { resolveGlobalStateDir } from '../daemon-state/daemon-process.js';
35
35
  import { createLogger } from '../log/daemon-log.js';
@@ -117,6 +117,65 @@ export function stampCandidateWait(productId, focusId, sha, now, dir = holdDir()
117
117
  return null;
118
118
  }
119
119
  }
120
+ /** Whether the focus's candidate `sha` was already re-pushed for a missing CI verdict (merge/completion-merge-driver.ts). */
121
+ export function readCandidateRepushed(productId, focusId, sha, dir = holdDir()) {
122
+ const existing = readCandidateWait(candidateWaitPath(productId, focusId, dir));
123
+ return existing !== null && existing.sha === sha && existing.repushed === true;
124
+ }
125
+ /**
126
+ * Record that `sha` was re-pushed at `now`: its wait window restarts from `now`
127
+ * and it is never re-pushed again. Best-effort (an unwritable record is logged;
128
+ * the driver's in-memory clock still bounds the wait).
129
+ */
130
+ export function markCandidateRepushed(productId, focusId, sha, now, dir = holdDir()) {
131
+ try {
132
+ writeAtomic(dir, candidateWaitPath(productId, focusId, dir), { productId, focusId, sha, since: now, repushed: true });
133
+ }
134
+ catch (err) {
135
+ log.warn(`[completion-merge] candidate-wait record for focus ${focusId} cannot record the re-push: ${err.message}`);
136
+ }
137
+ }
138
+ /** Whether a completion hold is recorded for the focus: its completed merge is still pending on this host. */
139
+ export function hasCompletionHold(productId, focusId, dir = holdDir()) {
140
+ try {
141
+ return readFirstHeldAt(completionHoldPath(productId, focusId, dir)) !== 'absent';
142
+ }
143
+ catch {
144
+ // An unreadable record still says a hold was written: treat it as pending (it only ever KEEPS a branch in view).
145
+ return true;
146
+ }
147
+ }
148
+ /**
149
+ * The focus ids with a recorded completion hold for a product, read from the
150
+ * record directory. A crash-recovery pass reads this to keep the worktree of a
151
+ * focus whose completed merge is still pending (focus/crash-recovery.ts).
152
+ */
153
+ export function listCompletionHoldFocusIds(productId, dir = holdDir()) {
154
+ let names;
155
+ try {
156
+ names = readdirSync(dir);
157
+ }
158
+ catch {
159
+ return [];
160
+ }
161
+ const out = [];
162
+ for (const name of names) {
163
+ if (!name.endsWith('.json') || name.endsWith('-candidate.json'))
164
+ continue;
165
+ try {
166
+ const parsed = JSON.parse(readFileSync(resolve(dir, name), 'utf8'));
167
+ if (typeof parsed !== 'object' || parsed === null)
168
+ continue;
169
+ const rec = parsed;
170
+ if (rec.productId === productId && typeof rec.focusId === 'string')
171
+ out.push(rec.focusId);
172
+ }
173
+ catch {
174
+ continue;
175
+ }
176
+ }
177
+ return out;
178
+ }
120
179
  /** Forget the focus's first hold and candidate wait (it merged, or it is no longer complete). Best-effort. */
121
180
  export function clearCompletionHold(productId, focusId, dir = holdDir()) {
122
181
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"completion-hold-record.js","sourceRoot":"","sources":["../../src/merge/completion-hold-record.ts"],"names":[],"mappings":"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"}
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,44 @@
1
+ /**
2
+ * What judges a completed focus's integration candidate -- the focus head merged
3
+ * with the integration tip -- before integration fast-forwards to it. The
4
+ * PRODUCT declares it (telora.verify.json `completionJudge`), read from the
5
+ * candidate commit itself, so the declaration travels with the code it judges:
6
+ *
7
+ * - `ci` -- the product's remote CI publishes refs/ci-status for the
8
+ * candidate branch (ci/candidate-ref.ts). Only a product that
9
+ * says so is waited on: a CI that publishes nothing would hold
10
+ * every finished focus forever.
11
+ * - `local` -- the daemon runs the product's completion command on exactly
12
+ * the candidate commit (merge/completion-local-judge.ts). The
13
+ * default for any repo that ships a manifest.
14
+ * - `none` -- the repo ships no manifest: no suite is declared, so the merge
15
+ * rests on the focus's review approval alone, and says so.
16
+ * - `unreadable` -- git could not read the manifest at the candidate, or the
17
+ * manifest is malformed: the merge holds (fail closed), naming why.
18
+ *
19
+ * Why: docs/DECISIONS.md, "The completion candidate is judged where the
20
+ * product declares".
21
+ *
22
+ * @module merge/completion-judge
23
+ */
24
+ import type { JudgedCommitRead } from '../verify/run-selection/verification-default-on.js';
25
+ /** Default bound on a local completion run: a full suite, not a targeted gate. */
26
+ export declare const DEFAULT_COMPLETION_TIMEOUT_MS: number;
27
+ /** The judge a candidate commit declares. */
28
+ export type CompletionJudge = {
29
+ kind: 'ci';
30
+ } | {
31
+ kind: 'local';
32
+ command: string;
33
+ timeoutMs: number;
34
+ } | {
35
+ kind: 'none';
36
+ } | {
37
+ kind: 'unreadable';
38
+ reason: string;
39
+ };
40
+ /** The judge the manifest read at the candidate commit declares. Pure. */
41
+ export declare function completionJudgeFrom(read: JudgedCommitRead): CompletionJudge;
42
+ /** One line naming a judge, for the merge log and holds. Pure. */
43
+ export declare function describeCompletionJudge(judge: CompletionJudge): string;
44
+ //# sourceMappingURL=completion-judge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-judge.d.ts","sourceRoot":"","sources":["../../src/merge/completion-judge.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAC;AAE3F,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAE5D,6CAA6C;AAC7C,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,eAAe,CAW3E;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAWtE"}
@@ -0,0 +1,36 @@
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-judge.test.ts
3
+ // PINNED-BY-END
4
+ /** Default bound on a local completion run: a full suite, not a targeted gate. */
5
+ export const DEFAULT_COMPLETION_TIMEOUT_MS = 60 * 60 * 1000;
6
+ /** The judge the manifest read at the candidate commit declares. Pure. */
7
+ export function completionJudgeFrom(read) {
8
+ if ('unreadable' in read)
9
+ return { kind: 'unreadable', reason: read.unreadable };
10
+ if (read.malformed !== undefined)
11
+ return { kind: 'unreadable', reason: read.malformed };
12
+ const manifest = read.manifest;
13
+ if (manifest === undefined)
14
+ return { kind: 'none' };
15
+ if (manifest.completionJudge === 'ci')
16
+ return { kind: 'ci' };
17
+ return {
18
+ kind: 'local',
19
+ command: manifest.completionCommand ?? manifest.command,
20
+ timeoutMs: manifest.completionTimeoutMs ?? manifest.timeoutMs ?? DEFAULT_COMPLETION_TIMEOUT_MS,
21
+ };
22
+ }
23
+ /** One line naming a judge, for the merge log and holds. Pure. */
24
+ export function describeCompletionJudge(judge) {
25
+ switch (judge.kind) {
26
+ case 'ci':
27
+ return 'CI (refs/ci-status)';
28
+ case 'local':
29
+ return `the daemon running \`${judge.command}\``;
30
+ case 'none':
31
+ return 'no completion suite (the repo ships no telora.verify.json)';
32
+ case 'unreadable':
33
+ return `an unreadable declaration (${judge.reason})`;
34
+ }
35
+ }
36
+ //# sourceMappingURL=completion-judge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-judge.js","sourceRoot":"","sources":["../../src/merge/completion-judge.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,gEAAgE;AAChE,gBAAgB;AA4BhB,kFAAkF;AAClF,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAS5D,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CAAC,IAAsB;IACxD,IAAI,YAAY,IAAI,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IACjF,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC/B,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACpD,IAAI,QAAQ,CAAC,eAAe,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC7D,OAAO;QACL,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,QAAQ,CAAC,iBAAiB,IAAI,QAAQ,CAAC,OAAO;QACvD,SAAS,EAAE,QAAQ,CAAC,mBAAmB,IAAI,QAAQ,CAAC,SAAS,IAAI,6BAA6B;KAC/F,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB,CAAC,KAAsB;IAC5D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,IAAI;YACP,OAAO,qBAAqB,CAAC;QAC/B,KAAK,OAAO;YACV,OAAO,wBAAwB,KAAK,CAAC,OAAO,IAAI,CAAC;QACnD,KAAK,MAAM;YACT,OAAO,4DAA4D,CAAC;QACtE,KAAK,YAAY;YACf,OAAO,8BAA8B,KAAK,CAAC,MAAM,GAAG,CAAC;IACzD,CAAC;AACH,CAAC"}
@@ -0,0 +1,90 @@
1
+ import type { StrategyResult } from '../verify/deterministic-gate/verification-deterministic.js';
2
+ import type { VerifyCheckout } from '../verify/deterministic-gate/verification-checkout.js';
3
+ import type { WorktreeProvisioningStatus } from '../worktree/worktree-package-provisioning.js';
4
+ /** How long a run that could not START waits before it is tried again. */
5
+ export declare const LOCAL_RUN_START_BACKOFF_MS: number;
6
+ /** A completed run's verdict on one candidate commit. */
7
+ export interface LocalCompletionVerdict {
8
+ productId: string;
9
+ focusId: string;
10
+ sha: string;
11
+ outcome: 'passed' | 'failed';
12
+ command: string;
13
+ rationale: string;
14
+ exitCode: number | null;
15
+ timedOut: boolean;
16
+ logPath: string | null;
17
+ at: number;
18
+ }
19
+ /** What a failed local run leaves for the focus's re-work Bug. */
20
+ export interface LocalSuiteFailure {
21
+ command: string;
22
+ rationale: string;
23
+ logPath: string | null;
24
+ }
25
+ /** The candidate's standing under the local judge. */
26
+ export type LocalCandidateStatus = 'green' | 'red' | 'running' | 'unknown';
27
+ /** Why a start did or did not begin a run. */
28
+ export type LocalRunStart = {
29
+ kind: 'started';
30
+ } | {
31
+ kind: 'running';
32
+ } | {
33
+ kind: 'busy';
34
+ holder: string;
35
+ } | {
36
+ kind: 'not_ready';
37
+ reason: string;
38
+ };
39
+ /** The focus a run judges. */
40
+ export interface LocalJudgeSubject {
41
+ productId: string;
42
+ focusId: string;
43
+ focusName: string;
44
+ worktreePath: string;
45
+ }
46
+ /** The judge's collaborators; bound at the composition root (composition/execution-merge-context.ts). */
47
+ export interface LocalJudgeDeps {
48
+ readProvisioning: (worktreePath: string) => WorktreeProvisioningStatus;
49
+ /** A detached checkout of the focus worktree's HEAD (verification-checkout.ts createVerifyCheckout). */
50
+ createCheckout: (worktreePath: string, checkoutKey: string) => VerifyCheckout | null;
51
+ run: (config: {
52
+ command: string;
53
+ timeoutMs: number;
54
+ }, cwd: string, logContext: {
55
+ deliveryId: string;
56
+ startedAtMs: number;
57
+ }) => Promise<StrategyResult>;
58
+ writeVerdict: (verdict: LocalCompletionVerdict) => void;
59
+ now: () => number;
60
+ }
61
+ /** The record file for one candidate; `dir` defaults to the global state dir. Exported for tests. */
62
+ export declare function localVerdictPath(productId: string, focusId: string, sha: string, dir?: string): string;
63
+ /** Write a verdict atomically (temp + rename). Throws when it cannot. */
64
+ export declare function writeLocalVerdict(verdict: LocalCompletionVerdict, dir?: string): void;
65
+ /** The recorded verdict on a candidate, or null when none is recorded (or it is unreadable). */
66
+ export declare function readLocalVerdict(productId: string, focusId: string, sha: string, dir?: string): LocalCompletionVerdict | null;
67
+ /** Reset the judge's memory -- tests start from a clean slate. */
68
+ export declare function __resetLocalJudgeForTests(): void;
69
+ /** Resolves when the run in flight (if any) has settled -- tests await a run they started. */
70
+ export declare function __settleLocalJudgeForTests(): Promise<void>;
71
+ /**
72
+ * The candidate's standing: its recorded verdict, else running when its run is
73
+ * in flight, else unknown (no run yet -- the gate names the run step).
74
+ */
75
+ export declare function readLocalCandidateStatus(productId: string, focusId: string, sha: string, readVerdict: (productId: string, focusId: string, sha: string) => LocalCompletionVerdict | null): LocalCandidateStatus;
76
+ /** What a failed verdict leaves for the re-work Bug, or null when the candidate has no failed verdict. */
77
+ export declare function readLocalFailure(productId: string, focusId: string, sha: string, readVerdict: (productId: string, focusId: string, sha: string) => LocalCompletionVerdict | null): LocalSuiteFailure | null;
78
+ /** A run's result as a verdict, or null when the run never ran (it could not start). Pure. */
79
+ export declare function verdictOf(subject: LocalJudgeSubject, sha: string, command: string, result: StrategyResult, at: number): LocalCompletionVerdict | null;
80
+ /**
81
+ * Start the local completion run of `sha` (the focus worktree's HEAD) unless one
82
+ * is in flight, the slot is taken, the worktree is not provisioned, the last
83
+ * start failed within the backoff, or no checkout of `sha` can be made. Never
84
+ * awaits the run.
85
+ */
86
+ export declare function startLocalCandidateRun(subject: LocalJudgeSubject, sha: string, judge: {
87
+ command: string;
88
+ timeoutMs: number;
89
+ }, deps: LocalJudgeDeps): LocalRunStart;
90
+ //# sourceMappingURL=completion-local-judge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-local-judge.d.ts","sourceRoot":"","sources":["../../src/merge/completion-local-judge.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4DAA4D,CAAC;AACjG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8CAA8C,CAAC;AAI/F,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,QAAiB,CAAC;AAEzD,yDAAyD;AACzD,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,sDAAsD;AACtD,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;AAE3E,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,8BAA8B;AAC9B,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,yGAAyG;AACzG,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,0BAA0B,CAAC;IACvE,wGAAwG;IACxG,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,cAAc,GAAG,IAAI,CAAC;IACrF,GAAG,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACvJ,YAAY,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IACxD,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAQD,qGAAqG;AACrG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,MAAM,CAEpH;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,GAAE,MAAqB,GAAG,IAAI,CAMnG;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAqB,GAAG,sBAAsB,GAAG,IAAI,CAsB3I;AAaD,kEAAkE;AAClE,wBAAgB,yBAAyB,IAAI,IAAI,CAGhD;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,sBAAsB,GAAG,IAAI,GAC9F,oBAAoB,CAKtB;AAED,0GAA0G;AAC1G,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,sBAAsB,GAAG,IAAI,GAC9F,iBAAiB,GAAG,IAAI,CAI1B;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CACvB,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,EAAE,EAAE,MAAM,GACT,sBAAsB,GAAG,IAAI,CAgB/B;AAgCD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC7C,IAAI,EAAE,cAAc,GACnB,aAAa,CAsBf"}
@@ -0,0 +1,193 @@
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-local-judge.test.ts
3
+ // PINNED-BY-END
4
+ /**
5
+ * The LOCAL completion judge: the daemon runs a product's completion command on
6
+ * exactly a completed focus's integration candidate (the focus head after the
7
+ * integration tip was merged in) and records the verdict, so integration
8
+ * fast-forwards only to a commit whose combined tree passed the product's full
9
+ * suite -- without depending on a remote CI that may publish nothing
10
+ * (merge/completion-judge.ts; docs/DECISIONS.md, "The completion candidate is
11
+ * judged where the product declares").
12
+ *
13
+ * The run happens in a detached checkout of the focus worktree's HEAD, made the
14
+ * way a deterministic verify makes one (verify/deterministic-gate/verification-checkout.ts):
15
+ * the focus worktree must be provisioned from the candidate's own lockfiles (a
16
+ * merge-out that changed them waits for the install), the checkout must hold
17
+ * the candidate sha (a head that moved is not judged), and a verdict rendered
18
+ * while the linked dependencies moved is discarded. The command runs through the
19
+ * same process-group runner, with the declared timeout.
20
+ *
21
+ * A run is long, so it is STARTED by the merge-back loop and never awaited by
22
+ * it: the verdict lands in a durable record (one file per product, focus and
23
+ * sha under the global state dir), which the completion gate reads on a later
24
+ * tick. One run at a time per daemon -- a full suite is heavy and the host also
25
+ * runs teams. What counts as a verdict is a run that exited (any exit code) or
26
+ * was killed by its timeout; a run that could not start is NOT a verdict -- it is
27
+ * logged and retried after a backoff, never charged to the focus.
28
+ *
29
+ * @module merge/completion-local-judge
30
+ */
31
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
32
+ import { resolve } from 'node:path';
33
+ import { resolveGlobalStateDir } from '../daemon-state/daemon-process.js';
34
+ import { createLogger } from '../log/daemon-log.js';
35
+ const log = createLogger({ module: 'completion-merge' });
36
+ /** How long a run that could not START waits before it is tried again. */
37
+ export const LOCAL_RUN_START_BACKOFF_MS = 10 * 60 * 1000;
38
+ // ── Durable verdict record ───────────────────────────────────────────
39
+ function verdictDir() {
40
+ return resolve(resolveGlobalStateDir(), 'completion-verdicts');
41
+ }
42
+ /** The record file for one candidate; `dir` defaults to the global state dir. Exported for tests. */
43
+ export function localVerdictPath(productId, focusId, sha, dir = verdictDir()) {
44
+ return resolve(dir, `${productId}-${focusId}-${sha}.json`.replace(/[^a-zA-Z0-9._-]/g, '_'));
45
+ }
46
+ /** Write a verdict atomically (temp + rename). Throws when it cannot. */
47
+ export function writeLocalVerdict(verdict, dir = verdictDir()) {
48
+ mkdirSync(dir, { recursive: true });
49
+ const path = localVerdictPath(verdict.productId, verdict.focusId, verdict.sha, dir);
50
+ const tmp = `${path}.${process.pid}.tmp`;
51
+ writeFileSync(tmp, JSON.stringify(verdict));
52
+ renameSync(tmp, path);
53
+ }
54
+ /** The recorded verdict on a candidate, or null when none is recorded (or it is unreadable). */
55
+ export function readLocalVerdict(productId, focusId, sha, dir = verdictDir()) {
56
+ let parsed;
57
+ try {
58
+ parsed = JSON.parse(readFileSync(localVerdictPath(productId, focusId, sha, dir), 'utf8'));
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ if (typeof parsed !== 'object' || parsed === null)
64
+ return null;
65
+ const v = parsed;
66
+ if (v.sha !== sha || (v.outcome !== 'passed' && v.outcome !== 'failed') || typeof v.command !== 'string')
67
+ return null;
68
+ return {
69
+ productId,
70
+ focusId,
71
+ sha,
72
+ outcome: v.outcome,
73
+ command: v.command,
74
+ rationale: typeof v.rationale === 'string' ? v.rationale : '',
75
+ exitCode: typeof v.exitCode === 'number' ? v.exitCode : null,
76
+ timedOut: v.timedOut === true,
77
+ logPath: typeof v.logPath === 'string' ? v.logPath : null,
78
+ at: typeof v.at === 'number' ? v.at : 0,
79
+ };
80
+ }
81
+ // ── In-flight runs ───────────────────────────────────────────────────
82
+ /** The one run in flight (a full suite at a time per daemon). */
83
+ let slot = null;
84
+ /** When a run of (focus, sha) last failed to START, for the backoff. */
85
+ const startFailures = new Map();
86
+ function key(productId, focusId) {
87
+ return `${productId}:${focusId}`;
88
+ }
89
+ /** Reset the judge's memory -- tests start from a clean slate. */
90
+ export function __resetLocalJudgeForTests() {
91
+ slot = null;
92
+ startFailures.clear();
93
+ }
94
+ /** Resolves when the run in flight (if any) has settled -- tests await a run they started. */
95
+ export function __settleLocalJudgeForTests() {
96
+ return slot?.done ?? Promise.resolve();
97
+ }
98
+ /**
99
+ * The candidate's standing: its recorded verdict, else running when its run is
100
+ * in flight, else unknown (no run yet -- the gate names the run step).
101
+ */
102
+ export function readLocalCandidateStatus(productId, focusId, sha, readVerdict) {
103
+ const verdict = readVerdict(productId, focusId, sha);
104
+ if (verdict !== null)
105
+ return verdict.outcome === 'passed' ? 'green' : 'red';
106
+ if (slot !== null && slot.key === key(productId, focusId) && slot.sha === sha)
107
+ return 'running';
108
+ return 'unknown';
109
+ }
110
+ /** What a failed verdict leaves for the re-work Bug, or null when the candidate has no failed verdict. */
111
+ export function readLocalFailure(productId, focusId, sha, readVerdict) {
112
+ const verdict = readVerdict(productId, focusId, sha);
113
+ if (verdict === null || verdict.outcome !== 'failed')
114
+ return null;
115
+ return { command: verdict.command, rationale: verdict.rationale, logPath: verdict.logPath };
116
+ }
117
+ /** A run's result as a verdict, or null when the run never ran (it could not start). Pure. */
118
+ export function verdictOf(subject, sha, command, result, at) {
119
+ const timedOut = result.timedOut === true;
120
+ const exited = typeof result.exitCode === 'number';
121
+ if (!timedOut && !exited)
122
+ return null;
123
+ return {
124
+ productId: subject.productId,
125
+ focusId: subject.focusId,
126
+ sha,
127
+ outcome: !timedOut && result.outcome === 'passed' ? 'passed' : 'failed',
128
+ command,
129
+ rationale: result.rationale ?? (result.outcome === 'passed' ? 'passed' : 'failed'),
130
+ exitCode: exited ? result.exitCode : null,
131
+ timedOut,
132
+ logPath: result.logPath ?? null,
133
+ at,
134
+ };
135
+ }
136
+ async function runToVerdict(subject, sha, judge, checkout, deps) {
137
+ const k = `${key(subject.productId, subject.focusId)}:${sha}`;
138
+ try {
139
+ const result = await deps.run(judge, checkout.path, { deliveryId: `completion-${subject.focusId}`, startedAtMs: deps.now() });
140
+ if (checkout.dependenciesMoved()) {
141
+ log.warn(`[completion-merge] "${subject.focusName}": dependencies moved during the local run of ${sha.slice(0, 9)}; verdict discarded, re-run next tick`);
142
+ return;
143
+ }
144
+ const verdict = verdictOf(subject, sha, judge.command, result, deps.now());
145
+ if (verdict === null) {
146
+ startFailures.set(k, deps.now());
147
+ log.warn(`[completion-merge] "${subject.focusName}": the local completion run of ${sha.slice(0, 9)} did not run (${result.rationale ?? 'no exit'}); retried after a backoff`);
148
+ return;
149
+ }
150
+ deps.writeVerdict(verdict);
151
+ log.info(`[completion-merge] "${subject.focusName}": local completion run of ${sha.slice(0, 9)} ${verdict.outcome.toUpperCase()} (\`${judge.command}\`: ${verdict.rationale})${verdict.logPath ? ` -- log ${verdict.logPath}` : ''}`);
152
+ }
153
+ catch (err) {
154
+ startFailures.set(k, deps.now());
155
+ log.warn(`[completion-merge] "${subject.focusName}": the local completion run of ${sha.slice(0, 9)} errored: ${err.message}; retried after a backoff`);
156
+ }
157
+ finally {
158
+ checkout.dispose();
159
+ }
160
+ }
161
+ /**
162
+ * Start the local completion run of `sha` (the focus worktree's HEAD) unless one
163
+ * is in flight, the slot is taken, the worktree is not provisioned, the last
164
+ * start failed within the backoff, or no checkout of `sha` can be made. Never
165
+ * awaits the run.
166
+ */
167
+ export function startLocalCandidateRun(subject, sha, judge, deps) {
168
+ const k = key(subject.productId, subject.focusId);
169
+ if (slot !== null) {
170
+ return slot.key === k && slot.sha === sha ? { kind: 'running' } : { kind: 'busy', holder: `"${slot.focusName}" at ${slot.sha.slice(0, 9)}` };
171
+ }
172
+ const failedAt = startFailures.get(`${k}:${sha}`);
173
+ if (failedAt !== undefined && deps.now() - failedAt < LOCAL_RUN_START_BACKOFF_MS) {
174
+ return { kind: 'not_ready', reason: `the last run of ${sha.slice(0, 9)} could not start; retried after ${Math.round(LOCAL_RUN_START_BACKOFF_MS / 60_000)}m` };
175
+ }
176
+ const provisioning = deps.readProvisioning(subject.worktreePath);
177
+ if (!provisioning.ready)
178
+ return { kind: 'not_ready', reason: `the focus worktree is not provisioned (${provisioning.state}: ${provisioning.reason})` };
179
+ const checkout = deps.createCheckout(subject.worktreePath, `completion-${subject.focusId}`);
180
+ if (checkout === null)
181
+ return { kind: 'not_ready', reason: 'no detached checkout of the focus head could be made' };
182
+ if (checkout.sha !== sha) {
183
+ checkout.dispose();
184
+ return { kind: 'not_ready', reason: `the focus head is ${checkout.sha.slice(0, 9)}, not the candidate ${sha.slice(0, 9)}` };
185
+ }
186
+ const done = runToVerdict(subject, sha, judge, checkout, deps).finally(() => {
187
+ if (slot?.key === k && slot.sha === sha)
188
+ slot = null;
189
+ });
190
+ slot = { key: k, sha, focusName: subject.focusName, done };
191
+ return { kind: 'started' };
192
+ }
193
+ //# sourceMappingURL=completion-local-judge.js.map