* Dry-run a candidate result. Stages its edits provisionally, then runs the * conflict checks. Returns conflicts (empty = clean). Does NOT commit.
(node: TaskNode, result: WorkerResult)
| 102 | * conflict checks. Returns conflicts (empty = clean). Does NOT commit. |
| 103 | */ |
| 104 | async dryRunMerge(node: TaskNode, result: WorkerResult): Promise<ConflictRecord[]> { |
| 105 | const conflicts: ConflictRecord[] = []; |
| 106 | |
| 107 | for (const edit of result.fileEdits) { |
| 108 | // (a) same-file-write against another in-flight/committed node. |
| 109 | const prior = this.staged.get(edit.path); |
| 110 | if (prior && prior.taskId !== node.id) { |
| 111 | conflicts.push({ |
| 112 | taskA: prior.taskId, taskB: node.id, file: edit.path, |
| 113 | kind: 'same-file-write', resolution: 'serialized', |
| 114 | }); |
| 115 | } |
| 116 | |
| 117 | // (b) import-broken: did this edit REMOVE an export that a known importer needs? |
| 118 | const before = await this.currentContent(edit.path); |
| 119 | if (before && !edit.isNew) { |
| 120 | const removed = setDiff(extractExports(before), extractExports(edit.content)); |
| 121 | if (removed.size > 0) { |
| 122 | const broken = await this.findBrokenImporters(edit.path, removed); |
| 123 | for (const b of broken) { |
| 124 | conflicts.push({ |
| 125 | taskA: node.id, taskB: b.importerTask ?? '(committed)', file: b.importer, |
| 126 | kind: 'import-broken', resolution: 'manual-required', |
| 127 | }); |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | // Provisionally stage (so subsequent dry-runs this tick see it). If the |
| 134 | // scheduler decides the conflicts are fatal it will not call commit, and the |
| 135 | // stage is rolled back via unstage(). |
| 136 | for (const edit of result.fileEdits) { |
| 137 | this.staged.set(edit.path, { taskId: node.id, content: edit.content, isNew: edit.isNew }); |
| 138 | } |
| 139 | |
| 140 | return conflicts; |
| 141 | } |
| 142 | |
| 143 | /** |
| 144 | * Find files (committed or staged) that import one of `removedExports` from |
no test coverage detected