@telora/daemon 0.23.15 → 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 (109) hide show
  1. package/build-info.json +4 -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/codex/codex-backend.d.ts.map +1 -1
  8. package/dist/backends/codex/codex-backend.js +10 -0
  9. package/dist/backends/codex/codex-backend.js.map +1 -1
  10. package/dist/ci/candidate-ref.d.ts +13 -0
  11. package/dist/ci/candidate-ref.d.ts.map +1 -1
  12. package/dist/ci/candidate-ref.js +18 -0
  13. package/dist/ci/candidate-ref.js.map +1 -1
  14. package/dist/composition/execution-merge-context.d.ts +7 -1
  15. package/dist/composition/execution-merge-context.d.ts.map +1 -1
  16. package/dist/composition/execution-merge-context.js +42 -6
  17. package/dist/composition/execution-merge-context.js.map +1 -1
  18. package/dist/composition/execution-recovery-context.d.ts.map +1 -1
  19. package/dist/composition/execution-recovery-context.js +2 -0
  20. package/dist/composition/execution-recovery-context.js.map +1 -1
  21. package/dist/config/model-resolution.d.ts +25 -1
  22. package/dist/config/model-resolution.d.ts.map +1 -1
  23. package/dist/config/model-resolution.js +26 -1
  24. package/dist/config/model-resolution.js.map +1 -1
  25. package/dist/focus/crash-recovery.d.ts +7 -0
  26. package/dist/focus/crash-recovery.d.ts.map +1 -1
  27. package/dist/focus/crash-recovery.js +26 -13
  28. package/dist/focus/crash-recovery.js.map +1 -1
  29. package/dist/focus/focus-executor.d.ts.map +1 -1
  30. package/dist/focus/focus-executor.js +1 -0
  31. package/dist/focus/focus-executor.js.map +1 -1
  32. package/dist/focus/focus-poller-spawn.d.ts.map +1 -1
  33. package/dist/focus/focus-poller-spawn.js +3 -1
  34. package/dist/focus/focus-poller-spawn.js.map +1 -1
  35. package/dist/merge/candidate-rework.d.ts +3 -3
  36. package/dist/merge/candidate-rework.d.ts.map +1 -1
  37. package/dist/merge/candidate-rework.js +30 -10
  38. package/dist/merge/candidate-rework.js.map +1 -1
  39. package/dist/merge/completion-hold-record.d.ts +16 -0
  40. package/dist/merge/completion-hold-record.d.ts.map +1 -1
  41. package/dist/merge/completion-hold-record.js +60 -1
  42. package/dist/merge/completion-hold-record.js.map +1 -1
  43. package/dist/merge/completion-judge.d.ts +44 -0
  44. package/dist/merge/completion-judge.d.ts.map +1 -0
  45. package/dist/merge/completion-judge.js +36 -0
  46. package/dist/merge/completion-judge.js.map +1 -0
  47. package/dist/merge/completion-local-judge.d.ts +90 -0
  48. package/dist/merge/completion-local-judge.d.ts.map +1 -0
  49. package/dist/merge/completion-local-judge.js +193 -0
  50. package/dist/merge/completion-local-judge.js.map +1 -0
  51. package/dist/merge/completion-merge-driver.d.ts +31 -7
  52. package/dist/merge/completion-merge-driver.d.ts.map +1 -1
  53. package/dist/merge/completion-merge-driver.js +36 -8
  54. package/dist/merge/completion-merge-driver.js.map +1 -1
  55. package/dist/merge/completion-merge-gate.d.ts +10 -2
  56. package/dist/merge/completion-merge-gate.d.ts.map +1 -1
  57. package/dist/merge/completion-merge-gate.js +65 -19
  58. package/dist/merge/completion-merge-gate.js.map +1 -1
  59. package/dist/merge/merge-back-loop.d.ts +9 -1
  60. package/dist/merge/merge-back-loop.d.ts.map +1 -1
  61. package/dist/merge/merge-back-loop.js +28 -1
  62. package/dist/merge/merge-back-loop.js.map +1 -1
  63. package/dist/queries/api-client/shared.js +1 -1
  64. package/dist/queries/focuses/focus-discovery.d.ts +14 -0
  65. package/dist/queries/focuses/focus-discovery.d.ts.map +1 -1
  66. package/dist/queries/focuses/focus-discovery.js +4 -0
  67. package/dist/queries/focuses/focus-discovery.js.map +1 -1
  68. package/dist/queries/org-config/local-models.d.ts.map +1 -1
  69. package/dist/queries/org-config/local-models.js +2 -1
  70. package/dist/queries/org-config/local-models.js.map +1 -1
  71. package/dist/queries/wire-schemas/schemas.d.ts +48 -0
  72. package/dist/queries/wire-schemas/schemas.d.ts.map +1 -1
  73. package/dist/queries/wire-schemas/schemas.js +15 -0
  74. package/dist/queries/wire-schemas/schemas.js.map +1 -1
  75. package/dist/spawn/model-routing.d.ts +13 -8
  76. package/dist/spawn/model-routing.d.ts.map +1 -1
  77. package/dist/spawn/model-routing.js +14 -8
  78. package/dist/spawn/model-routing.js.map +1 -1
  79. package/dist/spawn/spawn-decision.d.ts +7 -0
  80. package/dist/spawn/spawn-decision.d.ts.map +1 -1
  81. package/dist/spawn/spawn-decision.js.map +1 -1
  82. package/dist/testing/fixtures/api-client.js +1 -1
  83. package/dist/testing/fixtures/completion-judge-stubs.d.ts +15 -0
  84. package/dist/testing/fixtures/completion-judge-stubs.d.ts.map +1 -0
  85. package/dist/testing/fixtures/completion-judge-stubs.js +32 -0
  86. package/dist/testing/fixtures/completion-judge-stubs.js.map +1 -0
  87. package/dist/testing/fixtures/index.d.ts.map +1 -1
  88. package/dist/testing/fixtures/index.js +3 -1
  89. package/dist/testing/fixtures/index.js.map +1 -1
  90. package/dist/types/focus.d.ts +9 -0
  91. package/dist/types/focus.d.ts.map +1 -1
  92. package/dist/verify/deterministic-gate/verification-checkout.d.ts.map +1 -1
  93. package/dist/verify/deterministic-gate/verification-checkout.js +1 -0
  94. package/dist/verify/deterministic-gate/verification-checkout.js.map +1 -1
  95. package/dist/verify/deterministic-gate/verification-deterministic.d.ts.map +1 -1
  96. package/dist/verify/deterministic-gate/verification-deterministic.js +1 -0
  97. package/dist/verify/deterministic-gate/verification-deterministic.js.map +1 -1
  98. package/dist/verify/gate-config/verification-manifest.d.ts +21 -1
  99. package/dist/verify/gate-config/verification-manifest.d.ts.map +1 -1
  100. package/dist/verify/gate-config/verification-manifest.js +25 -1
  101. package/dist/verify/gate-config/verification-manifest.js.map +1 -1
  102. package/dist/verify/run-selection/verification-default-on.d.ts +2 -0
  103. package/dist/verify/run-selection/verification-default-on.d.ts.map +1 -1
  104. package/dist/verify/run-selection/verification-default-on.js +1 -1
  105. package/dist/verify/run-selection/verification-default-on.js.map +1 -1
  106. package/dist/worktree/focus-worktree-state.d.ts.map +1 -1
  107. package/dist/worktree/focus-worktree-state.js +1 -0
  108. package/dist/worktree/focus-worktree-state.js.map +1 -1
  109. package/package.json +3 -3
