@izagood/avcs 0.29.0 → 0.30.0
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/dist/api/repo.d.ts +64 -2
- package/dist/api/repo.d.ts.map +1 -1
- package/dist/api/repo.js +236 -16
- package/dist/api/repo.js.map +1 -1
- package/dist/cli.js +29 -2
- package/dist/cli.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/merge/merge3.d.ts +12 -1
- package/dist/merge/merge3.d.ts.map +1 -1
- package/dist/merge/merge3.js +23 -1
- package/dist/merge/merge3.js.map +1 -1
- package/dist/reducer/aliases.d.ts +39 -0
- package/dist/reducer/aliases.d.ts.map +1 -0
- package/dist/reducer/aliases.js +112 -0
- package/dist/reducer/aliases.js.map +1 -0
- package/dist/reducer/policy.d.ts +1 -1
- package/dist/reducer/reducer.d.ts +7 -0
- package/dist/reducer/reducer.d.ts.map +1 -1
- package/dist/reducer/reducer.js +161 -19
- package/dist/reducer/reducer.js.map +1 -1
- package/package.json +1 -1
package/dist/merge/merge3.js
CHANGED
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
// Determinism: same (base, variants in canonical order) ⇒ identical output on every
|
|
11
11
|
// replica. The algorithm version is pinned into MATERIALIZER_VERSION so a different
|
|
12
12
|
// merge implementation cannot silently diverge a replica's tree.
|
|
13
|
-
|
|
13
|
+
// 0.2.0 — file identity (docs/19). The merge of a single file's TEXT is unchanged; what
|
|
14
|
+
// changed is which file a content op applies to: the reducer now resolves paths through the
|
|
15
|
+
// rename closure, so an op set containing `rename_file` can reduce to a different (and
|
|
16
|
+
// correct) tree than it did at 0.1.0. A rename-free op set is byte-identical either way.
|
|
17
|
+
// The stamp moves so a replica still on the older substrate cannot silently disagree about
|
|
18
|
+
// a rename-bearing one — `Checkpoint.materializerVersion` makes the mismatch explicit.
|
|
19
|
+
export const MERGE3_VERSION = "text3/0.2.0";
|
|
14
20
|
const MAX_LINES = 50_000; // beyond this, line-DP cost isn't worth it → atomic compare.
|
|
15
21
|
const isBinary = (s) => s.includes("\u0000");
|
|
16
22
|
const splitLines = (s) => s.split("\n");
|
|
@@ -155,6 +161,22 @@ function renderSpan(baseLines, start, end, members) {
|
|
|
155
161
|
out.push(baseLines[i]);
|
|
156
162
|
return joinLines(out);
|
|
157
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* How many lines of `a` survive into `b` — the length of their longest common
|
|
166
|
+
* subsequence of lines.
|
|
167
|
+
*
|
|
168
|
+
* Derived from `diffHunks` instead of adding a second algorithm: in that edit script every
|
|
169
|
+
* line of `a` is either matched (producing no hunk) or consumed inside some hunk's
|
|
170
|
+
* `[start, end)` span, so the LCS length is `a.length` minus the total span the hunks
|
|
171
|
+
* cover. Exposed for the capture path's rename similarity (docs/19 §3.1), and as
|
|
172
|
+
* language-blind as the rest of this module — it compares lines and nothing else.
|
|
173
|
+
*/
|
|
174
|
+
export function lcsLineLength(a, b) {
|
|
175
|
+
let consumed = 0;
|
|
176
|
+
for (const h of diffHunks(a, b))
|
|
177
|
+
consumed += h.end - h.start;
|
|
178
|
+
return a.length - consumed;
|
|
179
|
+
}
|
|
158
180
|
/**
|
|
159
181
|
* Line-level diff (LCS) → maximal changed segments. Each Hunk replaces base[start:end)
|
|
160
182
|
* with `lines`. Unchanged lines produce no hunk. Deterministic.
|
package/dist/merge/merge3.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge3.js","sourceRoot":"","sources":["../../src/merge/merge3.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"merge3.js","sourceRoot":"","sources":["../../src/merge/merge3.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Operation } from "../objects/types.ts";
|
|
2
|
+
export interface AliasMap {
|
|
3
|
+
/** Original path → final path, chased through the whole rename chain. */
|
|
4
|
+
readonly final: ReadonlyMap<string, string>;
|
|
5
|
+
/** Paths no single destination can be derived for (concurrent multi-destination
|
|
6
|
+
* renames, or a rename cycle). These are NOT moved — conflict detection reports
|
|
7
|
+
* them and a human decides. */
|
|
8
|
+
readonly contested: ReadonlySet<string>;
|
|
9
|
+
/** rename op oid → the `fromPath` that op moved. Input to the causal condition in
|
|
10
|
+
* {@link resolvePath}. */
|
|
11
|
+
readonly byOp: ReadonlyMap<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build the path alias map from a set of `rename_file` operations.
|
|
15
|
+
*
|
|
16
|
+
* `renames` should be the ops actually projected into the tree (accepted, or whatever
|
|
17
|
+
* `materializeStatuses` admits). `isConcurrent(a, b)` answers whether two op oids are
|
|
18
|
+
* causally unrelated.
|
|
19
|
+
*
|
|
20
|
+
* Two renames moving the SAME source to DIFFERENT destinations are only a genuine
|
|
21
|
+
* contest when they are concurrent; when they are causally ordered they are a chain the
|
|
22
|
+
* author walked deliberately, and the latest (canonical (lamport, oid)) hop wins. A
|
|
23
|
+
* contested source is left where it is and reported, never moved somewhere arbitrary —
|
|
24
|
+
* silent data loss is the one outcome worse than a conflict.
|
|
25
|
+
*
|
|
26
|
+
* Every iteration order here is sorted rather than insertion-derived, so the returned
|
|
27
|
+
* maps are byte-identical no matter what order the caller enumerated the renames in.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildAliasMap(renames: Operation[], isConcurrent: (a: string, b: string) => boolean): AliasMap;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the path an op should actually be applied at.
|
|
32
|
+
*
|
|
33
|
+
* The causal condition is what keeps this from misrouting NEW files: an op that causally
|
|
34
|
+
* descends from the rename was written by an author who already saw the moved world, so
|
|
35
|
+
* the path it names is the path it means. Only an op that is concurrent with (or precedes)
|
|
36
|
+
* the rename is talking about the pre-move world and needs the alias.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolvePath(aliases: AliasMap, path: string, opOid: string, descendsFromRename: (opOid: string, renameOid: string) => boolean): string;
|
|
39
|
+
//# sourceMappingURL=aliases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../../src/reducer/aliases.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,QAAQ;IACvB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C;;oCAEgC;IAChC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACxC;+BAC2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAQD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,EAAE,EACpB,YAAY,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,GAC9C,QAAQ,CAwDV;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,GAChE,MAAM,CAOR"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Path aliases: the rename closure that restores rename × edit commutativity (docs/19 §3.2).
|
|
2
|
+
//
|
|
3
|
+
// A file's identity in this core is its PATH (`OperationTarget.entityId`). That makes a
|
|
4
|
+
// move and a concurrent edit of the same file look like two unrelated writes to two
|
|
5
|
+
// unrelated paths, and which of the two the reducer sees first decides whether the tree
|
|
6
|
+
// comes out right — correctness left to a lamport coincidence.
|
|
7
|
+
//
|
|
8
|
+
// The fix is to stop applying a content op at the path its author NAMED and apply it at
|
|
9
|
+
// the path the file actually ended up at. This module computes that mapping — "original
|
|
10
|
+
// path → final path" — from the accepted `rename_file` closure alone. It is a pure
|
|
11
|
+
// function of (rename set, canonical order, causal relation), all three of which are
|
|
12
|
+
// already deterministic, so the mapping is deterministic too and Pass B only reads it.
|
|
13
|
+
//
|
|
14
|
+
// Deliberately NOT here: any notion of identity stored on an operation. That is a later
|
|
15
|
+
// stage (docs/19 §3.3) and needs a schema field; this stage DERIVES identity from the
|
|
16
|
+
// rename graph and needs none.
|
|
17
|
+
const cmp = (a, b) => {
|
|
18
|
+
const x = a ?? "";
|
|
19
|
+
const y = b ?? "";
|
|
20
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Build the path alias map from a set of `rename_file` operations.
|
|
24
|
+
*
|
|
25
|
+
* `renames` should be the ops actually projected into the tree (accepted, or whatever
|
|
26
|
+
* `materializeStatuses` admits). `isConcurrent(a, b)` answers whether two op oids are
|
|
27
|
+
* causally unrelated.
|
|
28
|
+
*
|
|
29
|
+
* Two renames moving the SAME source to DIFFERENT destinations are only a genuine
|
|
30
|
+
* contest when they are concurrent; when they are causally ordered they are a chain the
|
|
31
|
+
* author walked deliberately, and the latest (canonical (lamport, oid)) hop wins. A
|
|
32
|
+
* contested source is left where it is and reported, never moved somewhere arbitrary —
|
|
33
|
+
* silent data loss is the one outcome worse than a conflict.
|
|
34
|
+
*
|
|
35
|
+
* Every iteration order here is sorted rather than insertion-derived, so the returned
|
|
36
|
+
* maps are byte-identical no matter what order the caller enumerated the renames in.
|
|
37
|
+
*/
|
|
38
|
+
export function buildAliasMap(renames, isConcurrent) {
|
|
39
|
+
const direct = new Map();
|
|
40
|
+
const byOp = new Map();
|
|
41
|
+
// Canonical order first: the "latest hop wins" tie-break below must not depend on the
|
|
42
|
+
// order the caller happened to enumerate.
|
|
43
|
+
const ordered = [...renames].sort((a, b) => a.lamport - b.lamport || cmp(a.oid, b.oid));
|
|
44
|
+
for (const r of ordered) {
|
|
45
|
+
const from = r.body.fromPath;
|
|
46
|
+
const to = r.body.path;
|
|
47
|
+
if (!from || !to || from === to)
|
|
48
|
+
continue;
|
|
49
|
+
const oid = r.oid;
|
|
50
|
+
byOp.set(oid, from);
|
|
51
|
+
if (!direct.has(from))
|
|
52
|
+
direct.set(from, []);
|
|
53
|
+
direct.get(from).push({ to, oid, lamport: r.lamport });
|
|
54
|
+
}
|
|
55
|
+
const contested = new Set();
|
|
56
|
+
const edge = new Map(); // from → to, contest-free hops only
|
|
57
|
+
for (const from of [...direct.keys()].sort(cmp)) {
|
|
58
|
+
const hops = direct.get(from);
|
|
59
|
+
const destinations = new Set(hops.map((h) => h.to));
|
|
60
|
+
if (destinations.size > 1) {
|
|
61
|
+
// More than one destination for one source. Concurrent ⇒ a real contest; causally
|
|
62
|
+
// ordered ⇒ a chain, and the last hop is the answer.
|
|
63
|
+
const contest = hops.some((a, i) => hops.slice(i + 1).some((b) => a.to !== b.to && isConcurrent(a.oid, b.oid)));
|
|
64
|
+
if (contest) {
|
|
65
|
+
contested.add(from);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
edge.set(from, hops[hops.length - 1].to);
|
|
70
|
+
}
|
|
71
|
+
// Chain closure. A cycle (only reachable from concurrent renames, e.g. P→Q ∥ Q→P) has
|
|
72
|
+
// no final path by construction — contest every path it touches.
|
|
73
|
+
const final = new Map();
|
|
74
|
+
for (const start of [...edge.keys()].sort(cmp)) {
|
|
75
|
+
const seen = new Set([start]);
|
|
76
|
+
let cur = start;
|
|
77
|
+
let next = edge.get(cur);
|
|
78
|
+
while (next !== undefined && !seen.has(next)) {
|
|
79
|
+
seen.add(next);
|
|
80
|
+
cur = next;
|
|
81
|
+
next = edge.get(cur);
|
|
82
|
+
}
|
|
83
|
+
if (next !== undefined) {
|
|
84
|
+
for (const p of seen)
|
|
85
|
+
contested.add(p); // cycle
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
final.set(start, cur);
|
|
89
|
+
}
|
|
90
|
+
for (const p of contested)
|
|
91
|
+
final.delete(p);
|
|
92
|
+
return { final, contested, byOp };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Resolve the path an op should actually be applied at.
|
|
96
|
+
*
|
|
97
|
+
* The causal condition is what keeps this from misrouting NEW files: an op that causally
|
|
98
|
+
* descends from the rename was written by an author who already saw the moved world, so
|
|
99
|
+
* the path it names is the path it means. Only an op that is concurrent with (or precedes)
|
|
100
|
+
* the rename is talking about the pre-move world and needs the alias.
|
|
101
|
+
*/
|
|
102
|
+
export function resolvePath(aliases, path, opOid, descendsFromRename) {
|
|
103
|
+
const to = aliases.final.get(path);
|
|
104
|
+
if (to === undefined)
|
|
105
|
+
return path;
|
|
106
|
+
for (const [renameOid, from] of aliases.byOp) {
|
|
107
|
+
if (from === path && descendsFromRename(opOid, renameOid))
|
|
108
|
+
return path;
|
|
109
|
+
}
|
|
110
|
+
return to;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=aliases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aliases.js","sourceRoot":"","sources":["../../src/reducer/aliases.ts"],"names":[],"mappings":"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"}
|
package/dist/reducer/policy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Evidence, Operation, Policy } from "../objects/types.ts";
|
|
2
|
-
export declare const MATERIALIZER_VERSION = "avcs-text3/0.
|
|
2
|
+
export declare const MATERIALIZER_VERSION = "avcs-text3/0.2.0";
|
|
3
3
|
/** A sane built-in policy used when a repo has not authored its own. */
|
|
4
4
|
export declare function defaultPolicy(): Policy;
|
|
5
5
|
export interface OpEvaluation {
|
|
@@ -87,6 +87,13 @@ export interface FileConflict {
|
|
|
87
87
|
*
|
|
88
88
|
* No language knowledge — merge3 compares lines. Ancestor relations (an edit built on a
|
|
89
89
|
* prior edit) are not concurrent and never flagged. Deterministic over canonical order.
|
|
90
|
+
*
|
|
91
|
+
* "The same file" means the same ALIAS-RESOLVED path, not the same declared one (docs/19
|
|
92
|
+
* §3.2). Two concurrent edits can reach one file by two names — one naming the path from
|
|
93
|
+
* before a move, the other naming it after — and bucketing them by whichever name each op
|
|
94
|
+
* happened to use would put them in separate buckets, never compare them, and let the
|
|
95
|
+
* loser's overlapping change disappear without a word. With no renames in the op set,
|
|
96
|
+
* resolution is the identity and the buckets are exactly the declared paths, as before.
|
|
90
97
|
*/
|
|
91
98
|
export declare function detectFileConflicts(ops: Operation[], result: ReductionResult, blobContent: Map<string, Buffer>): FileConflict[];
|
|
92
99
|
/** A single group's locally-decided statuses + the conflicts/autoDecisions it emitted. */
|
|
@@ -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,6 +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 { buildAliasMap, resolvePath } from "./aliases.js";
|
|
14
15
|
import { merge3 } from "../merge/merge3.js";
|
|
15
16
|
import { ownersFor } from "../policy/owners.js";
|
|
16
17
|
import { isBinary } from "../core/bytes.js";
|
|
@@ -125,9 +126,19 @@ export function conflictIdFor(key) {
|
|
|
125
126
|
*
|
|
126
127
|
* No language knowledge — merge3 compares lines. Ancestor relations (an edit built on a
|
|
127
128
|
* prior edit) are not concurrent and never flagged. Deterministic over canonical order.
|
|
129
|
+
*
|
|
130
|
+
* "The same file" means the same ALIAS-RESOLVED path, not the same declared one (docs/19
|
|
131
|
+
* §3.2). Two concurrent edits can reach one file by two names — one naming the path from
|
|
132
|
+
* before a move, the other naming it after — and bucketing them by whichever name each op
|
|
133
|
+
* happened to use would put them in separate buckets, never compare them, and let the
|
|
134
|
+
* loser's overlapping change disappear without a word. With no renames in the op set,
|
|
135
|
+
* resolution is the identity and the buckets are exactly the declared paths, as before.
|
|
128
136
|
*/
|
|
129
137
|
export function detectFileConflicts(ops, result, blobContent) {
|
|
130
138
|
const anc = ancestry(ops);
|
|
139
|
+
// Built from the same status filter the bucket loop below uses, so the aliases describe
|
|
140
|
+
// exactly the ops being bucketed.
|
|
141
|
+
const alias = aliasCtxFor(ops.filter((o) => result.statuses.get(o.oid) === "accepted"), anc);
|
|
131
142
|
const resolve = (oid) => (oid ? blobContent.get(oid) ?? Buffer.alloc(0) : Buffer.alloc(0));
|
|
132
143
|
const byFile = new Map();
|
|
133
144
|
for (const o of ops) {
|
|
@@ -135,7 +146,7 @@ export function detectFileConflicts(ops, result, blobContent) {
|
|
|
135
146
|
continue;
|
|
136
147
|
if (result.statuses.get(o.oid) !== "accepted")
|
|
137
148
|
continue;
|
|
138
|
-
const f = o.body.path ?? o.target.entityId;
|
|
149
|
+
const f = resolvedPath(o, o.body.path ?? o.target.entityId, alias);
|
|
139
150
|
(byFile.get(f) ?? byFile.set(f, []).get(f)).push(o);
|
|
140
151
|
}
|
|
141
152
|
const out = [];
|
|
@@ -222,6 +233,23 @@ function pathsOf(op) {
|
|
|
222
233
|
function isCrossPath(op) {
|
|
223
234
|
return op.body.kind === "rename_file";
|
|
224
235
|
}
|
|
236
|
+
/** Ops that carry the file's WHOLE content (or its absence) for one path. */
|
|
237
|
+
const CONTENT_KINDS = new Set(["put_file", "edit_file", "delete_file"]);
|
|
238
|
+
/** Build the alias context for a set of PROJECTED ops (docs/19 §3.2 Pass A). Only the
|
|
239
|
+
* renames that actually reach the tree may move anything, so the map is derived from
|
|
240
|
+
* the projected set — exactly the set `applyOp` will replay. */
|
|
241
|
+
function aliasCtxFor(projected, anc) {
|
|
242
|
+
const renames = projected.filter((o) => o.body.kind === "rename_file");
|
|
243
|
+
const descendsFromRename = (opOid, renameOid) => anc.get(opOid)?.has(renameOid) ?? false;
|
|
244
|
+
const isConcurrent = (a, b) => !descendsFromRename(a, b) && !descendsFromRename(b, a);
|
|
245
|
+
return { aliases: buildAliasMap(renames, isConcurrent), descendsFromRename };
|
|
246
|
+
}
|
|
247
|
+
/** The path an op actually writes, after the rename closure. */
|
|
248
|
+
function resolvedPath(op, declared, alias) {
|
|
249
|
+
if (!alias)
|
|
250
|
+
return declared;
|
|
251
|
+
return resolvePath(alias.aliases, declared, op.oid, alias.descendsFromRename);
|
|
252
|
+
}
|
|
225
253
|
/** Keep only the synth-blob entries the final tree actually references (drops the
|
|
226
254
|
* intermediate splices that get overwritten). Makes synthBlobs a pure function of the
|
|
227
255
|
* final tree — which is what lets the incremental path reuse base entries exactly. */
|
|
@@ -250,10 +278,11 @@ function frontier(ops, statuses, anc) {
|
|
|
250
278
|
function materializeProjection(ops, statuses, anc, materializeStatuses, blobContent) {
|
|
251
279
|
const projected = ops.filter((o) => materializeStatuses.has(statuses.get(o.oid)));
|
|
252
280
|
const ordered = kahnOrder(projected, anc);
|
|
281
|
+
const alias = aliasCtxFor(projected, anc);
|
|
253
282
|
const tree = new Map();
|
|
254
283
|
const synthBlobs = new Map();
|
|
255
284
|
for (const op of ordered)
|
|
256
|
-
applyOp(tree, op, blobContent, synthBlobs);
|
|
285
|
+
applyOp(tree, op, blobContent, synthBlobs, alias);
|
|
257
286
|
return { tree, treeHash: treeHashOf(tree), headOps: frontier(ops, statuses, anc), synthBlobs: pruneSynth(tree, synthBlobs) };
|
|
258
287
|
}
|
|
259
288
|
/**
|
|
@@ -269,12 +298,20 @@ function materializeProjection(ops, statuses, anc, materializeStatuses, blobCont
|
|
|
269
298
|
function materializeIncremental(ops, statuses, anc, materializeStatuses, blobContent, base, dirtyPaths) {
|
|
270
299
|
const projected = ops.filter((o) => materializeStatuses.has(statuses.get(o.oid)));
|
|
271
300
|
const ordered = kahnOrder(projected, anc);
|
|
272
|
-
//
|
|
301
|
+
// The alias map is a function of the WHOLE projected rename set, never of the dirty
|
|
302
|
+
// subset — otherwise the warm path would route ops differently from a cold reduce.
|
|
303
|
+
const alias = aliasCtxFor(projected, anc);
|
|
304
|
+
// Replay only dirty-touching ops, in the SAME global order, into a fresh tree. `pathsOf`
|
|
305
|
+
// is the DECLARED path, while `applyOp` writes at the alias-RESOLVED one; the two agree
|
|
306
|
+
// only because `dirtyPaths` marks both ends of every projected rename (see the caller's
|
|
307
|
+
// cross-path rule). If that ever narrows, an op could be replayed while the path it
|
|
308
|
+
// actually writes keeps a stale base entry, or be skipped while its resolved path was
|
|
309
|
+
// dropped as dirty. `AVCS_VERIFY_INCREMENTAL=1` and the C22 cases gate it.
|
|
273
310
|
const replayTree = new Map();
|
|
274
311
|
const replaySynth = new Map();
|
|
275
312
|
for (const op of ordered) {
|
|
276
313
|
if (pathsOf(op).some((p) => dirtyPaths.has(p)))
|
|
277
|
-
applyOp(replayTree, op, blobContent, replaySynth);
|
|
314
|
+
applyOp(replayTree, op, blobContent, replaySynth, alias);
|
|
278
315
|
}
|
|
279
316
|
// Final tree = clean base paths (not dirty) + replayed dirty paths.
|
|
280
317
|
const tree = new Map();
|
|
@@ -567,6 +604,16 @@ export function reduceIncremental(snap, next) {
|
|
|
567
604
|
if (projectedNow(oid) !== projectedBase(oid) || ancestryExtended(oid))
|
|
568
605
|
for (const p of pathsOf(o))
|
|
569
606
|
dirtyPaths.add(p);
|
|
607
|
+
// Every projected rename dirties BOTH its ends, unconditionally — even when nothing
|
|
608
|
+
// about the rename itself changed. This is what makes path aliases safe on the warm
|
|
609
|
+
// path (docs/19 §3.2, §6 R2): the alias map is a function of the whole op set, so an
|
|
610
|
+
// arriving rename changes where PRE-EXISTING content ops write, and it can invalidate
|
|
611
|
+
// a cached entry at a path NOTHING in the delta mentions — e.g. a second move of an
|
|
612
|
+
// already-moved source has to vacate the first destination. Since every aliased path
|
|
613
|
+
// is by construction one end of some projected rename, dirtying both ends covers every
|
|
614
|
+
// path whose value the alias closure can shift. Narrowing this rule breaks warm/cold
|
|
615
|
+
// agreement; `AVCS_VERIFY_INCREMENTAL=1`, incremental-equivalence and the C22 cases in
|
|
616
|
+
// test/rename-incremental.test.ts are what catch it.
|
|
570
617
|
else if (projectedNow(oid) && isCrossPath(o))
|
|
571
618
|
for (const p of pathsOf(o))
|
|
572
619
|
dirtyPaths.add(p);
|
|
@@ -637,18 +684,81 @@ export function deserializeSnapshot(raw) {
|
|
|
637
684
|
const stats = { groupsTotal: perKey.size, groupsRecomputed: 0, groupsReused: perKey.size, dirtyKeys: 0 };
|
|
638
685
|
return { input, result, perKey, groupOrder: s.groupOrder, groupMembers: entriesToMap(s.groupMembers), stats };
|
|
639
686
|
}
|
|
687
|
+
/**
|
|
688
|
+
* Is `o`'s tree effect fully carried by some later op in the same group, so that dropping
|
|
689
|
+
* `o` from the projection loses nothing?
|
|
690
|
+
*
|
|
691
|
+
* A content op (`put_file`/`edit_file`/`delete_file`) states the file's whole content for
|
|
692
|
+
* one path, so a causally later content op on the same key does subsume an earlier one.
|
|
693
|
+
* Two things do NOT:
|
|
694
|
+
*
|
|
695
|
+
* - A `rename_file` carries no content. It neither subsumes a content op nor is
|
|
696
|
+
* subsumed by one; a move followed by anything still has to be replayed or the file
|
|
697
|
+
* it moved never reaches the destination.
|
|
698
|
+
* - A content op on a path a rename VACATED in between. `put_file(P)` after
|
|
699
|
+
* `rename(P→Q)` is a different file that happens to reuse the name, so it cannot
|
|
700
|
+
* stand in for the `put_file(P)` whose content went to Q.
|
|
701
|
+
*
|
|
702
|
+
* Before path aliases existed this distinction was invisible, because a group's covered
|
|
703
|
+
* ops were dropped wholesale and a rename found nothing to move — which is why a plain
|
|
704
|
+
* create-then-move materialized an empty tree.
|
|
705
|
+
*/
|
|
706
|
+
function subsumedInGroup(o, groupOps, anc) {
|
|
707
|
+
if (!CONTENT_KINDS.has(o.body.kind))
|
|
708
|
+
return false;
|
|
709
|
+
const oid = o.oid;
|
|
710
|
+
const descendsFrom = (x, id) => anc.get(x.oid)?.has(id) ?? false;
|
|
711
|
+
for (const later of groupOps) {
|
|
712
|
+
if (later === o || !descendsFrom(later, oid))
|
|
713
|
+
continue;
|
|
714
|
+
if (!CONTENT_KINDS.has(later.body.kind))
|
|
715
|
+
continue;
|
|
716
|
+
const separated = groupOps.some((z) => z.body.kind === "rename_file" && descendsFrom(z, oid) && descendsFrom(later, z.oid));
|
|
717
|
+
if (!separated)
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Does this contended group's frontier consist of a move plus concurrent edits of the
|
|
724
|
+
* file being moved — the combination Pass B composes rather than contests?
|
|
725
|
+
*
|
|
726
|
+
* Requires the group key to be the rename's SOURCE. When the key is the DESTINATION the
|
|
727
|
+
* ops are genuinely fighting over who occupies that path (`rename(A→C)` ∥ `edit(C)`),
|
|
728
|
+
* which the alias map cannot compose and a human must settle. Renames present must all
|
|
729
|
+
* agree on the destination, so concurrent multi-destination moves (docs/19 C13) stay a
|
|
730
|
+
* conflict. And only `edit_file` composes: a concurrent `put_file` has no merge base
|
|
731
|
+
* (docs/15 §3), while `delete_file` ∥ rename keeps whatever it meant before (docs/19 R5).
|
|
732
|
+
*/
|
|
733
|
+
function composesWithRename(key, viable) {
|
|
734
|
+
const path = key.startsWith("file:") ? key.slice("file:".length) : undefined;
|
|
735
|
+
if (path === undefined)
|
|
736
|
+
return false;
|
|
737
|
+
const renames = viable.filter((o) => o.body.kind === "rename_file");
|
|
738
|
+
if (renames.length === 0)
|
|
739
|
+
return false;
|
|
740
|
+
if (!renames.every((r) => (r.body.fromPath ?? r.target.entityId) === path))
|
|
741
|
+
return false;
|
|
742
|
+
if (new Set(renames.map((r) => r.body.path)).size !== 1)
|
|
743
|
+
return false;
|
|
744
|
+
return viable.every((o) => o.body.kind === "rename_file" || (o.body.kind === "edit_file" && (o.body.path ?? o.target.entityId) === path));
|
|
745
|
+
}
|
|
640
746
|
function decideGroup(key, groupOps, anc, verdicts, evalOf, policy, conflicts, autoDecisions) {
|
|
641
747
|
const out = new Map();
|
|
642
|
-
// Frontier of this group: ops not an ancestor of another group member.
|
|
748
|
+
// Frontier of this group: ops not an ancestor of another group member. Only the frontier
|
|
749
|
+
// can contend — an op some later op was built on top of is history, not a competitor.
|
|
643
750
|
const heads = groupOps.filter((o) => {
|
|
644
751
|
for (const other of groupOps)
|
|
645
752
|
if (other !== o && anc.get(other.oid)?.has(o.oid))
|
|
646
753
|
return false;
|
|
647
754
|
return true;
|
|
648
755
|
});
|
|
756
|
+
// Being off the frontier is not the same as being redundant. A covered op is dropped
|
|
757
|
+
// from the projection ("superseded") only when a later op actually SUBSUMES its effect;
|
|
758
|
+
// otherwise it still has to be replayed or its contribution to the tree is destroyed.
|
|
649
759
|
for (const o of groupOps)
|
|
650
760
|
if (!heads.includes(o))
|
|
651
|
-
out.set(o.oid, "superseded");
|
|
761
|
+
out.set(o.oid, subsumedInGroup(o, groupOps, anc) ? "superseded" : "accepted");
|
|
652
762
|
// 1) Honor explicit human decisions first (H1) — globally, regardless of grouping.
|
|
653
763
|
const forcedAccept = heads.filter((o) => verdicts.get(o.oid) === "accept");
|
|
654
764
|
const forcedReject = heads.filter((o) => verdicts.get(o.oid) === "reject");
|
|
@@ -696,6 +806,15 @@ function decideGroup(key, groupOps, anc, verdicts, evalOf, policy, conflicts, au
|
|
|
696
806
|
out.set(o.oid, "accepted");
|
|
697
807
|
return out;
|
|
698
808
|
}
|
|
809
|
+
// A move and a concurrent edit of the file being moved also compose (docs/19 §3.2):
|
|
810
|
+
// Pass B routes the edit to the rename's destination, so there is nothing to choose
|
|
811
|
+
// between — the two changes are independent and both survive. See `composesWithRename`
|
|
812
|
+
// for which combinations this deliberately does NOT cover.
|
|
813
|
+
if (viable.length > 1 && !needsHuman && composesWithRename(key, viable)) {
|
|
814
|
+
for (const o of viable)
|
|
815
|
+
out.set(o.oid, "accepted");
|
|
816
|
+
return out;
|
|
817
|
+
}
|
|
699
818
|
const ranked = [...viable].sort((a, b) => {
|
|
700
819
|
const d = evalOf(b, inConflict).score - evalOf(a, inConflict).score;
|
|
701
820
|
if (d !== 0)
|
|
@@ -788,20 +907,31 @@ function kahnOrder(ops, anc) {
|
|
|
788
907
|
}
|
|
789
908
|
return order;
|
|
790
909
|
}
|
|
791
|
-
|
|
910
|
+
/**
|
|
911
|
+
* Apply one projected op to the tree.
|
|
912
|
+
*
|
|
913
|
+
* Every content op is applied at its ALIAS-RESOLVED path, not at the path its body names
|
|
914
|
+
* (docs/19 §3.2 Pass B). That is what makes `rename_file` and `edit_file` commute: the
|
|
915
|
+
* edit lands where the file actually lives regardless of which of the two the canonical
|
|
916
|
+
* order put first. With no renames in the op set the alias map is empty, resolution is
|
|
917
|
+
* the identity, and this function behaves exactly as it did before.
|
|
918
|
+
*/
|
|
919
|
+
function applyOp(tree, op, blobContent, synthBlobs, alias) {
|
|
792
920
|
const b = op.body;
|
|
793
921
|
const resolve = (oid) => synthBlobs.get(oid) ?? blobContent.get(oid) ?? Buffer.alloc(0);
|
|
922
|
+
const at = (declared) => resolvedPath(op, declared, alias);
|
|
794
923
|
switch (b.kind) {
|
|
795
924
|
case "put_file":
|
|
796
925
|
if (b.path && b.blobOid)
|
|
797
|
-
tree.set(b.path, b.blobOid);
|
|
926
|
+
tree.set(at(b.path), b.blobOid);
|
|
798
927
|
break;
|
|
799
928
|
case "edit_file": {
|
|
800
929
|
if (!b.path || !b.blobOid)
|
|
801
930
|
break;
|
|
931
|
+
const path = at(b.path);
|
|
802
932
|
const opNew = resolve(b.blobOid);
|
|
803
933
|
const opBase = b.baseBlobOid ? resolve(b.baseBlobOid) : Buffer.alloc(0);
|
|
804
|
-
const currentOid = tree.get(
|
|
934
|
+
const currentOid = tree.get(path);
|
|
805
935
|
const current = currentOid !== undefined ? resolve(currentOid) : opBase;
|
|
806
936
|
// Binary route: a NUL byte means line-merge is meaningless. Skip merge3 and keep a
|
|
807
937
|
// deterministic incumbent — leave the existing tree entry (currentOid) untouched if
|
|
@@ -811,7 +941,7 @@ function applyOp(tree, op, blobContent, synthBlobs) {
|
|
|
811
941
|
break; // incumbent stays; tree unchanged
|
|
812
942
|
const synthOid = `blob_${sha256hex(opNew).slice(0, 32)}`;
|
|
813
943
|
synthBlobs.set(synthOid, opNew);
|
|
814
|
-
tree.set(
|
|
944
|
+
tree.set(path, synthOid);
|
|
815
945
|
break;
|
|
816
946
|
}
|
|
817
947
|
// Apply this op's patch (opBase→opNew) onto the accumulated content. Disjoint
|
|
@@ -822,21 +952,33 @@ function applyOp(tree, op, blobContent, synthBlobs) {
|
|
|
822
952
|
const mergedBuf = Buffer.from(m.merged, "utf8");
|
|
823
953
|
const synthOid = `blob_${sha256hex(mergedBuf).slice(0, 32)}`;
|
|
824
954
|
synthBlobs.set(synthOid, mergedBuf);
|
|
825
|
-
tree.set(
|
|
955
|
+
tree.set(path, synthOid);
|
|
826
956
|
break;
|
|
827
957
|
}
|
|
828
958
|
case "delete_file":
|
|
829
|
-
tree.delete(b.path ?? op.target.entityId);
|
|
959
|
+
tree.delete(at(b.path ?? op.target.entityId));
|
|
830
960
|
break;
|
|
831
|
-
case "rename_file":
|
|
832
|
-
if (b.fromPath
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
961
|
+
case "rename_file": {
|
|
962
|
+
if (!b.fromPath || !b.path)
|
|
963
|
+
break;
|
|
964
|
+
// A rename the alias map resolved has nothing left to move: every content op that
|
|
965
|
+
// predates or is concurrent with it was already routed to the destination, so the
|
|
966
|
+
// source path was never written. This replaces the old "move whatever happens to be
|
|
967
|
+
// at fromPath right now", which is precisely where the order dependence lived — the
|
|
968
|
+
// answer depended on how many content ops the canonical order had applied by then.
|
|
969
|
+
//
|
|
970
|
+
// A rename the map could NOT resolve (a contested source: concurrent moves to
|
|
971
|
+
// different destinations, or a cycle) keeps the original behaviour, so a contest
|
|
972
|
+
// that a human resolves down to one rename still moves the file.
|
|
973
|
+
if (alias?.aliases.final.has(b.fromPath))
|
|
974
|
+
break;
|
|
975
|
+
const blob = tree.get(b.fromPath);
|
|
976
|
+
if (blob !== undefined) {
|
|
977
|
+
tree.delete(b.fromPath);
|
|
978
|
+
tree.set(b.path, blob);
|
|
838
979
|
}
|
|
839
980
|
break;
|
|
981
|
+
}
|
|
840
982
|
case "note":
|
|
841
983
|
break;
|
|
842
984
|
}
|