@adhdev/daemon-core 0.9.82-rc.523 → 0.9.82-rc.525

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.
@@ -13,6 +13,23 @@ export declare function buildRefineJobHandle(self: DaemonCommandRouter, args: {
13
13
  retryOfJobId?: string;
14
14
  coordinatorDaemonId?: string;
15
15
  }): MeshRefineJobHandle;
16
+ /**
17
+ * QW2: extract a compact failure diagnostic from a validation summary — the first
18
+ * failing command's name, its exit code, its failureKind, and a bounded output tail.
19
+ * Surfaced in BOTH the slim coordinator event and the ledger blockerContext so a
20
+ * coordinator can decide next-step without pulling and parsing the full ledger record.
21
+ *
22
+ * A command record carries `passed` (boolean), never `success` (see QW1) — the first
23
+ * record with passed===false is the gate's failing command. Returns undefined when the
24
+ * summary did not fail on a command (e.g. bootstrap-stage failure with no commandsRun
25
+ * entry), in which case the top-level failureCode/failureKind still describe the cause.
26
+ */
27
+ export declare function extractValidationFailureDiagnostics(validationSummary: Record<string, unknown> | undefined): {
28
+ firstFailedCommand?: string;
29
+ exitCode?: unknown;
30
+ failureKind?: unknown;
31
+ outputTail?: string;
32
+ } | undefined;
16
33
  /**
17
34
  * Slim the terminal-stage refine result down to the fields a coordinator needs to
18
35
  * decide next-step, dropping the heavy per-command / per-entry detail.
@@ -52,6 +69,26 @@ export declare function executeMeshRefineNodeSynchronously(self: DaemonCommandRo
52
69
  * branch head. Seeds the RefineContext consumed by every later stage.
53
70
  */
54
71
  export declare function refineResolveRefsStage(self: DaemonCommandRouter, meshId: string, nodeId: string, args: any, refineStages: Array<Record<string, unknown>>): Promise<RefineStageOutcome>;
72
+ /**
73
+ * DS2 sync_base stage: bring the worktree branch up to the pinned baseHead BEFORE
74
+ * validation, so every later gate (validation, patch_equivalence, merge) sees the
75
+ * final rebased tree rather than a stale pre-rebase one.
76
+ *
77
+ * The old auto-rebase lived inside patch_equivalence and only fired when branchHead
78
+ * was a STRICT ANCESTOR of baseHead (`merge-base --is-ancestor`). A diverged laggard
79
+ * — the branch has its own commits AND base moved underneath it (ahead>0 AND behind>0)
80
+ * — failed that ancestor check, so it was never rebased and fell straight to
81
+ * patch_equivalence_failed / blocked_review even though a clean rebase would have
82
+ * converged it. Here we compute ahead/behind explicitly and rebase whenever behind>0
83
+ * (strictly-behind OR diverged), aborting to blocked_review only on a real conflict.
84
+ *
85
+ * On a successful rebase we recompute branchHead and re-derive changeImpact against
86
+ * the rebased tree (its baseHead..branchHead diff changed), and record the
87
+ * `patch_equivalence_after_auto_rebase` stage so the batch/ancestry assertions can see
88
+ * the rebase happened. When the branch is already up to date (behind===0), this is a
89
+ * no-op passed stage.
90
+ */
91
+ export declare function refineSyncBaseStage(self: DaemonCommandRouter, ctx: RefineContext): Promise<RefineStageOutcome>;
55
92
  /**
56
93
  * validation stage: run the refinery validation gate (typecheck / test /
57
94
  * lint / build per node config) and block on failure or when no allowlisted
@@ -59,11 +96,11 @@ export declare function refineResolveRefsStage(self: DaemonCommandRouter, meshId
59
96
  */
60
97
  export declare function refineValidationStage(self: DaemonCommandRouter, ctx: RefineContext): Promise<RefineStageOutcome>;
