@izagood/avcs 0.1.0 → 0.1.1
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.
- package/README.md +28 -8
- package/dist/api/repo.d.ts +12 -42
- package/dist/api/repo.d.ts.map +1 -1
- package/dist/api/repo.js +40 -87
- package/dist/api/repo.js.map +1 -1
- package/dist/merge/merge3.d.ts +46 -0
- package/dist/merge/merge3.d.ts.map +1 -0
- package/dist/merge/merge3.js +214 -0
- package/dist/merge/merge3.js.map +1 -0
- package/dist/objects/types.d.ts +9 -10
- package/dist/objects/types.d.ts.map +1 -1
- package/dist/reducer/reducer.d.ts +21 -28
- package/dist/reducer/reducer.d.ts.map +1 -1
- package/dist/reducer/reducer.js +65 -101
- package/dist/reducer/reducer.js.map +1 -1
- package/package.json +1 -1
- package/dist/semantic/contract.d.ts +0 -32
- package/dist/semantic/contract.d.ts.map +0 -1
- package/dist/semantic/contract.js +0 -150
- package/dist/semantic/contract.js.map +0 -1
- package/dist/semantic/symbols.d.ts +0 -45
- package/dist/semantic/symbols.d.ts.map +0 -1
- package/dist/semantic/symbols.js +0 -323
- package/dist/semantic/symbols.js.map +0 -1
package/dist/objects/types.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface Blob extends BaseObject {
|
|
|
37
37
|
redactionOid?: string;
|
|
38
38
|
}
|
|
39
39
|
export type IntentKind = "feature" | "bugfix" | "refactor" | "formatting" | "generated";
|
|
40
|
-
/** A
|
|
40
|
+
/** A file/glob scope the intent is allowed to touch. */
|
|
41
41
|
export type ScopeRef = string;
|
|
42
42
|
/** Machine-checkable invariants. `constraints` (NL) is human prose; these are enforced. */
|
|
43
43
|
export type ConstraintKind = "forbid_public_api_break" | "forbid_behavior_change" | "require_tests";
|
|
@@ -65,25 +65,24 @@ export interface Session extends BaseObject {
|
|
|
65
65
|
toolCalls: string[];
|
|
66
66
|
startedAt: string;
|
|
67
67
|
}
|
|
68
|
-
export type OperationKind = "put_file" | "
|
|
68
|
+
export type OperationKind = "put_file" | "edit_file" | "delete_file" | "rename_file" | "note";
|
|
69
69
|
export interface OperationTarget {
|
|
70
70
|
/** What conceptual entity this op changes. */
|
|
71
|
-
entityKind: "file" | "
|
|
72
|
-
/** Stable entity id
|
|
71
|
+
entityKind: "file" | "contract" | "config" | "test";
|
|
72
|
+
/** Stable entity id — for files, the path. */
|
|
73
73
|
entityId: string;
|
|
74
74
|
}
|
|
75
75
|
export interface OperationBody {
|
|
76
76
|
kind: OperationKind;
|
|
77
|
-
/** put_file /
|
|
77
|
+
/** put_file / edit_file / rename_file destination path. */
|
|
78
78
|
path?: string;
|
|
79
79
|
/** rename_file source path. */
|
|
80
80
|
fromPath?: string;
|
|
81
|
-
/** put_file
|
|
81
|
+
/** put_file / edit_file new full file content (blob oid). */
|
|
82
82
|
blobOid?: string;
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
newName?: string;
|
|
83
|
+
/** edit_file: the blob this edit was derived from — the 3-way merge base.
|
|
84
|
+
* Empty/absent ⇒ base is the empty file. */
|
|
85
|
+
baseBlobOid?: string;
|
|
87
86
|
}
|
|
88
87
|
export interface Operation extends BaseObject {
|
|
89
88
|
type: "operation";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/objects/types.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,QAAQ,GACR,SAAS,GACT,WAAW,GACX,UAAU,GACV,UAAU,GACV,YAAY,GACZ,MAAM,GACN,QAAQ,GACR,OAAO,GACP,SAAS,GACT,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,WAAW,GACX,WAAW,GACX,UAAU,GACV,UAAU,CAAC;AAEf,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,SAAS,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAGD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AACxD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,IAAK,SAAQ,UAAU;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAGD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AACxF
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/objects/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Decision, Evidence, Intent, Operation, OperationStatus, Policy } from "../objects/types.ts";
|
|
2
|
+
import { type ConflictRegion } from "../merge/merge3.ts";
|
|
2
3
|
export interface ConflictOption {
|
|
3
4
|
opOid: string;
|
|
4
5
|
actor: string;
|
|
@@ -19,18 +20,6 @@ export interface Conflict {
|
|
|
19
20
|
/** Actor ids that own this scope and should make the call (Phase 5). */
|
|
20
21
|
requiredOwners?: string[];
|
|
21
22
|
}
|
|
22
|
-
/**
|
|
23
|
-
* A merge that is text-clean but meaning-broken: one op changed a public contract
|
|
24
|
-
* while another depends on the old one. Detected (and escalated) by the repo's
|
|
25
|
-
* semantic pass, not the core grouping.
|
|
26
|
-
*/
|
|
27
|
-
export interface SemanticConflict {
|
|
28
|
-
kind: "contract_break";
|
|
29
|
-
symbol: string;
|
|
30
|
-
breakingOp: string;
|
|
31
|
-
dependentOps: string[];
|
|
32
|
-
reason: string;
|
|
33
|
-
}
|
|
34
23
|
/** A contest the policy resolved by itself — recorded so auto-merges are auditable. */
|
|
35
24
|
export interface AutoDecision {
|
|
36
25
|
key: string;
|
|
@@ -47,15 +36,16 @@ export interface ReductionResult {
|
|
|
47
36
|
statuses: Map<string, OperationStatus>;
|
|
48
37
|
conflicts: Conflict[];
|
|
49
38
|
autoDecisions: AutoDecision[];
|
|
50
|
-
/**
|
|
51
|
-
|
|
39
|
+
/** Line-level text merge conflicts among concurrent edit_file ops, filled by the repo's
|
|
40
|
+
* post-reduce pass (detectFileConflicts). reduce() itself leaves this empty. */
|
|
41
|
+
fileConflicts: FileConflict[];
|
|
52
42
|
/** Frontier op ids: accepted ops that no other accepted op descends from. */
|
|
53
43
|
headOps: string[];
|
|
54
44
|
/**
|
|
55
|
-
* Content for blob oids synthesized during reduction (
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
45
|
+
* Content for blob oids synthesized during reduction (a 3-way text merge produces file
|
|
46
|
+
* content that is not any single stored blob). oid → content. The caller persists or
|
|
47
|
+
* writes these directly. Synthetic oids are content-derived, so the treeHash that
|
|
48
|
+
* references them stays deterministic.
|
|
59
49
|
*/
|
|
60
50
|
synthBlobs: Map<string, string>;
|
|
61
51
|
}
|
|
@@ -67,7 +57,7 @@ export interface ReduceInput {
|
|
|
67
57
|
policy: Policy;
|
|
68
58
|
/** Which statuses get projected into the tree. Default: accepted only. */
|
|
69
59
|
materializeStatuses?: OperationStatus[];
|
|
70
|
-
/** blob oid → content, for ops that need file text (
|
|
60
|
+
/** blob oid → content, for ops that need file text (edit_file 3-way merge). */
|
|
71
61
|
blobContent?: Map<string, string>;
|
|
72
62
|
/** actorId → bounded reliability nudge (Phase 5 trust learning). */
|
|
73
63
|
reliability?: Map<string, number>;
|
|
@@ -81,20 +71,23 @@ export interface ReduceInput {
|
|
|
81
71
|
*/
|
|
82
72
|
export declare function keysOf(op: Operation): string[];
|
|
83
73
|
export declare function conflictIdFor(key: string): string;
|
|
84
|
-
|
|
74
|
+
/** A file whose concurrent edits overlapped at the line level — a genuine text merge
|
|
75
|
+
* conflict. Language-neutral: detected purely by merge3 over the file's content. */
|
|
76
|
+
export interface FileConflict {
|
|
85
77
|
file: string;
|
|
86
78
|
ops: string[];
|
|
79
|
+
regions: ConflictRegion[];
|
|
87
80
|
}
|
|
88
81
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
82
|
+
* Detect line-level merge conflicts among CONCURRENT accepted edit_file ops on the same
|
|
83
|
+
* file. The reducer's grouping accepts all such ops (their disjoint hunks compose); this
|
|
84
|
+
* pass runs the authoritative N-way `merge3` over the file's concurrent frontier to find
|
|
85
|
+
* the ones whose hunks actually OVERLAP, so the repo can surface a Conflict / hold back.
|
|
86
|
+
*
|
|
87
|
+
* No language knowledge — merge3 compares lines. Ancestor relations (an edit built on a
|
|
88
|
+
* prior edit) are not concurrent and never flagged. Deterministic over canonical order.
|
|
96
89
|
*/
|
|
97
|
-
export declare function
|
|
90
|
+
export declare function detectFileConflicts(ops: Operation[], result: ReductionResult, blobContent: Map<string, string>): FileConflict[];
|
|
98
91
|
/** A single group's locally-decided statuses + the conflicts/autoDecisions it emitted. */
|
|
99
92
|
export interface PerKeyDecision {
|
|
100
93
|
local: Map<string, OperationStatus>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/reducer/reducer.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,SAAS,EACT,eAAe,EACf,MAAM,EACP,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/reducer/reducer.ts"],"names":[],"mappings":"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"}
|
package/dist/reducer/reducer.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// Phase-2 AST upgrade only swaps `keysOf` (the unit of contention) and `applyOp`.
|
|
12
12
|
import { sha256hex, canonicalize } from "../core/canonical.js";
|
|
13
13
|
import { evaluateOp } from "./policy.js";
|
|
14
|
-
import {
|
|
14
|
+
import { merge3 } from "../merge/merge3.js";
|
|
15
15
|
import { ownersFor } from "../policy/owners.js";
|
|
16
16
|
// Status precedence when an op belongs to several contended keys (rename touches
|
|
17
17
|
// two). The strictest verdict across its groups wins.
|
|
@@ -36,20 +36,13 @@ export function keysOf(op) {
|
|
|
36
36
|
const b = op.body;
|
|
37
37
|
switch (b.kind) {
|
|
38
38
|
case "put_file":
|
|
39
|
-
|
|
39
|
+
case "edit_file":
|
|
40
40
|
case "delete_file":
|
|
41
|
+
// Every file op contends on the file. Concurrent edit_file ops on the same file
|
|
42
|
+
// are 3-way text-merged at materialization; only overlapping line ranges conflict.
|
|
41
43
|
return [`file:${b.path ?? op.target.entityId}`];
|
|
42
44
|
case "rename_file":
|
|
43
45
|
return [`file:${b.fromPath ?? op.target.entityId}`, `file:${b.path ?? op.target.entityId}`];
|
|
44
|
-
case "set_symbol":
|
|
45
|
-
// Symbol-granular: two edits to different symbols of the same file auto-merge.
|
|
46
|
-
return [`symbol:${b.path}#${b.symbolName}`];
|
|
47
|
-
case "rename_symbol":
|
|
48
|
-
// Contends on both the old and new symbol names within the file.
|
|
49
|
-
return [`symbol:${b.path}#${b.symbolName}`, `symbol:${b.path}#${b.newName}`];
|
|
50
|
-
case "move_symbol":
|
|
51
|
-
// Contends on the symbol at its source and its destination.
|
|
52
|
-
return [`symbol:${b.fromPath}#${b.symbolName}`, `symbol:${b.path}#${b.symbolName}`];
|
|
53
46
|
case "note":
|
|
54
47
|
return [];
|
|
55
48
|
}
|
|
@@ -123,53 +116,42 @@ export function conflictIdFor(key) {
|
|
|
123
116
|
return `conflict_${sha256hex(key).slice(0, 24)}`;
|
|
124
117
|
}
|
|
125
118
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
119
|
+
* Detect line-level merge conflicts among CONCURRENT accepted edit_file ops on the same
|
|
120
|
+
* file. The reducer's grouping accepts all such ops (their disjoint hunks compose); this
|
|
121
|
+
* pass runs the authoritative N-way `merge3` over the file's concurrent frontier to find
|
|
122
|
+
* the ones whose hunks actually OVERLAP, so the repo can surface a Conflict / hold back.
|
|
123
|
+
*
|
|
124
|
+
* No language knowledge — merge3 compares lines. Ancestor relations (an edit built on a
|
|
125
|
+
* prior edit) are not concurrent and never flagged. Deterministic over canonical order.
|
|
133
126
|
*/
|
|
134
|
-
export function
|
|
127
|
+
export function detectFileConflicts(ops, result, blobContent) {
|
|
135
128
|
const anc = ancestry(ops);
|
|
136
|
-
const
|
|
137
|
-
const b = o.body;
|
|
138
|
-
if (b.kind === "put_file" || b.kind === "delete_file")
|
|
139
|
-
return b.path ?? o.target.entityId;
|
|
140
|
-
if (b.kind === "rename_file")
|
|
141
|
-
return b.fromPath ?? o.target.entityId;
|
|
142
|
-
if (b.kind === "set_symbol")
|
|
143
|
-
return b.path ?? null;
|
|
144
|
-
return null;
|
|
145
|
-
};
|
|
146
|
-
const isWhole = (o) => o.body.kind === "put_file" || o.body.kind === "delete_file" || o.body.kind === "rename_file";
|
|
129
|
+
const resolve = (oid) => (oid ? blobContent.get(oid) ?? "" : "");
|
|
147
130
|
const byFile = new Map();
|
|
148
131
|
for (const o of ops) {
|
|
132
|
+
if (o.body.kind !== "edit_file")
|
|
133
|
+
continue;
|
|
149
134
|
if (result.statuses.get(o.oid) !== "accepted")
|
|
150
135
|
continue;
|
|
151
|
-
const f =
|
|
152
|
-
|
|
153
|
-
(byFile.get(f) ?? byFile.set(f, []).get(f)).push(o);
|
|
136
|
+
const f = o.body.path ?? o.target.entityId;
|
|
137
|
+
(byFile.get(f) ?? byFile.set(f, []).get(f)).push(o);
|
|
154
138
|
}
|
|
155
139
|
const out = [];
|
|
156
140
|
for (const [file, fops] of byFile) {
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
160
|
-
continue;
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
if (involved.size)
|
|
172
|
-
out.push({ file, ops: [...involved].sort() });
|
|
141
|
+
// Concurrent frontier: ops not a causal ancestor of another edit on this file.
|
|
142
|
+
const frontier = fops.filter((o) => !fops.some((p) => p !== o && anc.get(p.oid)?.has(o.oid)));
|
|
143
|
+
if (frontier.length < 2)
|
|
144
|
+
continue; // linear chain ⇒ no concurrency ⇒ no conflict
|
|
145
|
+
const ordered = [...frontier].sort((a, b) => a.lamport - b.lamport || cmp(a.oid, b.oid));
|
|
146
|
+
// Common 3-way base: the content all variants were derived from. Use the shared
|
|
147
|
+
// baseBlobOid when they agree (the normal case); else the lexically-first for a
|
|
148
|
+
// deterministic, conservative comparison.
|
|
149
|
+
const baseOid = [...new Set(ordered.map((o) => o.body.baseBlobOid ?? ""))].sort()[0] ?? "";
|
|
150
|
+
const base = resolve(baseOid);
|
|
151
|
+
const variants = ordered.map((o) => resolve(o.body.blobOid));
|
|
152
|
+
const m = merge3(base, variants);
|
|
153
|
+
if (!m.clean)
|
|
154
|
+
out.push({ file, ops: ordered.map((o) => o.oid), regions: m.conflicts });
|
|
173
155
|
}
|
|
174
156
|
return out;
|
|
175
157
|
}
|
|
@@ -203,21 +185,18 @@ function pathsOf(op) {
|
|
|
203
185
|
const b = op.body;
|
|
204
186
|
switch (b.kind) {
|
|
205
187
|
case "put_file":
|
|
188
|
+
case "edit_file":
|
|
206
189
|
case "delete_file":
|
|
207
|
-
case "set_symbol":
|
|
208
|
-
case "rename_symbol":
|
|
209
190
|
return [b.path ?? op.target.entityId];
|
|
210
191
|
case "rename_file":
|
|
211
192
|
return [b.fromPath ?? op.target.entityId, b.path ?? op.target.entityId];
|
|
212
|
-
case "move_symbol":
|
|
213
|
-
return [b.fromPath ?? op.target.entityId, b.path ?? op.target.entityId];
|
|
214
193
|
case "note":
|
|
215
194
|
return [];
|
|
216
195
|
}
|
|
217
196
|
}
|
|
218
|
-
/** rename_file
|
|
197
|
+
/** rename_file reads a SOURCE path's live content, coupling two paths. */
|
|
219
198
|
function isCrossPath(op) {
|
|
220
|
-
return op.body.kind === "rename_file"
|
|
199
|
+
return op.body.kind === "rename_file";
|
|
221
200
|
}
|
|
222
201
|
/** Keep only the synth-blob entries the final tree actually references (drops the
|
|
223
202
|
* intermediate splices that get overwritten). Makes synthBlobs a pure function of the
|
|
@@ -340,7 +319,7 @@ export function snapshotReduce(input) {
|
|
|
340
319
|
if (keysOf(o).length === 0 && statuses.get(o.oid) === "proposed")
|
|
341
320
|
statuses.set(o.oid, "accepted");
|
|
342
321
|
const { tree, treeHash, headOps, synthBlobs } = materializeProjection(ops, statuses, anc, materializeStatuses, input.blobContent ?? new Map());
|
|
343
|
-
const result = { tree, treeHash, statuses, conflicts, autoDecisions,
|
|
322
|
+
const result = { tree, treeHash, statuses, conflicts, autoDecisions, fileConflicts: [], headOps, synthBlobs };
|
|
344
323
|
const stats = { groupsTotal: groups.size, groupsRecomputed: groups.size, groupsReused: 0, dirtyKeys: groups.size };
|
|
345
324
|
return { input, result, perKey, groupOrder, groupMembers, stats };
|
|
346
325
|
}
|
|
@@ -569,7 +548,7 @@ export function reduceIncremental(snap, next) {
|
|
|
569
548
|
dirtyPaths.add(p);
|
|
570
549
|
}
|
|
571
550
|
const { tree, treeHash, headOps, synthBlobs } = materializeIncremental(ops, statuses, anc, materializeStatuses, next.blobContent ?? new Map(), snap.result, dirtyPaths);
|
|
572
|
-
const result = { tree, treeHash, statuses, conflicts, autoDecisions,
|
|
551
|
+
const result = { tree, treeHash, statuses, conflicts, autoDecisions, fileConflicts: [], headOps, synthBlobs };
|
|
573
552
|
const stats = { groupsTotal: groups.size, groupsRecomputed: recomputed, groupsReused: reused, dirtyKeys: dirty.size };
|
|
574
553
|
return { input: next, result, perKey, groupOrder, groupMembers, stats };
|
|
575
554
|
}
|
|
@@ -595,7 +574,7 @@ export function serializeSnapshot(snap) {
|
|
|
595
574
|
statuses: mapToEntries(r.statuses),
|
|
596
575
|
conflicts: r.conflicts,
|
|
597
576
|
autoDecisions: r.autoDecisions,
|
|
598
|
-
|
|
577
|
+
fileConflicts: r.fileConflicts,
|
|
599
578
|
headOps: r.headOps,
|
|
600
579
|
synthBlobs: mapToEntries(r.synthBlobs),
|
|
601
580
|
},
|
|
@@ -626,7 +605,7 @@ export function deserializeSnapshot(raw) {
|
|
|
626
605
|
statuses: entriesToMap(r.statuses),
|
|
627
606
|
conflicts: r.conflicts,
|
|
628
607
|
autoDecisions: r.autoDecisions,
|
|
629
|
-
|
|
608
|
+
fileConflicts: r.fileConflicts,
|
|
630
609
|
headOps: r.headOps,
|
|
631
610
|
synthBlobs: entriesToMap(r.synthBlobs),
|
|
632
611
|
};
|
|
@@ -683,6 +662,16 @@ function decideGroup(key, groupOps, anc, verdicts, evalOf, policy, conflicts, au
|
|
|
683
662
|
out.set(o.oid, "rejected");
|
|
684
663
|
const viable = remaining.filter((o) => !blocked.includes(o));
|
|
685
664
|
const needsHuman = viable.some((o) => evalOf(o, inConflict).requiresHuman);
|
|
665
|
+
// Concurrent TEXT edits (all edit_file) auto-merge: accept all. Their disjoint line
|
|
666
|
+
// hunks compose deterministically (merge3); an actual line overlap is surfaced by
|
|
667
|
+
// detectFileConflicts over the full op set, NOT resolved by dropping a sibling here.
|
|
668
|
+
// (A winner-pick would silently lose the loser's non-overlapping changes.) When a
|
|
669
|
+
// human is required (e.g. declared API break) we still fall through to escalation.
|
|
670
|
+
if (viable.length > 1 && !needsHuman && viable.every((o) => o.body.kind === "edit_file")) {
|
|
671
|
+
for (const o of viable)
|
|
672
|
+
out.set(o.oid, "accepted");
|
|
673
|
+
return out;
|
|
674
|
+
}
|
|
686
675
|
const ranked = [...viable].sort((a, b) => {
|
|
687
676
|
const d = evalOf(b, inConflict).score - evalOf(a, inConflict).score;
|
|
688
677
|
if (d !== 0)
|
|
@@ -783,6 +772,23 @@ function applyOp(tree, op, blobContent, synthBlobs) {
|
|
|
783
772
|
if (b.path && b.blobOid)
|
|
784
773
|
tree.set(b.path, b.blobOid);
|
|
785
774
|
break;
|
|
775
|
+
case "edit_file": {
|
|
776
|
+
if (!b.path || !b.blobOid)
|
|
777
|
+
break;
|
|
778
|
+
const opNew = resolve(b.blobOid);
|
|
779
|
+
const opBase = b.baseBlobOid ? resolve(b.baseBlobOid) : "";
|
|
780
|
+
const currentOid = tree.get(b.path);
|
|
781
|
+
const current = currentOid !== undefined ? resolve(currentOid) : opBase;
|
|
782
|
+
// Apply this op's patch (opBase→opNew) onto the accumulated content. Disjoint
|
|
783
|
+
// line changes compose (order-independent); an overlap with a prior concurrent op
|
|
784
|
+
// keeps `current` (deterministic incumbent) — the overlap is reported separately
|
|
785
|
+
// by detectFileConflicts over the full op set. Language-neutral: pure text.
|
|
786
|
+
const m = merge3(opBase, [current, opNew], { onConflict: "first" });
|
|
787
|
+
const synthOid = `blob_${sha256hex(m.merged).slice(0, 32)}`;
|
|
788
|
+
synthBlobs.set(synthOid, m.merged);
|
|
789
|
+
tree.set(b.path, synthOid);
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
786
792
|
case "delete_file":
|
|
787
793
|
tree.delete(b.path ?? op.target.entityId);
|
|
788
794
|
break;
|
|
@@ -795,48 +801,6 @@ function applyOp(tree, op, blobContent, synthBlobs) {
|
|
|
795
801
|
}
|
|
796
802
|
}
|
|
797
803
|
break;
|
|
798
|
-
case "set_symbol": {
|
|
799
|
-
if (!b.path || !b.symbolName || !b.blobOid)
|
|
800
|
-
break;
|
|
801
|
-
const currentOid = tree.get(b.path);
|
|
802
|
-
const current = currentOid !== undefined ? resolve(currentOid) : "";
|
|
803
|
-
const merged = spliceSymbol(current, b.symbolName, resolve(b.blobOid));
|
|
804
|
-
const synthOid = `blob_${sha256hex(merged).slice(0, 32)}`;
|
|
805
|
-
synthBlobs.set(synthOid, merged);
|
|
806
|
-
tree.set(b.path, synthOid);
|
|
807
|
-
break;
|
|
808
|
-
}
|
|
809
|
-
case "rename_symbol": {
|
|
810
|
-
if (!b.path || !b.symbolName || !b.newName)
|
|
811
|
-
break;
|
|
812
|
-
const currentOid = tree.get(b.path);
|
|
813
|
-
if (currentOid === undefined)
|
|
814
|
-
break;
|
|
815
|
-
const renamed = renameSymbol(resolve(currentOid), b.symbolName, b.newName);
|
|
816
|
-
const synthOid = `blob_${sha256hex(renamed).slice(0, 32)}`;
|
|
817
|
-
synthBlobs.set(synthOid, renamed);
|
|
818
|
-
tree.set(b.path, synthOid);
|
|
819
|
-
break;
|
|
820
|
-
}
|
|
821
|
-
case "move_symbol": {
|
|
822
|
-
if (!b.fromPath || !b.path || !b.symbolName)
|
|
823
|
-
break;
|
|
824
|
-
const fromOid = tree.get(b.fromPath);
|
|
825
|
-
if (fromOid === undefined)
|
|
826
|
-
break;
|
|
827
|
-
const extracted = extractSymbol(resolve(fromOid), b.symbolName);
|
|
828
|
-
if (!extracted)
|
|
829
|
-
break;
|
|
830
|
-
const toContent = tree.get(b.path) !== undefined ? resolve(tree.get(b.path)) : "";
|
|
831
|
-
const newTo = spliceSymbol(toContent, b.symbolName, extracted.text);
|
|
832
|
-
const fromSynth = `blob_${sha256hex(extracted.rest).slice(0, 32)}`;
|
|
833
|
-
const toSynth = `blob_${sha256hex(newTo).slice(0, 32)}`;
|
|
834
|
-
synthBlobs.set(fromSynth, extracted.rest);
|
|
835
|
-
synthBlobs.set(toSynth, newTo);
|
|
836
|
-
tree.set(b.fromPath, fromSynth);
|
|
837
|
-
tree.set(b.path, toSynth);
|
|
838
|
-
break;
|
|
839
|
-
}
|
|
840
804
|
case "note":
|
|
841
805
|
break;
|
|
842
806
|
}
|