@@ -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":"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"}
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-local-judge.js","sourceRoot":"","sources":["../../src/merge/completion-local-judge.ts"],"names":[],"mappings":"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"}
@@ -15,13 +15,24 @@
15
15
  * push_candidate -> push the head to the focus's candidate branch so CI runs the
16
16
  * full suite on exactly that commit (ci/candidate-ref.ts).
17
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.
18
+ * no verdict; then the candidate is RE-PUSHED once (deleted
19
+ * and pushed again, so CI sees a fresh push), and after a
20
+ * second window with no verdict the merge simply holds --
21
+ * the stuck_focus_branch observation surfaces it. A missing
22
+ * verdict is the CI's fault, not the focus's: it is never
23
+ * re-work (no team can fix a missing verdict, and a
24
+ * converged review resets the cycle cap, so re-work would
25
+ * never end). The wait is counted from a DURABLE stamp of the
26
+ * candidate (merge/completion-hold-record.ts), so a daemon
27
+ * restart neither restarts nor forgets the window.
28
+ * run_local -> start the daemon's own run of the completion command on the
29
+ * head (merge/completion-local-judge.ts); its verdict lands
30
+ * on a later tick.
22
31
  * rework -> return the focus to coding: one Bug on the owning delivery,
23
32
  * re-opened to verify_failed (merge/candidate-rework.ts). No
