merge-steward 0.9.0 → 0.9.2

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.
@@ -115,7 +115,7 @@ export class ShellGitOperations {
115
115
  // PR branches are always remote refs — use explicit origin/ prefix
116
116
  // because git DWIM doesn't reliably resolve bare names in worktrees.
117
117
  const mergeRef = prBranch.startsWith("origin/") ? prBranch : `origin/${prBranch}`;
118
- const mergeArgs = ["merge", "--no-ff"];
118
+ const mergeArgs = ["merge", "--no-ff", "-X", "patience"];
119
119
  if (mergeMessage)
120
120
  mergeArgs.push("-m", mergeMessage);
121
121
  mergeArgs.push(mergeRef);
package/dist/service.d.ts CHANGED
@@ -67,6 +67,12 @@ export declare class MergeStewardService {
67
67
  updateHeadByPR(prNumber: number, headSha: string): void;
68
68
  /** Acknowledge an external merge (webhook: PR merged outside queue). */
69
69
  acknowledgeExternalMerge(prNumber: number): void;
70
+ /**
71
+ * Reset all active entries positioned after the given entry to preparing_head
72
+ * with clean spec/CI state. Prevents downstream specs that included the
73
+ * dequeued entry's changes from being merged to main.
74
+ */
75
+ private invalidateDownstreamOf;
70
76
  private runTick;
71
77
  private scheduleNextTick;
72
78
  private describeMainBroken;
package/dist/service.js CHANGED
@@ -127,6 +127,7 @@ export class MergeStewardService {
127
127
  if (!entry)
128
128
  return false;
129
129
  this.store.dequeue(entryId);
130
+ this.invalidateDownstreamOf(entry);
130
131
  this.logger.info({ entryId, prNumber: entry.prNumber }, "Entry dequeued");
131
132
  return true;
132
133
  }
@@ -252,6 +253,7 @@ export class MergeStewardService {
252
253
  const entry = this.store.getEntryByPR(this.config.repoId, prNumber);
253
254
  if (entry) {
254
255
  this.store.dequeue(entry.id);
256
+ this.invalidateDownstreamOf(entry);
255
257
  this.logger.info({ prNumber, entryId: entry.id }, "PR dequeued");
256
258
  }
257
259
  }
@@ -275,6 +277,29 @@ export class MergeStewardService {
275
277
  this.logger.info({ prNumber, entryId: entry.id }, "External merge acknowledged");
276
278
  }
277
279
  }
280
+ /**
281
+ * Reset all active entries positioned after the given entry to preparing_head
282
+ * with clean spec/CI state. Prevents downstream specs that included the
283
+ * dequeued entry's changes from being merged to main.
284
+ */
285
+ invalidateDownstreamOf(removedEntry) {
286
+ const allActive = this.store.listActive(this.config.repoId);
287
+ let invalidated = 0;
288
+ for (const downstream of allActive) {
289
+ if (downstream.position <= removedEntry.position)
290
+ continue;
291
+ if (TERMINAL_STATUSES.includes(downstream.status))
292
+ continue;
293
+ this.store.transition(downstream.id, "preparing_head", {
294
+ ciRunId: null, ciRetries: 0,
295
+ specBranch: null, specSha: null, specBasedOn: null,
296
+ }, `invalidated: entry ${removedEntry.id.slice(0, 8)} dequeued`);
297
+ invalidated++;
298
+ }
299
+ if (invalidated > 0) {
300
+ this.logger.info({ removedEntryId: removedEntry.id, invalidated }, "Invalidated downstream entries after dequeue");
301
+ }
302
+ }
278
303
  async runTick() {
279
304
  if (this.tickInProgress)
280
305
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "merge-steward",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Serial merge queue for GitHub — rebase, CI-gate, and merge PRs one at a time",
5
5
  "type": "module",
6
6
  "repository": {