amalgm 0.1.245 → 0.1.246
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 +12 -0
- package/lib/cli.js +146 -8
- package/lib/layout.js +89 -4
- package/lib/shared-realtime-tunnel.js +384 -43
- package/lib/supervisor.js +0 -3
- package/package.json +2 -2
- package/runtime/scripts/amalgm-mcp/adapters/contract.js +197 -0
- package/runtime/scripts/amalgm-mcp/adapters/filesystem.js +135 -0
- package/runtime/scripts/amalgm-mcp/adapters/git.js +84 -0
- package/runtime/scripts/amalgm-mcp/adapters/index.js +43 -0
- package/runtime/scripts/amalgm-mcp/adapters/reference.js +31 -0
- package/runtime/scripts/amalgm-mcp/adapters/truth.js +19 -0
- package/runtime/scripts/amalgm-mcp/browser/cookie-jar.js +20 -68
- package/runtime/scripts/amalgm-mcp/index.js +4 -0
- package/runtime/scripts/amalgm-mcp/lib/layout.js +89 -4
- package/runtime/scripts/amalgm-mcp/observer/README.md +259 -0
- package/runtime/scripts/amalgm-mcp/observer/apply.js +150 -0
- package/runtime/scripts/amalgm-mcp/observer/continuity.js +111 -0
- package/runtime/scripts/amalgm-mcp/observer/edges.js +111 -0
- package/runtime/scripts/amalgm-mcp/observer/index.js +1146 -0
- package/runtime/scripts/amalgm-mcp/observer/scan.js +387 -0
- package/runtime/scripts/amalgm-mcp/observer/store.js +262 -0
- package/runtime/scripts/amalgm-mcp/observer/verify.js +200 -0
- package/runtime/scripts/amalgm-mcp/observer/watch.js +62 -0
- package/runtime/scripts/amalgm-mcp/project-context/store.js +19 -87
- package/runtime/scripts/amalgm-mcp/registration/classify.js +33 -0
- package/runtime/scripts/amalgm-mcp/registration/entity-cloud.js +456 -0
- package/runtime/scripts/amalgm-mcp/registration/entity-content.js +345 -0
- package/runtime/scripts/amalgm-mcp/registration/index.js +752 -0
- package/runtime/scripts/amalgm-mcp/registration/refusal.js +42 -0
- package/runtime/scripts/amalgm-mcp/registration/repo-followers.js +127 -0
- package/runtime/scripts/amalgm-mcp/registration/repo-states.js +109 -0
- package/runtime/scripts/amalgm-mcp/registration/service.js +310 -0
- package/runtime/scripts/amalgm-mcp/registration/tree.js +178 -0
- package/runtime/scripts/amalgm-mcp/registry/evidence.js +826 -0
- package/runtime/scripts/amalgm-mcp/registry/index.js +666 -0
- package/runtime/scripts/amalgm-mcp/registry/store.js +290 -0
- package/runtime/scripts/amalgm-mcp/repocard/README.md +103 -0
- package/runtime/scripts/amalgm-mcp/repocard/apply.js +111 -0
- package/runtime/scripts/amalgm-mcp/repocard/capture-worker.js +94 -0
- package/runtime/scripts/amalgm-mcp/repocard/capture.js +149 -0
- package/runtime/scripts/amalgm-mcp/repocard/follow.js +310 -0
- package/runtime/scripts/amalgm-mcp/repocard/git.js +48 -0
- package/runtime/scripts/amalgm-mcp/repocard/index.js +48 -0
- package/runtime/scripts/amalgm-mcp/server/local-service-router.js +2 -0
- package/runtime/scripts/amalgm-mcp/server/routes/entities.js +287 -0
- package/runtime/scripts/amalgm-mcp/server/routes/state.js +0 -13
- package/runtime/scripts/amalgm-mcp/state/attachments.js +11 -45
- package/runtime/scripts/amalgm-mcp/state/db.js +46 -215
- package/runtime/scripts/amalgm-mcp/state/docs.js +301 -1101
- package/runtime/scripts/amalgm-mcp/state/mutation-contracts.js +0 -99
- package/runtime/scripts/amalgm-mcp/state/mutations.js +130 -507
- package/runtime/scripts/amalgm-mcp/state/promotions.js +1 -21
- package/runtime/scripts/amalgm-mcp/state/replicas.js +13 -134
- package/runtime/scripts/amalgm-mcp/state/shared-rest.js +3 -46
- package/runtime/scripts/amalgm-mcp/tests/adapters.test.js +379 -0
- package/runtime/scripts/amalgm-mcp/tests/browser-cookie-cloud.test.js +0 -193
- package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.life.test.js +449 -0
- package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.rig.js +107 -0
- package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.watch.test.js +213 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/adapter.js +72 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/assert.js +497 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/bind.js +91 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/graph.js +1031 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/ledger.js +234 -0
- package/runtime/scripts/amalgm-mcp/tests/entity-oracle/referee.js +118 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.oracle.test.js +1365 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.registry.test.js +967 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.rig.js +239 -0
- package/runtime/scripts/amalgm-mcp/tests/entity.storm.test.js +486 -0
- package/runtime/scripts/amalgm-mcp/tests/fake-watch.js +35 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.links.test.js +289 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.rig.js +103 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.roots.test.js +505 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.storm.test.js +389 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.territory.test.js +845 -0
- package/runtime/scripts/amalgm-mcp/tests/observer.test.js +657 -0
- package/runtime/scripts/amalgm-mcp/tests/project-context.test.js +17 -32
- package/runtime/scripts/amalgm-mcp/tests/registration.service.test.js +256 -0
- package/runtime/scripts/amalgm-mcp/tests/registration.test.js +931 -0
- package/runtime/scripts/amalgm-mcp/tests/repocard.storm.test.js +284 -0
- package/runtime/scripts/amalgm-mcp/tests/repocard.test.js +371 -0
- package/runtime/scripts/amalgm-mcp/tests/repofollow.storm.test.js +435 -0
- package/runtime/scripts/amalgm-mcp/tests/repofollow.test.js +675 -0
- package/runtime/scripts/amalgm-mcp/tests/shared-tunnel-rehydration.test.js +0 -84
- package/runtime/scripts/amalgm-mcp/tests/state-docs.test.js +13 -376
- package/runtime/scripts/amalgm-mcp/tests/state-mutations.test.js +0 -309
- package/runtime/scripts/amalgm-mcp/tests/state-shared-replica.test.js +30 -758
- package/runtime/scripts/amalgm-mcp/tests/workspace-cards-store.test.js +3 -72
- package/runtime/scripts/amalgm-mcp/tests/workspace-cards.test.js +1 -89
- package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint-reducer.test.js +24 -55
- package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint.test.js +141 -424
- package/runtime/scripts/amalgm-mcp/tests/workspace-object-tunnel.test.js +3 -171
- package/runtime/scripts/amalgm-mcp/tests/workspace-objects.test.js +7 -220
- package/runtime/scripts/amalgm-mcp/tests/workspace-publication-invariants.test.js +236 -179
- package/runtime/scripts/amalgm-mcp/tests/workspace-reducer.test.js +326 -2228
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-cloud.test.js +3 -5319
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-core.test.js +1 -191
- package/runtime/scripts/amalgm-mcp/tests/workspace-tree-store.test.js +17 -3140
- package/runtime/scripts/amalgm-mcp/tests/workspace-wall.test.js +740 -137
- package/runtime/scripts/amalgm-mcp/workspace/access-store.js +1 -5
- package/runtime/scripts/amalgm-mcp/workspace/card.js +11 -35
- package/runtime/scripts/amalgm-mcp/workspace/cards.js +14 -39
- package/runtime/scripts/amalgm-mcp/workspace/checkpoint.js +147 -587
- package/runtime/scripts/amalgm-mcp/workspace/git.js +34 -406
- package/runtime/scripts/amalgm-mcp/workspace/merge.js +181 -102
- package/runtime/scripts/amalgm-mcp/workspace/objects.js +56 -221
- package/runtime/scripts/amalgm-mcp/workspace/reducer.js +538 -1964
- package/runtime/scripts/amalgm-mcp/workspace/rest.js +28 -49
- package/runtime/scripts/amalgm-mcp/workspace/store.js +4 -77
- package/runtime/scripts/amalgm-mcp/workspace/transition.js +192 -1734
- package/runtime/scripts/amalgm-mcp/workspace/tree/inclusion.js +1 -7
- package/runtime/scripts/amalgm-mcp/workspace/tree/local-state.js +61 -73
- package/runtime/scripts/amalgm-mcp/workspace/tree/reducer.js +6 -51
- package/runtime/scripts/amalgm-mcp/workspace/tree/snapshot.js +8 -79
- package/runtime/scripts/amalgm-mcp/workspace/tree-cloud.js +146 -3461
- package/runtime/scripts/amalgm-mcp/workspace/tree-store.js +71 -899
- package/runtime/scripts/amalgm-mcp/workspace/wall.js +538 -370
- package/runtime/scripts/local-gateway.js +1 -0
- package/runtime/scripts/amalgm-mcp/state/doc-disk.js +0 -550
- package/runtime/scripts/amalgm-mcp/tests/code-project-stream.test.js +0 -399
- package/runtime/scripts/amalgm-mcp/tests/fixtures/code-project-stream-v2.json +0 -1
- package/runtime/scripts/amalgm-mcp/tests/workspace-durable.test.js +0 -24
- package/runtime/scripts/amalgm-mcp/tests/workspace-local-intent.test.js +0 -1999
- package/runtime/scripts/amalgm-mcp/tests/workspace-native-file-transaction.test.js +0 -364
- package/runtime/scripts/amalgm-mcp/tests/workspace-provenance.test.js +0 -185
- package/runtime/scripts/amalgm-mcp/tests/workspace-reducer-liveness.test.js +0 -26
- package/runtime/scripts/amalgm-mcp/tests/workspace-sync-stats.test.js +0 -119
- package/runtime/scripts/amalgm-mcp/tests/workspace-transition.test.js +0 -1446
- package/runtime/scripts/amalgm-mcp/workspace/content.js +0 -32
- package/runtime/scripts/amalgm-mcp/workspace/durable.js +0 -45
- package/runtime/scripts/amalgm-mcp/workspace/intent.js +0 -535
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/BUILD.md +0 -31
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/darwin-arm64/amalgm-file-transaction +0 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/linux-x64/amalgm-file-transaction +0 -0
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/build.mjs +0 -72
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/client.js +0 -165
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.mod +0 -5
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.sum +0 -2
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/main.go +0 -2201
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/manifest.json +0 -19
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_darwin.go +0 -18
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_linux.go +0 -18
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_darwin.go +0 -33
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_linux.go +0 -47
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/verify.mjs +0 -43
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_darwin.go +0 -114
- package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_linux.go +0 -84
- package/runtime/scripts/amalgm-mcp/workspace/project-stream.js +0 -771
- package/runtime/scripts/amalgm-mcp/workspace/provenance.js +0 -240
- package/runtime/scripts/amalgm-mcp/workspace/sync-stats.js +0 -240
- package/runtime/scripts/amalgm-mcp/workspace/tree/floor.js +0 -100
- package/runtime/scripts/amalgm-mcp/workspace/tree/observation-holds.js +0 -127
- package/runtime/scripts/amalgm-mcp/workspace/tree/path-state.js +0 -12
- package/runtime/scripts/amalgm-mcp/workspace/tree/root-binding.js +0 -125
- package/runtime/scripts/amalgm-mcp/workspace/tree/symlinks.js +0 -76
- package/runtime/scripts/amalgm-mcp/workspace/tree-materialization.js +0 -3766
|
@@ -5,7 +5,7 @@ const assert = require('node:assert/strict');
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const os = require('os');
|
|
7
7
|
const path = require('path');
|
|
8
|
-
const { execFile
|
|
8
|
+
const { execFile } = require('child_process');
|
|
9
9
|
const { promisify } = require('util');
|
|
10
10
|
|
|
11
11
|
const execFileAsync = promisify(execFile);
|
|
@@ -23,27 +23,18 @@ fs.writeFileSync(
|
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
const { closeLocalDb } = require('../state/db');
|
|
26
|
-
const {
|
|
27
|
-
_test: gitTest,
|
|
28
|
-
captureCheckpoint,
|
|
29
|
-
captureWorktreeDiff,
|
|
30
|
-
} = require('../workspace/git');
|
|
26
|
+
const { captureCheckpoint, captureWorktreeDiff } = require('../workspace/git');
|
|
31
27
|
const merge = require('../workspace/merge');
|
|
32
|
-
const {
|
|
28
|
+
const { applyPatch } = require('../workspace/transition');
|
|
33
29
|
const {
|
|
34
30
|
_test,
|
|
35
31
|
CHECKPOINT_CONTRACT,
|
|
36
32
|
checkpointFile,
|
|
37
|
-
checkpointValue,
|
|
38
33
|
checkpointValueReady,
|
|
39
34
|
readCheckpointValue,
|
|
40
35
|
revisionOf,
|
|
41
36
|
sameTransition,
|
|
42
37
|
} = require('../workspace/checkpoint');
|
|
43
|
-
const {
|
|
44
|
-
acknowledgeUpload,
|
|
45
|
-
claimUpload,
|
|
46
|
-
} = require('../workspace/objects');
|
|
47
38
|
|
|
48
39
|
test.after(() => {
|
|
49
40
|
closeLocalDb();
|
|
@@ -63,75 +54,6 @@ test('checkpoint publication waits until the reducer finishes writing both repo
|
|
|
63
54
|
assert.equal(_test.checkpointMayPublish(repoKey), true);
|
|
64
55
|
});
|
|
65
56
|
|
|
66
|
-
test('a checkpoint read across two different HEADs is discarded', () => {
|
|
67
|
-
assert.deepEqual(gitTest.checkpointCaptureResult({
|
|
68
|
-
baseOid: 'old-head',
|
|
69
|
-
observedOid: 'new-head',
|
|
70
|
-
indexDiff: '',
|
|
71
|
-
worktreeDiff: '',
|
|
72
|
-
bytes: 0,
|
|
73
|
-
maxBytes: Infinity,
|
|
74
|
-
}), {
|
|
75
|
-
baseOid: 'old-head',
|
|
76
|
-
indexDiff: null,
|
|
77
|
-
worktreeDiff: null,
|
|
78
|
-
reason: 'head-moved',
|
|
79
|
-
bytes: 0,
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('a checkpoint read across two different index or worktree states is discarded', () => {
|
|
84
|
-
const clean = {
|
|
85
|
-
baseOid: 'a'.repeat(40),
|
|
86
|
-
indexDiff: '',
|
|
87
|
-
worktreeDiff: '',
|
|
88
|
-
bytes: 0,
|
|
89
|
-
};
|
|
90
|
-
const staged = {
|
|
91
|
-
...clean,
|
|
92
|
-
indexDiff: 'staged bytes',
|
|
93
|
-
bytes: 12,
|
|
94
|
-
};
|
|
95
|
-
assert.deepEqual(gitTest.stableCheckpointCapture(clean, staged), {
|
|
96
|
-
baseOid: 'a'.repeat(40),
|
|
97
|
-
indexDiff: null,
|
|
98
|
-
worktreeDiff: null,
|
|
99
|
-
reason: 'observation-moved',
|
|
100
|
-
bytes: 12,
|
|
101
|
-
});
|
|
102
|
-
assert.deepEqual(gitTest.stableCheckpointCapture(staged, staged), staged);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('checkpoint capture requires two consecutive equal observations within its bound', async () => {
|
|
106
|
-
const clean = {
|
|
107
|
-
baseOid: 'a'.repeat(40),
|
|
108
|
-
indexDiff: '',
|
|
109
|
-
worktreeDiff: '',
|
|
110
|
-
bytes: 0,
|
|
111
|
-
};
|
|
112
|
-
const staged = {
|
|
113
|
-
...clean,
|
|
114
|
-
indexDiff: 'staged bytes',
|
|
115
|
-
bytes: 12,
|
|
116
|
-
};
|
|
117
|
-
const settling = [clean, staged, staged];
|
|
118
|
-
assert.deepEqual(
|
|
119
|
-
await gitTest.captureStableCheckpoint(() => Promise.resolve(settling.shift()), 3),
|
|
120
|
-
staged,
|
|
121
|
-
);
|
|
122
|
-
const alternating = [clean, staged, clean, staged];
|
|
123
|
-
assert.deepEqual(
|
|
124
|
-
await gitTest.captureStableCheckpoint(() => Promise.resolve(alternating.shift()), 4),
|
|
125
|
-
{
|
|
126
|
-
baseOid: 'a'.repeat(40),
|
|
127
|
-
indexDiff: null,
|
|
128
|
-
worktreeDiff: null,
|
|
129
|
-
reason: 'observation-moved',
|
|
130
|
-
bytes: 12,
|
|
131
|
-
},
|
|
132
|
-
);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
57
|
async function run(cwd, ...args) {
|
|
136
58
|
await execFileAsync(
|
|
137
59
|
'git',
|
|
@@ -166,7 +88,7 @@ async function makeRepoPair() {
|
|
|
166
88
|
return { author, receiver };
|
|
167
89
|
}
|
|
168
90
|
|
|
169
|
-
test('a dirty worktree round-trips through
|
|
91
|
+
test('a dirty worktree round-trips through capture and apply, gitignore filtering included', async () => {
|
|
170
92
|
const { author, receiver } = await makeRepoPair();
|
|
171
93
|
|
|
172
94
|
// Every dirty shape at once: tracked edit, staged edit, deletion, new
|
|
@@ -181,32 +103,13 @@ test('a dirty worktree round-trips through checkpoint trees, gitignore filtering
|
|
|
181
103
|
fs.mkdirSync(path.join(author, 'node_modules', 'junk'), { recursive: true });
|
|
182
104
|
fs.writeFileSync(path.join(author, 'node_modules', 'junk', 'x.js'), 'never travels\n');
|
|
183
105
|
|
|
184
|
-
const captured = await
|
|
185
|
-
assert.ok(captured.
|
|
186
|
-
assert.ok(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
const indexTree = await merge.treeOfPatch(receiver, captured.baseOid, captured.indexDiff);
|
|
192
|
-
const worktreeTree = await merge.treeOfPatch(
|
|
193
|
-
receiver,
|
|
194
|
-
indexTree,
|
|
195
|
-
captured.worktreeDiff,
|
|
196
|
-
);
|
|
197
|
-
await merge.advance(receiver, baseTree, worktreeTree, { label: 'checkpoint-test-forward' });
|
|
198
|
-
const forwardIndexOperation = '1'.repeat(64);
|
|
199
|
-
await advanceIndex(
|
|
200
|
-
receiver,
|
|
201
|
-
await merge.indexTree(receiver),
|
|
202
|
-
indexTree,
|
|
203
|
-
forwardIndexOperation,
|
|
204
|
-
);
|
|
205
|
-
require('../workspace/transition').releaseGitMetadataReceipts(
|
|
206
|
-
receiver,
|
|
207
|
-
forwardIndexOperation,
|
|
208
|
-
'index',
|
|
209
|
-
);
|
|
106
|
+
const captured = await captureWorktreeDiff(author);
|
|
107
|
+
assert.ok(captured.diff.length > 0);
|
|
108
|
+
assert.ok(!captured.diff.includes('node_modules'), 'ignored files must never enter a checkpoint');
|
|
109
|
+
|
|
110
|
+
const patchFile = path.join(tempRoot, 'roundtrip.patch');
|
|
111
|
+
fs.writeFileSync(patchFile, captured.diff);
|
|
112
|
+
await applyPatch(receiver, patchFile);
|
|
210
113
|
|
|
211
114
|
assert.equal(
|
|
212
115
|
fs.readFileSync(path.join(receiver, 'README.md'), 'utf8'),
|
|
@@ -227,20 +130,8 @@ test('a dirty worktree round-trips through checkpoint trees, gitignore filtering
|
|
|
227
130
|
assert.equal(fs.existsSync(path.join(receiver, 'LICENSE')), false, 'deletions travel');
|
|
228
131
|
assert.equal(fs.existsSync(path.join(receiver, 'node_modules')), false);
|
|
229
132
|
|
|
230
|
-
//
|
|
231
|
-
await
|
|
232
|
-
const reverseIndexOperation = '2'.repeat(64);
|
|
233
|
-
await advanceIndex(
|
|
234
|
-
receiver,
|
|
235
|
-
await merge.indexTree(receiver),
|
|
236
|
-
baseTree,
|
|
237
|
-
reverseIndexOperation,
|
|
238
|
-
);
|
|
239
|
-
require('../workspace/transition').releaseGitMetadataReceipts(
|
|
240
|
-
receiver,
|
|
241
|
-
reverseIndexOperation,
|
|
242
|
-
'index',
|
|
243
|
-
);
|
|
133
|
+
// And the reverse of the same patch restores the receiver to clean.
|
|
134
|
+
await applyPatch(receiver, patchFile, { reverse: true });
|
|
244
135
|
const after = await captureWorktreeDiff(receiver);
|
|
245
136
|
assert.equal(after.diff, '');
|
|
246
137
|
});
|
|
@@ -254,232 +145,6 @@ test('capture is stable: two reads of an untouched tree produce the same revisio
|
|
|
254
145
|
assert.equal(revisionOf(first.baseOid, first.diff), revisionOf(second.baseOid, second.diff));
|
|
255
146
|
});
|
|
256
147
|
|
|
257
|
-
test('index ABA cannot produce a checkpoint that never physically existed', async () => {
|
|
258
|
-
const author = path.join(tempRoot, 'index-aba-author');
|
|
259
|
-
fs.mkdirSync(author);
|
|
260
|
-
await run(author, 'init');
|
|
261
|
-
fs.writeFileSync(path.join(author, 'file.txt'), 'floor\n');
|
|
262
|
-
await run(author, 'add', 'file.txt');
|
|
263
|
-
await run(author, 'commit', '-m', 'floor');
|
|
264
|
-
fs.writeFileSync(path.join(author, 'file.txt'), 'local\n');
|
|
265
|
-
|
|
266
|
-
const mover = spawn('/bin/sh', ['-c', `
|
|
267
|
-
index=0
|
|
268
|
-
while [ "$index" -lt 500 ]; do
|
|
269
|
-
git reset -q HEAD -- file.txt
|
|
270
|
-
git add file.txt
|
|
271
|
-
index=$((index + 1))
|
|
272
|
-
done
|
|
273
|
-
`], {
|
|
274
|
-
cwd: author,
|
|
275
|
-
env: { ...process.env, GIT_CONFIG_NOSYSTEM: '1', GIT_TERMINAL_PROMPT: '0' },
|
|
276
|
-
stdio: ['ignore', 'ignore', 'pipe'],
|
|
277
|
-
});
|
|
278
|
-
let moved = 0;
|
|
279
|
-
try {
|
|
280
|
-
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
281
|
-
const captured = await captureCheckpoint(author);
|
|
282
|
-
if (captured.reason === 'observation-moved') {
|
|
283
|
-
moved += 1;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
assert.ok(
|
|
287
|
-
captured.indexDiff.length > 0 || captured.worktreeDiff.length > 0,
|
|
288
|
-
'capture returned an impossible clean index + clean worktree mixture',
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
} finally {
|
|
292
|
-
mover.kill('SIGTERM');
|
|
293
|
-
await new Promise((resolve) => {
|
|
294
|
-
if (mover.exitCode !== null) resolve();
|
|
295
|
-
else mover.once('exit', resolve);
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
assert.ok(moved > 0, 'the test did not overlap an index movement');
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
test('directory membership ABA cannot hide an untracked file from capture', async () => {
|
|
302
|
-
const author = path.join(tempRoot, 'membership-aba-author');
|
|
303
|
-
fs.mkdirSync(author);
|
|
304
|
-
await run(author, 'init', '-b', 'main');
|
|
305
|
-
fs.writeFileSync(path.join(author, 'tracked.txt'), 'floor\n');
|
|
306
|
-
await run(author, 'add', 'tracked.txt');
|
|
307
|
-
await run(author, 'commit', '-m', 'floor');
|
|
308
|
-
|
|
309
|
-
const source = String.raw`
|
|
310
|
-
const childProcess = require('child_process');
|
|
311
|
-
const fs = require('fs');
|
|
312
|
-
const path = require('path');
|
|
313
|
-
const { promisify } = require('util');
|
|
314
|
-
const originalExecFile = childProcess.execFile;
|
|
315
|
-
const late = path.join(process.env.TEST_REPO, 'late.txt');
|
|
316
|
-
let otherCalls = 0;
|
|
317
|
-
const wrappedExecFile = function(file, args, options, callback) {
|
|
318
|
-
const isUntracked = file === 'git'
|
|
319
|
-
&& Array.isArray(args)
|
|
320
|
-
&& args.includes('ls-files')
|
|
321
|
-
&& args.includes('--others');
|
|
322
|
-
if (!isUntracked) return originalExecFile(file, args, options, callback);
|
|
323
|
-
otherCalls += 1;
|
|
324
|
-
fs.rmSync(late, { force: true });
|
|
325
|
-
return originalExecFile(file, args, options, (error, stdout, stderr) => {
|
|
326
|
-
fs.writeFileSync(late, 'late bytes\n');
|
|
327
|
-
callback(error, stdout, stderr);
|
|
328
|
-
});
|
|
329
|
-
};
|
|
330
|
-
wrappedExecFile[promisify.custom] = (file, args, options) => new Promise(
|
|
331
|
-
(resolve, reject) => wrappedExecFile(file, args, options, (error, stdout, stderr) => {
|
|
332
|
-
if (error) {
|
|
333
|
-
error.stdout = stdout;
|
|
334
|
-
error.stderr = stderr;
|
|
335
|
-
reject(error);
|
|
336
|
-
} else {
|
|
337
|
-
resolve({ stdout, stderr });
|
|
338
|
-
}
|
|
339
|
-
}),
|
|
340
|
-
);
|
|
341
|
-
childProcess.execFile = wrappedExecFile;
|
|
342
|
-
const { captureCheckpoint } = require(process.env.GIT_MODULE);
|
|
343
|
-
captureCheckpoint(process.env.TEST_REPO).then((captured) => {
|
|
344
|
-
process.stdout.write(JSON.stringify({
|
|
345
|
-
captured,
|
|
346
|
-
otherCalls,
|
|
347
|
-
finalLateExists: fs.existsSync(late),
|
|
348
|
-
}));
|
|
349
|
-
}).catch((error) => {
|
|
350
|
-
process.stderr.write(error.stack || String(error));
|
|
351
|
-
process.exitCode = 1;
|
|
352
|
-
});
|
|
353
|
-
`;
|
|
354
|
-
const { stdout } = await execFileAsync(process.execPath, ['-e', source], {
|
|
355
|
-
env: {
|
|
356
|
-
...process.env,
|
|
357
|
-
TEST_REPO: author,
|
|
358
|
-
GIT_MODULE: require.resolve('../workspace/git'),
|
|
359
|
-
},
|
|
360
|
-
timeout: 30_000,
|
|
361
|
-
maxBuffer: 8 * 1024 * 1024,
|
|
362
|
-
});
|
|
363
|
-
const result = JSON.parse(stdout);
|
|
364
|
-
assert.equal(result.finalLateExists, true);
|
|
365
|
-
assert.ok(result.otherCalls >= 4);
|
|
366
|
-
assert.equal(result.captured.reason, 'observation-moved');
|
|
367
|
-
assert.equal(result.captured.indexDiff, null);
|
|
368
|
-
assert.equal(result.captured.worktreeDiff, null);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
test('same-inode directory rename ABA cannot hide its untracked children', async () => {
|
|
372
|
-
const author = path.join(tempRoot, 'directory-rename-aba-author');
|
|
373
|
-
fs.mkdirSync(author);
|
|
374
|
-
await run(author, 'init', '-b', 'main');
|
|
375
|
-
fs.writeFileSync(path.join(author, 'tracked.txt'), 'floor\n');
|
|
376
|
-
await run(author, 'add', 'tracked.txt');
|
|
377
|
-
await run(author, 'commit', '-m', 'floor');
|
|
378
|
-
fs.mkdirSync(path.join(author, 'local'));
|
|
379
|
-
fs.writeFileSync(path.join(author, 'local', 'local.txt'), 'local bytes\n');
|
|
380
|
-
|
|
381
|
-
const source = String.raw`
|
|
382
|
-
const childProcess = require('child_process');
|
|
383
|
-
const fs = require('fs');
|
|
384
|
-
const path = require('path');
|
|
385
|
-
const { promisify } = require('util');
|
|
386
|
-
const originalExecFile = childProcess.execFile;
|
|
387
|
-
const held = path.join(process.env.TEST_REPO, 'local');
|
|
388
|
-
const outside = path.join(path.dirname(process.env.TEST_REPO), 'held-local');
|
|
389
|
-
const originalIno = fs.statSync(held).ino;
|
|
390
|
-
let intercepted = 0;
|
|
391
|
-
const wrappedExecFile = function(file, args, options, callback) {
|
|
392
|
-
const isUntracked = file === 'git'
|
|
393
|
-
&& Array.isArray(args)
|
|
394
|
-
&& args.includes('ls-files')
|
|
395
|
-
&& args.includes('--others')
|
|
396
|
-
&& !args.includes('--ignored');
|
|
397
|
-
if (!isUntracked) return originalExecFile(file, args, options, callback);
|
|
398
|
-
intercepted += 1;
|
|
399
|
-
fs.renameSync(held, outside);
|
|
400
|
-
return originalExecFile(file, args, options, (error, stdout, stderr) => {
|
|
401
|
-
fs.renameSync(outside, held);
|
|
402
|
-
callback(error, stdout, stderr);
|
|
403
|
-
});
|
|
404
|
-
};
|
|
405
|
-
wrappedExecFile[promisify.custom] = (file, args, options) => new Promise(
|
|
406
|
-
(resolve, reject) => wrappedExecFile(file, args, options, (error, stdout, stderr) => {
|
|
407
|
-
if (error) {
|
|
408
|
-
error.stdout = stdout;
|
|
409
|
-
error.stderr = stderr;
|
|
410
|
-
reject(error);
|
|
411
|
-
} else {
|
|
412
|
-
resolve({ stdout, stderr });
|
|
413
|
-
}
|
|
414
|
-
}),
|
|
415
|
-
);
|
|
416
|
-
childProcess.execFile = wrappedExecFile;
|
|
417
|
-
const { captureCheckpoint } = require(process.env.GIT_MODULE);
|
|
418
|
-
captureCheckpoint(process.env.TEST_REPO).then((captured) => {
|
|
419
|
-
process.stdout.write(JSON.stringify({
|
|
420
|
-
captured,
|
|
421
|
-
intercepted,
|
|
422
|
-
finalExists: fs.existsSync(path.join(held, 'local.txt')),
|
|
423
|
-
sameInode: fs.statSync(held).ino === originalIno,
|
|
424
|
-
}));
|
|
425
|
-
}).catch((error) => {
|
|
426
|
-
process.stderr.write(error.stack || String(error));
|
|
427
|
-
process.exitCode = 1;
|
|
428
|
-
});
|
|
429
|
-
`;
|
|
430
|
-
const { stdout } = await execFileAsync(process.execPath, ['-e', source], {
|
|
431
|
-
env: {
|
|
432
|
-
...process.env,
|
|
433
|
-
TEST_REPO: author,
|
|
434
|
-
GIT_MODULE: require.resolve('../workspace/git'),
|
|
435
|
-
},
|
|
436
|
-
timeout: 30_000,
|
|
437
|
-
maxBuffer: 8 * 1024 * 1024,
|
|
438
|
-
});
|
|
439
|
-
const result = JSON.parse(stdout);
|
|
440
|
-
assert.ok(result.intercepted >= 2);
|
|
441
|
-
assert.equal(result.finalExists, true);
|
|
442
|
-
assert.equal(result.sameInode, true);
|
|
443
|
-
assert.equal(result.captured.reason, 'observation-moved');
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
test('an untracked nested repository is rejected instead of certified clean', async () => {
|
|
447
|
-
const author = path.join(tempRoot, 'nested-repository-author');
|
|
448
|
-
fs.mkdirSync(author);
|
|
449
|
-
await run(author, 'init', '-b', 'main');
|
|
450
|
-
fs.writeFileSync(path.join(author, 'tracked.txt'), 'floor\n');
|
|
451
|
-
await run(author, 'add', 'tracked.txt');
|
|
452
|
-
await run(author, 'commit', '-m', 'floor');
|
|
453
|
-
const nested = path.join(author, 'nested');
|
|
454
|
-
fs.mkdirSync(nested);
|
|
455
|
-
await run(nested, 'init', '-b', 'main');
|
|
456
|
-
fs.writeFileSync(path.join(nested, 'local.txt'), 'nested local bytes\n');
|
|
457
|
-
await run(nested, 'add', 'local.txt');
|
|
458
|
-
await run(nested, 'commit', '-m', 'nested');
|
|
459
|
-
|
|
460
|
-
const captured = await captureCheckpoint(author);
|
|
461
|
-
assert.equal(captured.reason, 'unsupported-nested-repository');
|
|
462
|
-
assert.equal(captured.indexDiff, null);
|
|
463
|
-
assert.equal(captured.worktreeDiff, null);
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
test('checkpoint identity ignores Git file-patch order', async () => {
|
|
467
|
-
const { author } = await makeRepoPair();
|
|
468
|
-
fs.appendFileSync(path.join(author, 'README.md'), 'tracked edit\n');
|
|
469
|
-
fs.writeFileSync(path.join(author, 'A-new-file.txt'), 'untracked edit\n');
|
|
470
|
-
|
|
471
|
-
const captured = await captureCheckpoint(author);
|
|
472
|
-
const indexTree = await merge.treeOfPatch(author, captured.baseOid, captured.indexDiff);
|
|
473
|
-
const worktreeTree = await merge.treeOfPatch(author, indexTree, captured.worktreeDiff);
|
|
474
|
-
const normalized = await merge.diffOfTree(author, indexTree, worktreeTree);
|
|
475
|
-
|
|
476
|
-
assert.notEqual(captured.worktreeDiff, normalized);
|
|
477
|
-
assert.equal(
|
|
478
|
-
revisionOf(captured.baseOid, captured.indexDiff, captured.worktreeDiff),
|
|
479
|
-
revisionOf(captured.baseOid, captured.indexDiff, normalized),
|
|
480
|
-
);
|
|
481
|
-
});
|
|
482
|
-
|
|
483
148
|
test('one checkpoint preserves the staged and unstaged layers separately', async () => {
|
|
484
149
|
const { author } = await makeRepoPair();
|
|
485
150
|
fs.writeFileSync(path.join(author, 'src', 'index.js'), 'console.log(2);\n');
|
|
@@ -488,11 +153,10 @@ test('one checkpoint preserves the staged and unstaged layers separately', async
|
|
|
488
153
|
fs.appendFileSync(path.join(author, 'README.md'), 'unstaged\n');
|
|
489
154
|
|
|
490
155
|
const captured = await captureCheckpoint(author);
|
|
491
|
-
assert.
|
|
492
|
-
assert.ok(captured.indexDiff.includes('console.log(
|
|
493
|
-
assert.ok(
|
|
494
|
-
assert.ok(captured.worktreeDiff.includes('
|
|
495
|
-
assert.ok(captured.worktreeDiff.includes('unstaged'), JSON.stringify(captured));
|
|
156
|
+
assert.ok(captured.indexDiff.includes('console.log(2)'));
|
|
157
|
+
assert.ok(!captured.indexDiff.includes('console.log(3)'));
|
|
158
|
+
assert.ok(captured.worktreeDiff.includes('console.log(3)'));
|
|
159
|
+
assert.ok(captured.worktreeDiff.includes('unstaged'));
|
|
496
160
|
|
|
497
161
|
const indexTree = await merge.treeOfPatch(author, captured.baseOid, captured.indexDiff);
|
|
498
162
|
const worktreeTree = await merge.treeOfPatch(author, indexTree, captured.worktreeDiff);
|
|
@@ -500,23 +164,6 @@ test('one checkpoint preserves the staged and unstaged layers separately', async
|
|
|
500
164
|
assert.equal(await runOutput(author, 'show', `${worktreeTree}:src/index.js`), 'console.log(3);\n');
|
|
501
165
|
});
|
|
502
166
|
|
|
503
|
-
test('same-size same-time saves cannot make Git mix staged identity with working bytes', async () => {
|
|
504
|
-
const { author } = await makeRepoPair();
|
|
505
|
-
await run(author, 'config', 'core.trustctime', 'false');
|
|
506
|
-
const file = path.join(author, 'src', 'index.js');
|
|
507
|
-
fs.writeFileSync(file, 'console.log(2);\n');
|
|
508
|
-
await run(author, 'add', 'src/index.js');
|
|
509
|
-
const stagedTime = fs.statSync(file);
|
|
510
|
-
fs.writeFileSync(file, 'console.log(3);\n');
|
|
511
|
-
fs.utimesSync(file, stagedTime.atime, stagedTime.mtime);
|
|
512
|
-
|
|
513
|
-
const captured = await captureCheckpoint(author);
|
|
514
|
-
assert.equal(captured.reason, undefined, JSON.stringify(captured));
|
|
515
|
-
assert.ok(captured.indexDiff.includes('console.log(2)'), JSON.stringify(captured));
|
|
516
|
-
assert.ok(!captured.indexDiff.includes('console.log(3)'), JSON.stringify(captured));
|
|
517
|
-
assert.ok(captured.worktreeDiff.includes('console.log(3)'), JSON.stringify(captured));
|
|
518
|
-
});
|
|
519
|
-
|
|
520
167
|
test('a clean tree captures as an empty patch, and oversized state is a named refusal', async () => {
|
|
521
168
|
const { author } = await makeRepoPair();
|
|
522
169
|
const clean = await captureWorktreeDiff(author);
|
|
@@ -533,7 +180,43 @@ test('checkpoint captures are local cache; their operations travel on the one wa
|
|
|
533
180
|
assert.equal(first, checkpointFile('m1', 'https://github.com/a/b'));
|
|
534
181
|
assert.notEqual(first, checkpointFile('m2', 'https://github.com/a/b'));
|
|
535
182
|
assert.notEqual(first, checkpointFile('m1', 'https://github.com/a/c'));
|
|
536
|
-
assert.match(first, /repo-checkpoints-
|
|
183
|
+
assert.match(first, /repo-checkpoints-v8/);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test('a materialized peer card is immediately a valid checkpoint base', () => {
|
|
187
|
+
const oid = 'a'.repeat(40);
|
|
188
|
+
assert.equal(_test.checkpointBaseReady({
|
|
189
|
+
head: { branch: 'main', oid },
|
|
190
|
+
}, {
|
|
191
|
+
appliedThrough: 12,
|
|
192
|
+
branch: 'main',
|
|
193
|
+
baseOid: oid,
|
|
194
|
+
indexDiff: '',
|
|
195
|
+
worktreeDiff: '',
|
|
196
|
+
}, {
|
|
197
|
+
receivedThrough: 12,
|
|
198
|
+
appliedThrough: 12,
|
|
199
|
+
pending: 0,
|
|
200
|
+
current: true,
|
|
201
|
+
}), true);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('checkpoint publication waits when the reducer is behind the rail', () => {
|
|
205
|
+
const oid = 'a'.repeat(40);
|
|
206
|
+
const card = { head: { branch: 'main', oid } };
|
|
207
|
+
const reduced = {
|
|
208
|
+
appliedThrough: 11,
|
|
209
|
+
branch: 'main',
|
|
210
|
+
baseOid: oid,
|
|
211
|
+
indexDiff: '',
|
|
212
|
+
worktreeDiff: '',
|
|
213
|
+
};
|
|
214
|
+
assert.equal(_test.checkpointBaseReady(card, reduced, {
|
|
215
|
+
receivedThrough: 12,
|
|
216
|
+
appliedThrough: 11,
|
|
217
|
+
pending: 0,
|
|
218
|
+
current: false,
|
|
219
|
+
}), false);
|
|
537
220
|
});
|
|
538
221
|
|
|
539
222
|
test('an uploading checkpoint payload is not published as a transition', () => {
|
|
@@ -541,7 +224,7 @@ test('an uploading checkpoint payload is not published as a transition', () => {
|
|
|
541
224
|
revision: 'a'.repeat(64),
|
|
542
225
|
payload: {
|
|
543
226
|
kind: 'pending',
|
|
544
|
-
contract: 'opaque-chunks@
|
|
227
|
+
contract: 'opaque-chunks@1',
|
|
545
228
|
checksum: 'b'.repeat(64),
|
|
546
229
|
},
|
|
547
230
|
};
|
|
@@ -550,61 +233,95 @@ test('an uploading checkpoint payload is not published as a transition', () => {
|
|
|
550
233
|
assert.equal(checkpointValueReady({ revision: null, indexDiff: '', worktreeDiff: '' }), true);
|
|
551
234
|
});
|
|
552
235
|
|
|
553
|
-
test('a
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
'
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
'
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
'
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
'
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
'
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
236
|
+
test('a clean losing commit travels as parked metadata on a no-op checkpoint', () => {
|
|
237
|
+
const sharedValue = { revision: null, indexDiff: '', worktreeDiff: '' };
|
|
238
|
+
const parked = [{
|
|
239
|
+
oid: 'a'.repeat(40),
|
|
240
|
+
ref: `refs/amalgm/parked/${'a'.repeat(40)}`,
|
|
241
|
+
objects: { kind: 'bundle', checksum: 'b'.repeat(64) },
|
|
242
|
+
}];
|
|
243
|
+
const checkpoint = _test.checkpointForSharedState({
|
|
244
|
+
checkpoint: CHECKPOINT_CONTRACT,
|
|
245
|
+
machine: 'machine-a',
|
|
246
|
+
repoKey: 'root:test',
|
|
247
|
+
branch: 'old',
|
|
248
|
+
baseOid: 'c'.repeat(40),
|
|
249
|
+
from: sharedValue,
|
|
250
|
+
to: sharedValue,
|
|
251
|
+
parked: [],
|
|
252
|
+
}, {
|
|
253
|
+
machine: 'machine-a',
|
|
254
|
+
repoKey: 'root:test',
|
|
255
|
+
branch: 'main',
|
|
256
|
+
baseOid: 'd'.repeat(40),
|
|
257
|
+
sharedValue,
|
|
258
|
+
parked,
|
|
259
|
+
capturedAt: '2026-07-24T00:00:00.000Z',
|
|
260
|
+
});
|
|
577
261
|
|
|
578
|
-
assert.equal(
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
);
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
'machine-a',
|
|
594
|
-
repoKey,
|
|
262
|
+
assert.equal(checkpoint.checkpoint, CHECKPOINT_CONTRACT);
|
|
263
|
+
assert.equal(checkpoint.baseOid, 'd'.repeat(40));
|
|
264
|
+
assert.equal(checkpoint.branch, 'main');
|
|
265
|
+
assert.deepEqual(checkpoint.from, sharedValue);
|
|
266
|
+
assert.deepEqual(checkpoint.to, sharedValue);
|
|
267
|
+
assert.deepEqual(checkpoint.parked, parked);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('only this machine keeps announcing its parked commits', () => {
|
|
271
|
+
const baseOid = 'a'.repeat(40);
|
|
272
|
+
const localOid = 'b'.repeat(40);
|
|
273
|
+
const peerOid = 'c'.repeat(40);
|
|
274
|
+
const pendingOid = 'd'.repeat(40);
|
|
275
|
+
const existing = {
|
|
276
|
+
branch: 'main',
|
|
595
277
|
baseOid,
|
|
596
|
-
'',
|
|
597
|
-
|
|
278
|
+
parked: [{ oid: localOid, objects: { kind: 'pending' } }],
|
|
279
|
+
};
|
|
280
|
+
const reduced = {
|
|
281
|
+
parked: [
|
|
282
|
+
{ oid: localOid, version: 10, objects: { kind: 'pending' } },
|
|
283
|
+
{ oid: peerOid, version: 11, objects: { kind: 'bundle' } },
|
|
284
|
+
{ oid: pendingOid, objects: { kind: 'pending' } },
|
|
285
|
+
],
|
|
286
|
+
};
|
|
287
|
+
const card = { head: { branch: 'main', oid: baseOid } };
|
|
288
|
+
|
|
289
|
+
assert.deepEqual(
|
|
290
|
+
_test.localParkedEntries(existing, reduced, card).map((entry) => entry.oid),
|
|
291
|
+
[localOid, pendingOid],
|
|
598
292
|
);
|
|
599
|
-
assert.
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
293
|
+
assert.deepEqual(
|
|
294
|
+
_test.localParkedEntries(existing, reduced, {
|
|
295
|
+
head: { branch: 'main', oid: 'e'.repeat(40) },
|
|
296
|
+
}).map((entry) => entry.oid),
|
|
297
|
+
[pendingOid],
|
|
603
298
|
);
|
|
604
|
-
|
|
605
|
-
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('a server rail number does not turn the same parked checkpoint into new work', () => {
|
|
302
|
+
const value = { revision: null, indexDiff: '', worktreeDiff: '' };
|
|
303
|
+
const checkpoint = {
|
|
304
|
+
branch: 'main',
|
|
305
|
+
baseOid: 'a'.repeat(40),
|
|
306
|
+
from: value,
|
|
307
|
+
to: value,
|
|
308
|
+
parked: [{
|
|
309
|
+
oid: 'b'.repeat(40),
|
|
310
|
+
ref: `refs/amalgm/parked/${'b'.repeat(40)}`,
|
|
311
|
+
objects: { kind: 'bundle', checksum: 'c'.repeat(64) },
|
|
312
|
+
version: 12,
|
|
313
|
+
}],
|
|
314
|
+
};
|
|
606
315
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
316
|
+
assert.equal(sameTransition(checkpoint, {
|
|
317
|
+
...checkpoint,
|
|
318
|
+
parked: checkpoint.parked.map((entry) => ({ ...entry, version: 37 })),
|
|
319
|
+
}), true);
|
|
320
|
+
assert.equal(sameTransition(checkpoint, {
|
|
321
|
+
...checkpoint,
|
|
322
|
+
parked: checkpoint.parked.map((entry) => ({
|
|
323
|
+
...entry,
|
|
324
|
+
objects: { ...entry.objects, checksum: 'd'.repeat(64) },
|
|
325
|
+
})),
|
|
326
|
+
}), false);
|
|
610
327
|
});
|