61
98
  /**
62
- * patch_equivalence stage: preflight that the worktree branch's cumulative
63
- * patch is equivalent to base+branch. On a "behind base" branch, auto-rebase
64
- * once and re-check; on an empty merge-tree with real branch changes, treat as
65
- * already-merged-via-another-path and short-circuit to cleanup. Mutates the
66
- * context's branchHead (after rebase) and patchEquivalence (rebased gate).
99
+ * patch_equivalence stage: preflight that the worktree branch's cumulative patch is
100
+ * equivalent to base+branch. The DS2 sync_base stage already rebased any behind/diverged
101
+ * branch onto the pinned baseHead, so this is now a pure check: equivalent → continue;
102
+ * empty merge-tree with real branch changes → already-merged-via-another-path
103
+ * short-circuit to cleanup; otherwise patch_equivalence_failed / blocked_review.
67
104
  */
68
105
  export declare function refinePatchEquivalenceStage(self: DaemonCommandRouter, ctx: RefineContext): Promise<RefineStageOutcome>;
69
106
  /**
@@ -80,6 +117,33 @@ export declare function refineSubmoduleReachabilityStage(self: DaemonCommandRout
80
117
  * never committed, so the merge would land nothing real on main.
81
118
  */
82
119
  export declare function refineEffectiveDiffStage(self: DaemonCommandRouter, ctx: RefineContext): Promise<RefineStageOutcome>;
120
+ /**
121
+ * DS3: after a successful Refinery push advanced origin/<baseBranch>, bring the
122
+ * ORIGINATING COORDINATOR daemon's own local base checkout up to the pushed commit so
123
+ * the coordinator isn't silently left behind (the "merged to main but my local main is
124
+ * stale" gap). Guarded and NON-destructive:
125
+ *
126
+ * - If the coordinator's base node is hosted by THIS daemon and is reachable locally,
127
+ * run fastForwardMeshNode(mode:'merge') on it directly. That helper is itself the
128
+ * guard: it only ff-only-merges when the workspace is clean, ahead=0 and behind>0;
129
+ * an ahead/diverged/dirty coordinator returns a structured block (never a rebase).
130
+ * - If the coordinator is a DIFFERENT daemon (remote), we cannot touch its checkout
131
+ * from here, so we queue a `coordinator_catchup` pending event targeted at that
132
+ * coordinator daemon; its reconcile loop / next mesh-tool call drains it and runs the
133
+ * same guarded fast-forward locally (busy → naturally deferred to the next idle edge).
134
+ *
135
+ * Best-effort and advisory: the caller never fails the refine on a catch-up problem. The
136
+ * refine's own repoRoot IS the base it just merged+pushed, so when the coordinator IS this
137
+ * daemon and IS repoRoot the ff is a no-op `already_up_to_date` — correct and harmless.
138
+ * Returns a compact summary for the stage record, or undefined when there's nothing to do.
139
+ */
140
+ export declare function requestCoordinatorLocalCatchup(self: DaemonCommandRouter, params: {
141
+ meshId: string;
142
+ ctx: RefineContext;
143
+ mesh: any;
144
+ baseBranch: string;
145
+ repoRoot: string;
146
+ }): Promise<Record<string, unknown> | undefined>;
83
147
  /**
84
148
  * merge + finalize stage: perform the --no-ff merge, align submodule
85
149
  * checkouts after merge, clean up (remove) the worktree node per policy,
@@ -87,6 +151,16 @@ export declare function refineEffectiveDiffStage(self: DaemonCommandRouter, ctx:
87
151
  * base branch. Always terminal — produces the final CommandRouterResult.
88
152
  */
89
153
  export declare function refineMergeAndFinalizeStage(self: DaemonCommandRouter, ctx: RefineContext): Promise<RefineStageOutcome>;
154
+ /**
155
+ * DS2 CAS + DS1 order: the base-lease-protected core of merge/finalize. Before the
156
+ * merge it re-fetches origin/<baseBranch> and compare-and-swaps the live origin SHA
157
+ * against the pinned baseHead from resolve_refs; if the base moved, it terminates
158
+ * retryable (base_moved) WITHOUT merging so a re-run rebases onto and validates the
159
+ * new base. DS1: on the auto-push path the order is merge → push → cleanup, so a push
160
+ * failure leaves the worktree/branch intact (cleanup withheld) and is reported as a
161
+ * terminal blocked state — the batch never counts an un-pushed node as merged.
162
+ */
163
+ export declare function runRefineMergeAndFinalizeLocked(self: DaemonCommandRouter, ctx: RefineContext): Promise<RefineStageOutcome>;
90
164
  /**
91
165
  * Batch refinery: converge multiple sibling worktree nodes onto the base branch
92
166
  * in one sequential pipeline, absorbing the rebase + patch-equivalence churn that
@@ -101,6 +175,13 @@ export declare function refineMergeAndFinalizeStage(self: DaemonCommandRouter, c
101
175
  * isolated as blocked_review while the rest of the batch proceeds.
102
176
  */