24
33
  * escalation is filed.
34
+ * rework_local -> the same, for a candidate that failed the local run; the
35
+ * Bug names the command, its result and the log.
25
36
  *
26
37
  * Integration never moves here; a green candidate is admitted by the gate and
27
38
  * fast-forwarded by the caller's normal merge.
@@ -29,7 +40,8 @@
29
40
  * @module merge/completion-merge-driver
30
41
  */
31
42
  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. */
43
+ import type { LocalRunStart, LocalSuiteFailure } from './completion-local-judge.js';
44
+ /** How long a pushed candidate may sit with no published verdict before it is re-pushed (once). */
33
45
  export declare const CANDIDATE_CI_VERDICT_WAIT_MS: number;
34
46
  /** The focus branch a step acts on. */
35
47
  export interface CompletionMergeSubject {
@@ -39,7 +51,9 @@ export interface CompletionMergeSubject {
39
51
  branchName: string;
40
52
  }
41
53
  /** Why a candidate is returned to the focus as re-work. */
42
- export type CandidateReworkCause = 'red' | 'no_verdict' | 'conflict' | 'unreviewed_merge';
54
+ export type CandidateReworkCause = 'red' | 'local_red' | 'conflict' | 'unreviewed_merge';
55
+ /** What a re-work Bug is told beyond its cause: a conflict's paths, or a failed local run. */
56
+ export type CandidateReworkDetail = CompletionMergeConflict | LocalSuiteFailure;
43
57
  /** What a conflicting final merge left for the team: the paths, and the integration commits the branch lacks. */
44
58
  export interface CompletionMergeConflict {
45
59
  integrationBranch: string;
@@ -77,8 +91,18 @@ export interface CompletionMergeDriverDeps {
77
91
  * becomes re-work.
78
92
  */
79
93
  candidateWaitSince: (sha: string, now: number) => number | null;
94
+ /** Whether the focus's candidate `sha` was already re-pushed for a missing verdict. */
95
+ candidateRepushed: (sha: string) => boolean;
96
+ /** Record that `sha` was re-pushed at `now`, restarting its wait window. */
97
+ markCandidateRepushed: (sha: string, now: number) => void;
98
+ /** Delete and re-push the focus's candidate branch at `sha`, so CI sees a fresh push; false on failure. */
99
+ repushCandidate: (repoPath: string, focusId: string, sha: string) => boolean;
100
+ /** Start the daemon's local completion run of `sha` (never awaited). */
101
+ startLocalRun: (sha: string) => LocalRunStart;
102
+ /** What a failed local run of `sha` recorded, for the re-work Bug. */
103
+ readLocalFailure: (sha: string) => LocalSuiteFailure | null;
80
104
  /** 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>;
105
+ routeRework: (subject: CompletionMergeSubject, sha: string, cause: CandidateReworkCause, detail: CandidateReworkDetail | null) => Promise<CandidateReworkOutcome>;
82
106
  now: () => number;
83
107
  }
84
108
  /** Reset the driver's memory -- tests start from a clean slate. */
@@ -1 +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"}
1
+ {"version":3,"file":"completion-merge-driver.d.ts","sourceRoot":"","sources":["../../src/merge/completion-merge-driver.ts"],"names":[],"mappings":"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"}