103
177
  export declare function batchRefineMeshNodes(self: DaemonCommandRouter, meshId: string, requestedNodeIds: string[] | undefined, args: any): Promise<CommandRouterResult>;
178
+ export type BatchNodeConvergence = 'merged_to_main' | 'blocked_review' | 'skipped_patch_equivalent' | 'not_mergeable';
179
+ export declare function classifyBatchNodeConvergence(result: Record<string, unknown>): {
180
+ convergence: BatchNodeConvergence;
181
+ code: string;
182
+ stage?: string;
183
+ retryable: boolean;
184
+ };
104
185
  /**
105
186
  * Convergence core shared by the synchronous batch entry and the async batch job.
106
187
  * Refines each node in order: the per-node refine pipeline fetches origin/<base>
@@ -137,6 +137,15 @@ export declare class DaemonCommandRouter {
137
137
  runningRefineBatchJobs: Map<string, MeshRefineBatchJobHandle>;
138
138
  /** Terminal async batch Refinery jobs preserve the last batch outcome for late readers. */
139
139
  terminalRefineBatchJobs: Map<string, MeshRefineBatchTerminalJob>;
140
+ /**
141
+ * DS2: in-process refinement leases keyed by `${repoRoot}::${baseBranch}`. Serialize
142
+ * the base-mutating window (candidate-SHA pin → merge → push) of concurrent single-node
143
+ * refines that target the SAME base branch in the same repo, so two refines cannot both
144
+ * validate against one baseHead and then race their merges (the base-movement race). The
145
+ * batch path is already sequential, so this only matters for overlapping single-node
146
+ * async jobs. Value = the meshId:nodeId job key holding the lease (for diagnostics).
147
+ */
148
+ refineBaseLeases: Map<string, string>;
140
149
  constructor(deps: CommandRouterDeps);
141
150
  private hydrateCachedAggregateMeshStatusFromInline;
142
151
  private getCachedAggregateMeshStatus;
@@ -1,6 +1,6 @@
1
1
  import type { GitRepoStatus } from './git-types.js';
2
2
  import { type DaemonBuildInfo } from '../build-info.js';
3
- import { type ChangeImpactConfig } from './change-impact-config.js';
3
+ import { type ChangeImpactConfig, type ChangeImpactKind } from './change-impact-config.js';
4
4
  /**
5
5
  * TTL for the happy-path result cache (C1). reconcile fires every 4s and mesh_status
6
6
  * is polled; a single getGitRepoStatus on a 1-submodule repo spawns ~13-15 git
@@ -71,6 +71,19 @@ export declare function getGitRepoStatus(workspace: string, options?: GitStatusO
71
71
  export interface ChangedPackageClassification {
72
72
  isDaemonAffecting: boolean;
73
73
  affectedPackages: string[];
74
+ /**
75
+ * DOCS-ROOT: three-way change area, refining the binary isDaemonAffecting so a
76
+ * docs-only branch is distinguishable from a code (web) branch:
77
+ * 'daemon' — a daemon-runtime package (or an unknown/ambiguous path) changed;
78
+ * full validation + daemon rebuild/restart required.
79
+ * 'web' — only web-only packages changed; web validation but no daemon restart.
80
+ * 'none' — no package changed at all; every changed file is a benign non-runtime
81
+ * root file (docs/markers). No code validation is meaningful — only an
82
+ * explicit docs-scoped profile (e.g. docs:verify) should run.
83
+ * Derived from the same facts as isDaemonAffecting, so it never contradicts it
84
+ * (changeArea === 'daemon' ⇔ isDaemonAffecting === true).
85
+ */
86
+ changeArea: ChangeImpactKind;
74
87
  }
75
88
  /**
76
89
  * Ref-parameterized change-impact classification for a repo/worktree, reusing the