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
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const test = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const crypto = require('node:crypto');
|
|
6
|
-
const fs = require('node:fs');
|
|
7
|
-
const os = require('node:os');
|
|
8
|
-
const path = require('node:path');
|
|
9
|
-
const { execFile, execFileSync, spawn } = require('node:child_process');
|
|
10
|
-
const { promisify } = require('node:util');
|
|
11
|
-
|
|
12
|
-
const execFileAsync = promisify(execFile);
|
|
13
|
-
|
|
14
|
-
test('checked-in descriptor-relative transaction binaries match their exact source', async () => {
|
|
15
|
-
const verifier = path.join(
|
|
16
|
-
__dirname,
|
|
17
|
-
'..',
|
|
18
|
-
'workspace',
|
|
19
|
-
'native-file-transaction',
|
|
20
|
-
'verify.mjs',
|
|
21
|
-
);
|
|
22
|
-
const { stdout } = await execFileAsync(process.execPath, [verifier]);
|
|
23
|
-
assert.match(stdout, /verified source [a-f0-9]{64} and 2 binaries/);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('native process lifetime distinguishes live owners from exited PIDs', () => {
|
|
27
|
-
const platform = process.platform === 'darwin' && process.arch === 'arm64'
|
|
28
|
-
? 'darwin-arm64'
|
|
29
|
-
: process.platform === 'linux' && process.arch === 'x64'
|
|
30
|
-
? 'linux-x64'
|
|
31
|
-
: null;
|
|
32
|
-
if (platform === null) return;
|
|
33
|
-
const executable = path.join(
|
|
34
|
-
__dirname,
|
|
35
|
-
'..',
|
|
36
|
-
'workspace',
|
|
37
|
-
'native-file-transaction',
|
|
38
|
-
'bin',
|
|
39
|
-
platform,
|
|
40
|
-
'amalgm-file-transaction',
|
|
41
|
-
);
|
|
42
|
-
const identity = (pid) => JSON.parse(execFileSync(executable, [], {
|
|
43
|
-
input: JSON.stringify({
|
|
44
|
-
action: 'identity',
|
|
45
|
-
backend: 'process-identity',
|
|
46
|
-
pid,
|
|
47
|
-
}),
|
|
48
|
-
encoding: 'utf8',
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
const current = identity(process.pid);
|
|
52
|
-
assert.equal(current.status, 'identified');
|
|
53
|
-
assert.match(current.identity, /.+/);
|
|
54
|
-
assert.equal(identity(1).status, 'identified');
|
|
55
|
-
assert.deepEqual(identity(2_147_483_647), { status: 'exited' });
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('same bytes on a replacement inode do not satisfy an exact document predecessor', () => {
|
|
59
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'amalgm-file-cas-test-'));
|
|
60
|
-
const file = path.join(root, 'document.md');
|
|
61
|
-
fs.writeFileSync(file, 'same bytes\n', 'utf8');
|
|
62
|
-
const docDisk = require('../state/doc-disk');
|
|
63
|
-
const native = require('../workspace/native-file-transaction/client');
|
|
64
|
-
const expected = docDisk.observe(file);
|
|
65
|
-
|
|
66
|
-
const replacement = path.join(root, 'replacement.md');
|
|
67
|
-
fs.writeFileSync(replacement, 'same bytes\n', 'utf8');
|
|
68
|
-
fs.renameSync(replacement, file);
|
|
69
|
-
|
|
70
|
-
const targetContent = Buffer.from('new target\n', 'utf8');
|
|
71
|
-
const transaction = {
|
|
72
|
-
root: expected.root,
|
|
73
|
-
rootDev: expected.rootDev,
|
|
74
|
-
rootIno: expected.rootIno,
|
|
75
|
-
path: expected.relativePath,
|
|
76
|
-
id: crypto.createHash('sha256').update('same-byte-inode-cas').digest('hex'),
|
|
77
|
-
operation: 'same-byte-inode-cas',
|
|
78
|
-
expected: expected.identity,
|
|
79
|
-
target: docDisk.byteIdentity(targetContent),
|
|
80
|
-
};
|
|
81
|
-
try {
|
|
82
|
-
const result = native.run(transaction, 'apply', targetContent);
|
|
83
|
-
assert.equal(result.status, 'changed');
|
|
84
|
-
assert.equal(fs.readFileSync(file, 'utf8'), 'same bytes\n');
|
|
85
|
-
} finally {
|
|
86
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test('document observation stays with one physical parent across rename and replacement', () => {
|
|
91
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'amalgm-file-observe-test-'));
|
|
92
|
-
const parent = path.join(root, 'registered-parent');
|
|
93
|
-
const renamed = path.join(root, 'uuid-owned-parent');
|
|
94
|
-
const file = path.join(parent, 'document.md');
|
|
95
|
-
fs.mkdirSync(parent);
|
|
96
|
-
fs.writeFileSync(file, 'owned bytes\n', 'utf8');
|
|
97
|
-
const originalParent = fs.statSync(parent, { bigint: true });
|
|
98
|
-
const child = spawn(process.execPath, [
|
|
99
|
-
'-e',
|
|
100
|
-
'const fs=require("fs");'
|
|
101
|
-
+ `setTimeout(()=>{fs.renameSync(${JSON.stringify(parent)},${JSON.stringify(renamed)});`
|
|
102
|
-
+ `fs.mkdirSync(${JSON.stringify(parent)});`
|
|
103
|
-
+ `fs.writeFileSync(${JSON.stringify(file)},"unrelated bytes\\n","utf8");},75);`,
|
|
104
|
-
], { stdio: 'ignore' });
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const observed = require('../state/doc-disk').observe(file, {
|
|
108
|
-
pauseAfterParentOpen: 350,
|
|
109
|
-
});
|
|
110
|
-
assert.equal(observed.text, 'owned bytes\n');
|
|
111
|
-
assert.equal(observed.rootDev, originalParent.dev.toString());
|
|
112
|
-
assert.equal(observed.rootIno, originalParent.ino.toString());
|
|
113
|
-
assert.notEqual(observed.text, fs.readFileSync(file, 'utf8'));
|
|
114
|
-
} finally {
|
|
115
|
-
child.unref();
|
|
116
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test('receipt release keeps proof when its physical parent moved', () => {
|
|
121
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'amalgm-receipt-move-test-'));
|
|
122
|
-
const parent = path.join(root, 'original-parent');
|
|
123
|
-
const movedParent = path.join(root, 'moved-parent');
|
|
124
|
-
const file = path.join(parent, 'document.md');
|
|
125
|
-
fs.mkdirSync(parent);
|
|
126
|
-
fs.writeFileSync(file, 'before\n', 'utf8');
|
|
127
|
-
const docDisk = require('../state/doc-disk');
|
|
128
|
-
const native = require('../workspace/native-file-transaction/client');
|
|
129
|
-
const expected = docDisk.observe(file);
|
|
130
|
-
const targetContent = Buffer.from('after\n', 'utf8');
|
|
131
|
-
const transaction = {
|
|
132
|
-
root: expected.root,
|
|
133
|
-
rootDev: expected.rootDev,
|
|
134
|
-
rootIno: expected.rootIno,
|
|
135
|
-
path: expected.relativePath,
|
|
136
|
-
id: crypto.createHash('sha256').update('moved-receipt-parent').digest('hex'),
|
|
137
|
-
operation: 'moved-receipt-parent',
|
|
138
|
-
expected: expected.identity,
|
|
139
|
-
target: docDisk.byteIdentity(targetContent),
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
assert.equal(
|
|
144
|
-
native.run(transaction, 'apply', targetContent).status,
|
|
145
|
-
'applied',
|
|
146
|
-
);
|
|
147
|
-
fs.renameSync(parent, movedParent);
|
|
148
|
-
|
|
149
|
-
const retained = native.run(transaction, 'release');
|
|
150
|
-
assert.equal(retained.status, 'pending');
|
|
151
|
-
assert.match(retained.reason, /receipt parent is unavailable/);
|
|
152
|
-
assert.equal(
|
|
153
|
-
fs.existsSync(path.join(
|
|
154
|
-
movedParent,
|
|
155
|
-
`.amalgm-apply-${transaction.id}`,
|
|
156
|
-
)),
|
|
157
|
-
true,
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
const rebound = native.run({
|
|
161
|
-
...transaction,
|
|
162
|
-
root: fs.realpathSync(movedParent),
|
|
163
|
-
}, 'release');
|
|
164
|
-
assert.equal(rebound.status, 'released');
|
|
165
|
-
assert.equal(
|
|
166
|
-
fs.existsSync(path.join(
|
|
167
|
-
movedParent,
|
|
168
|
-
`.amalgm-apply-${transaction.id}`,
|
|
169
|
-
)),
|
|
170
|
-
false,
|
|
171
|
-
);
|
|
172
|
-
} finally {
|
|
173
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test('exclusive tree moves preserve a destination created during the rename window', () => {
|
|
178
|
-
const native = require('../workspace/native-file-transaction/client');
|
|
179
|
-
for (const kind of ['file', 'directory']) {
|
|
180
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), `amalgm-tree-cas-${kind}-`));
|
|
181
|
-
const source = path.join(root, `source-${kind}`);
|
|
182
|
-
const destination = path.join(root, `destination-${kind}`);
|
|
183
|
-
if (kind === 'directory') {
|
|
184
|
-
fs.mkdirSync(source);
|
|
185
|
-
fs.writeFileSync(path.join(source, 'value.txt'), 'source directory\n', 'utf8');
|
|
186
|
-
} else {
|
|
187
|
-
fs.writeFileSync(source, 'source file\n', 'utf8');
|
|
188
|
-
}
|
|
189
|
-
const rootStats = fs.lstatSync(root, { bigint: true });
|
|
190
|
-
const sourceStats = fs.lstatSync(source, { bigint: true });
|
|
191
|
-
const child = spawn(process.execPath, [
|
|
192
|
-
'-e',
|
|
193
|
-
'const fs=require("fs");'
|
|
194
|
-
+ `setTimeout(()=>{`
|
|
195
|
-
+ (kind === 'directory'
|
|
196
|
-
? `fs.mkdirSync(${JSON.stringify(destination)});`
|
|
197
|
-
+ `fs.writeFileSync(${JSON.stringify(path.join(destination, 'value.txt'))},"racing directory\\n","utf8");`
|
|
198
|
-
: `fs.writeFileSync(${JSON.stringify(destination)},"racing file\\n","utf8");`)
|
|
199
|
-
+ '},75);',
|
|
200
|
-
], { stdio: 'ignore' });
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
const result = native.moveNoReplace({
|
|
204
|
-
root: fs.realpathSync(root),
|
|
205
|
-
rootDev: rootStats.dev.toString(),
|
|
206
|
-
rootIno: rootStats.ino.toString(),
|
|
207
|
-
source: path.basename(source),
|
|
208
|
-
sourceIdentity: {
|
|
209
|
-
kind: kind === 'directory' ? 'folder' : kind,
|
|
210
|
-
dev: sourceStats.dev.toString(),
|
|
211
|
-
ino: sourceStats.ino.toString(),
|
|
212
|
-
},
|
|
213
|
-
sourceParentIdentity: {
|
|
214
|
-
kind: 'folder',
|
|
215
|
-
dev: rootStats.dev.toString(),
|
|
216
|
-
ino: rootStats.ino.toString(),
|
|
217
|
-
},
|
|
218
|
-
targetParentIdentity: {
|
|
219
|
-
kind: 'folder',
|
|
220
|
-
dev: rootStats.dev.toString(),
|
|
221
|
-
ino: rootStats.ino.toString(),
|
|
222
|
-
},
|
|
223
|
-
path: path.basename(destination),
|
|
224
|
-
id: crypto.createHash('sha256').update(`tree-cas-${kind}`).digest('hex'),
|
|
225
|
-
operation: `tree-cas-${kind}`,
|
|
226
|
-
}, {
|
|
227
|
-
pauseBeforeInstall: 300,
|
|
228
|
-
});
|
|
229
|
-
assert.equal(result.status, 'changed');
|
|
230
|
-
assert.match(result.reason, /destination changed/);
|
|
231
|
-
if (kind === 'directory') {
|
|
232
|
-
assert.equal(
|
|
233
|
-
fs.readFileSync(path.join(source, 'value.txt'), 'utf8'),
|
|
234
|
-
'source directory\n',
|
|
235
|
-
);
|
|
236
|
-
assert.equal(
|
|
237
|
-
fs.readFileSync(path.join(destination, 'value.txt'), 'utf8'),
|
|
238
|
-
'racing directory\n',
|
|
239
|
-
);
|
|
240
|
-
} else {
|
|
241
|
-
assert.equal(fs.readFileSync(source, 'utf8'), 'source file\n');
|
|
242
|
-
assert.equal(fs.readFileSync(destination, 'utf8'), 'racing file\n');
|
|
243
|
-
}
|
|
244
|
-
} finally {
|
|
245
|
-
child.unref();
|
|
246
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test('exclusive tree moves restore a source name swapped during the rename window', () => {
|
|
252
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'amalgm-tree-source-cas-'));
|
|
253
|
-
const source = path.join(root, 'source.txt');
|
|
254
|
-
const movedOriginal = path.join(root, 'moved-original.txt');
|
|
255
|
-
const destination = path.join(root, 'destination.txt');
|
|
256
|
-
fs.writeFileSync(source, 'original source\n', 'utf8');
|
|
257
|
-
const rootStats = fs.lstatSync(root, { bigint: true });
|
|
258
|
-
const sourceStats = fs.lstatSync(source, { bigint: true });
|
|
259
|
-
const child = spawn(process.execPath, [
|
|
260
|
-
'-e',
|
|
261
|
-
'const fs=require("fs");'
|
|
262
|
-
+ `setTimeout(()=>{`
|
|
263
|
-
+ `fs.renameSync(${JSON.stringify(source)},${JSON.stringify(movedOriginal)});`
|
|
264
|
-
+ `fs.writeFileSync(${JSON.stringify(source)},"replacement source\\n","utf8");`
|
|
265
|
-
+ '},75);',
|
|
266
|
-
], { stdio: 'ignore' });
|
|
267
|
-
|
|
268
|
-
try {
|
|
269
|
-
const result = require('../workspace/native-file-transaction/client')
|
|
270
|
-
.moveNoReplace({
|
|
271
|
-
root: fs.realpathSync(root),
|
|
272
|
-
rootDev: rootStats.dev.toString(),
|
|
273
|
-
rootIno: rootStats.ino.toString(),
|
|
274
|
-
source: path.basename(source),
|
|
275
|
-
sourceIdentity: {
|
|
276
|
-
kind: 'file',
|
|
277
|
-
dev: sourceStats.dev.toString(),
|
|
278
|
-
ino: sourceStats.ino.toString(),
|
|
279
|
-
},
|
|
280
|
-
sourceParentIdentity: {
|
|
281
|
-
kind: 'folder',
|
|
282
|
-
dev: rootStats.dev.toString(),
|
|
283
|
-
ino: rootStats.ino.toString(),
|
|
284
|
-
},
|
|
285
|
-
targetParentIdentity: {
|
|
286
|
-
kind: 'folder',
|
|
287
|
-
dev: rootStats.dev.toString(),
|
|
288
|
-
ino: rootStats.ino.toString(),
|
|
289
|
-
},
|
|
290
|
-
path: path.basename(destination),
|
|
291
|
-
id: crypto.createHash('sha256').update('tree-source-cas').digest('hex'),
|
|
292
|
-
operation: 'tree-source-cas',
|
|
293
|
-
}, {
|
|
294
|
-
pauseBeforeInstall: 300,
|
|
295
|
-
});
|
|
296
|
-
assert.equal(result.status, 'changed');
|
|
297
|
-
assert.match(result.reason, /source changed during exclusive move and was restored/);
|
|
298
|
-
assert.equal(fs.existsSync(destination), false);
|
|
299
|
-
assert.equal(fs.readFileSync(source, 'utf8'), 'replacement source\n');
|
|
300
|
-
assert.equal(fs.readFileSync(movedOriginal, 'utf8'), 'original source\n');
|
|
301
|
-
} finally {
|
|
302
|
-
child.unref();
|
|
303
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
test('exclusive tree moves retain both names when a second source wins the undo race', () => {
|
|
308
|
-
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'amalgm-tree-source-both-'));
|
|
309
|
-
const source = path.join(root, 'source.txt');
|
|
310
|
-
const movedOriginal = path.join(root, 'moved-original.txt');
|
|
311
|
-
const destination = path.join(root, 'destination.txt');
|
|
312
|
-
fs.writeFileSync(source, 'original source\n', 'utf8');
|
|
313
|
-
const rootStats = fs.lstatSync(root, { bigint: true });
|
|
314
|
-
const sourceStats = fs.lstatSync(source, { bigint: true });
|
|
315
|
-
const child = spawn(process.execPath, [
|
|
316
|
-
'-e',
|
|
317
|
-
'const fs=require("fs");'
|
|
318
|
-
+ `setTimeout(()=>{`
|
|
319
|
-
+ `fs.renameSync(${JSON.stringify(source)},${JSON.stringify(movedOriginal)});`
|
|
320
|
-
+ `fs.writeFileSync(${JSON.stringify(source)},"first replacement\\n","utf8");`
|
|
321
|
-
+ '},250);'
|
|
322
|
-
+ `setTimeout(()=>{`
|
|
323
|
-
+ `fs.writeFileSync(${JSON.stringify(source)},"second replacement\\n","utf8");`
|
|
324
|
-
+ '},900);',
|
|
325
|
-
], { stdio: 'ignore' });
|
|
326
|
-
try {
|
|
327
|
-
const result = require('../workspace/native-file-transaction/client')
|
|
328
|
-
.moveNoReplace({
|
|
329
|
-
root: fs.realpathSync(root),
|
|
330
|
-
rootDev: rootStats.dev.toString(),
|
|
331
|
-
rootIno: rootStats.ino.toString(),
|
|
332
|
-
source: path.basename(source),
|
|
333
|
-
sourceIdentity: {
|
|
334
|
-
kind: 'file',
|
|
335
|
-
dev: sourceStats.dev.toString(),
|
|
336
|
-
ino: sourceStats.ino.toString(),
|
|
337
|
-
},
|
|
338
|
-
sourceParentIdentity: {
|
|
339
|
-
kind: 'folder',
|
|
340
|
-
dev: rootStats.dev.toString(),
|
|
341
|
-
ino: rootStats.ino.toString(),
|
|
342
|
-
},
|
|
343
|
-
targetParentIdentity: {
|
|
344
|
-
kind: 'folder',
|
|
345
|
-
dev: rootStats.dev.toString(),
|
|
346
|
-
ino: rootStats.ino.toString(),
|
|
347
|
-
},
|
|
348
|
-
path: path.basename(destination),
|
|
349
|
-
id: crypto.createHash('sha256').update('tree-source-both').digest('hex'),
|
|
350
|
-
operation: 'tree-source-both',
|
|
351
|
-
}, {
|
|
352
|
-
pauseBeforeInstall: 600,
|
|
353
|
-
pauseAfterTreeMove: 600,
|
|
354
|
-
});
|
|
355
|
-
assert.equal(result.status, 'changed');
|
|
356
|
-
assert.match(result.reason, /both entries were retained/);
|
|
357
|
-
assert.equal(fs.readFileSync(movedOriginal, 'utf8'), 'original source\n');
|
|
358
|
-
assert.equal(fs.readFileSync(destination, 'utf8'), 'first replacement\n');
|
|
359
|
-
assert.equal(fs.readFileSync(source, 'utf8'), 'second replacement\n');
|
|
360
|
-
} finally {
|
|
361
|
-
child.unref();
|
|
362
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
363
|
-
}
|
|
364
|
-
});
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const assert = require('node:assert/strict');
|
|
4
|
-
const test = require('node:test');
|
|
5
|
-
|
|
6
|
-
const provenance = require('../workspace/provenance');
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
ACTION,
|
|
10
|
-
CLASS,
|
|
11
|
-
STATE,
|
|
12
|
-
TRANSITIONS,
|
|
13
|
-
allStates,
|
|
14
|
-
provenanceClass,
|
|
15
|
-
publicationState,
|
|
16
|
-
requireTransition,
|
|
17
|
-
} = provenance;
|
|
18
|
-
|
|
19
|
-
const key = (from, action, to) => `${from} --${action}--> ${to}`;
|
|
20
|
-
|
|
21
|
-
test('managed bytes have exactly three provenance classes', () => {
|
|
22
|
-
assert.deepEqual(Object.values(CLASS), [
|
|
23
|
-
'officially-applied',
|
|
24
|
-
'journaled-local-intent',
|
|
25
|
-
'unknown-provenance',
|
|
26
|
-
]);
|
|
27
|
-
assert.deepEqual(
|
|
28
|
-
[...new Set(allStates.map(provenanceClass))].sort(),
|
|
29
|
-
Object.values(CLASS).sort(),
|
|
30
|
-
);
|
|
31
|
-
assert.equal(allStates.every((state) => provenanceClass(state) !== null), true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('the complete provenance transition relation has no implicit branch', () => {
|
|
35
|
-
const legal = new Set(TRANSITIONS.map((entry) => key(
|
|
36
|
-
entry.from,
|
|
37
|
-
entry.action,
|
|
38
|
-
entry.to,
|
|
39
|
-
)));
|
|
40
|
-
assert.equal(legal.size, TRANSITIONS.length, 'every transition is named once');
|
|
41
|
-
|
|
42
|
-
for (const from of allStates) {
|
|
43
|
-
for (const action of Object.values(ACTION)) {
|
|
44
|
-
for (const to of allStates) {
|
|
45
|
-
const transitionKey = key(from, action, to);
|
|
46
|
-
if (legal.has(transitionKey)) {
|
|
47
|
-
const entry = TRANSITIONS.find((candidate) => (
|
|
48
|
-
key(candidate.from, candidate.action, candidate.to) === transitionKey
|
|
49
|
-
));
|
|
50
|
-
assert.ok(entry.facts.length > 0, `${transitionKey} names its durable facts`);
|
|
51
|
-
assert.equal(
|
|
52
|
-
requireTransition(from, action, to, entry.facts),
|
|
53
|
-
entry,
|
|
54
|
-
transitionKey,
|
|
55
|
-
);
|
|
56
|
-
} else {
|
|
57
|
-
assert.throws(
|
|
58
|
-
() => requireTransition(from, action, to),
|
|
59
|
-
/illegal provenance transition/,
|
|
60
|
-
transitionKey,
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('publication substates keep numbering, folding, and physical apply distinct', () => {
|
|
69
|
-
const publication = {
|
|
70
|
-
mutationId: 'mutation_provenance_state_01',
|
|
71
|
-
numberedVersion: null,
|
|
72
|
-
numberedAt: null,
|
|
73
|
-
foldedAt: null,
|
|
74
|
-
};
|
|
75
|
-
assert.equal(publicationState(null), STATE.CAPTURED);
|
|
76
|
-
assert.equal(publicationState(publication), STATE.RESERVED);
|
|
77
|
-
assert.equal(publicationState({
|
|
78
|
-
...publication,
|
|
79
|
-
numberedVersion: 51,
|
|
80
|
-
numberedAt: '2026-07-27T00:00:00.000Z',
|
|
81
|
-
}), STATE.NUMBERED);
|
|
82
|
-
assert.equal(publicationState({
|
|
83
|
-
...publication,
|
|
84
|
-
numberedVersion: 51,
|
|
85
|
-
numberedAt: '2026-07-27T00:00:00.000Z',
|
|
86
|
-
foldedAt: '2026-07-27T00:00:01.000Z',
|
|
87
|
-
}), STATE.FOLDED);
|
|
88
|
-
|
|
89
|
-
assert.throws(
|
|
90
|
-
() => requireTransition(
|
|
91
|
-
STATE.RESERVED,
|
|
92
|
-
ACTION.NUMBER,
|
|
93
|
-
STATE.NUMBERED,
|
|
94
|
-
['publication-id', 'official-version'],
|
|
95
|
-
),
|
|
96
|
-
/server-receipt/,
|
|
97
|
-
);
|
|
98
|
-
assert.throws(
|
|
99
|
-
() => requireTransition(
|
|
100
|
-
STATE.NUMBERED,
|
|
101
|
-
ACTION.APPLY,
|
|
102
|
-
STATE.OFFICIAL,
|
|
103
|
-
[],
|
|
104
|
-
),
|
|
105
|
-
/illegal provenance transition/,
|
|
106
|
-
'numbered work must fold before physical apply',
|
|
107
|
-
);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('unknown bytes can only verify, capture, or remain unknown', () => {
|
|
111
|
-
const outgoing = TRANSITIONS
|
|
112
|
-
.filter((entry) => entry.from === STATE.UNKNOWN)
|
|
113
|
-
.map((entry) => [entry.action, entry.to])
|
|
114
|
-
.sort();
|
|
115
|
-
assert.deepEqual(outgoing, [
|
|
116
|
-
[ACTION.CAPTURE, STATE.CAPTURED],
|
|
117
|
-
[ACTION.OBSERVE_UNKNOWN, STATE.UNKNOWN],
|
|
118
|
-
[ACTION.RECOVER, STATE.UNKNOWN],
|
|
119
|
-
[ACTION.SNAPSHOT, STATE.OFFICIAL],
|
|
120
|
-
[ACTION.SNAPSHOT, STATE.UNKNOWN],
|
|
121
|
-
[ACTION.VERIFY, STATE.OFFICIAL],
|
|
122
|
-
].sort());
|
|
123
|
-
assert.equal(
|
|
124
|
-
outgoing.some(([action]) => (
|
|
125
|
-
action === ACTION.RESERVE
|
|
126
|
-
|| action === ACTION.RETRY
|
|
127
|
-
|| action === ACTION.APPLY
|
|
128
|
-
)),
|
|
129
|
-
false,
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('server compaction, local journal prune, and intent retirement are distinct', () => {
|
|
134
|
-
const prunes = TRANSITIONS.filter((entry) => entry.action === ACTION.PRUNE);
|
|
135
|
-
assert.deepEqual(prunes[0], {
|
|
136
|
-
from: STATE.FOLDED,
|
|
137
|
-
action: ACTION.PRUNE,
|
|
138
|
-
to: STATE.FOLDED,
|
|
139
|
-
facts: [
|
|
140
|
-
'official-fold',
|
|
141
|
-
'durable-folded-intent',
|
|
142
|
-
],
|
|
143
|
-
});
|
|
144
|
-
assert.deepEqual(prunes[1], {
|
|
145
|
-
from: STATE.OFFICIAL,
|
|
146
|
-
action: ACTION.PRUNE,
|
|
147
|
-
to: STATE.OFFICIAL,
|
|
148
|
-
facts: [
|
|
149
|
-
'official-fold',
|
|
150
|
-
'physical-verification',
|
|
151
|
-
'applied-cursor',
|
|
152
|
-
],
|
|
153
|
-
});
|
|
154
|
-
const compact = TRANSITIONS.find((entry) => entry.action === ACTION.COMPACT);
|
|
155
|
-
assert.deepEqual(compact.facts, [
|
|
156
|
-
'retained-server-receipt',
|
|
157
|
-
'verified-server-snapshot',
|
|
158
|
-
]);
|
|
159
|
-
const physicalApply = TRANSITIONS.find((entry) => (
|
|
160
|
-
entry.from === STATE.FOLDED
|
|
161
|
-
&& entry.action === ACTION.APPLY
|
|
162
|
-
&& entry.to === STATE.OFFICIAL
|
|
163
|
-
));
|
|
164
|
-
assert.deepEqual(physicalApply.facts.slice(-3), [
|
|
165
|
-
'physical-verification',
|
|
166
|
-
'applied-cursor',
|
|
167
|
-
'intent-retired',
|
|
168
|
-
]);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test('WAL recovery keeps source and target provenance but exposes any third value', () => {
|
|
172
|
-
for (const state of allStates.filter((candidate) => candidate !== STATE.UNKNOWN)) {
|
|
173
|
-
assert.ok(TRANSITIONS.some((entry) => (
|
|
174
|
-
entry.from === state
|
|
175
|
-
&& entry.action === ACTION.RECOVER
|
|
176
|
-
&& entry.to === state
|
|
177
|
-
)));
|
|
178
|
-
assert.ok(TRANSITIONS.some((entry) => (
|
|
179
|
-
entry.from === state
|
|
180
|
-
&& entry.action === ACTION.RECOVER
|
|
181
|
-
&& entry.to === STATE.UNKNOWN
|
|
182
|
-
&& entry.facts.includes('exact-third-value-observation')
|
|
183
|
-
)));
|
|
184
|
-
}
|
|
185
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const assert = require('node:assert/strict');
|
|
4
|
-
const test = require('node:test');
|
|
5
|
-
|
|
6
|
-
const { repairDelayForPass } = require('../workspace/reducer');
|
|
7
|
-
|
|
8
|
-
test('every non-terminal wait gets the same bounded repair retry', () => {
|
|
9
|
-
assert.equal(
|
|
10
|
-
repairDelayForPass([{ state: 'waiting', reason: 'a-new-reason-the-code-has-never-seen' }]),
|
|
11
|
-
1_000,
|
|
12
|
-
);
|
|
13
|
-
assert.equal(
|
|
14
|
-
repairDelayForPass([{ state: 'waiting', reason: 'another-reason' }]),
|
|
15
|
-
1_000,
|
|
16
|
-
);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('a materialization pass is verified again after it moves the repo', () => {
|
|
20
|
-
assert.equal(repairDelayForPass([{ state: 'in-sync' }], true), 1_000);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('settled repos and terminal corruption do not enter a fast retry loop', () => {
|
|
24
|
-
assert.equal(repairDelayForPass([{ state: 'in-sync' }]), null);
|
|
25
|
-
assert.equal(repairDelayForPass([{ state: 'error', reason: 'invalid official payload' }]), null);
|
|
26
|
-
});
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const assert = require('node:assert/strict');
|
|
4
|
-
const test = require('node:test');
|
|
5
|
-
const {
|
|
6
|
-
autoUpdateDisabled,
|
|
7
|
-
digest,
|
|
8
|
-
folderFor,
|
|
9
|
-
pendingIntentValue,
|
|
10
|
-
syncFingerprintFiles,
|
|
11
|
-
verificationFor,
|
|
12
|
-
} = require('../workspace/sync-stats')._test;
|
|
13
|
-
|
|
14
|
-
test('snapshot digest is content-derived rather than key-order-derived', () => {
|
|
15
|
-
assert.equal(
|
|
16
|
-
digest({ version: 7, records: [{ machine: 'm', cards: [] }] }),
|
|
17
|
-
digest({ records: [{ cards: [], machine: 'm' }], version: 7 }),
|
|
18
|
-
);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('registered folder UUID and exact path identify the listening checkout', () => {
|
|
22
|
-
const project = { repoKey: 'repo', path: '/code/repo' };
|
|
23
|
-
const cards = [{
|
|
24
|
-
kind: 'primary',
|
|
25
|
-
path: '/wrong',
|
|
26
|
-
repo: { remote: 'repo' },
|
|
27
|
-
}];
|
|
28
|
-
const workspaces = [{ id: 'folder-uuid', path: '/code/repo' }];
|
|
29
|
-
assert.deepEqual(folderFor(project, cards, workspaces), {
|
|
30
|
-
card: cards[0],
|
|
31
|
-
folderPath: '/code/repo',
|
|
32
|
-
folderUuid: 'folder-uuid',
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('verification exposes one pending intent and named waits without hidden branches', () => {
|
|
37
|
-
const pendingIntent = {
|
|
38
|
-
baseThrough: 4,
|
|
39
|
-
semanticDigest: 'intent',
|
|
40
|
-
mutationId: null,
|
|
41
|
-
terminalCode: null,
|
|
42
|
-
};
|
|
43
|
-
const value = verificationFor({
|
|
44
|
-
verificationContract: 'verified-repo-state@1',
|
|
45
|
-
appliedThrough: 4,
|
|
46
|
-
materialized: false,
|
|
47
|
-
targetDigest: 'target',
|
|
48
|
-
expectedPhysicalDigest: 'expected',
|
|
49
|
-
observedPhysicalDigest: 'observed',
|
|
50
|
-
}, {
|
|
51
|
-
state: 'waiting',
|
|
52
|
-
reason: 'physical-state-mismatch',
|
|
53
|
-
}, pendingIntent);
|
|
54
|
-
assert.equal(value.appliedThrough, 4);
|
|
55
|
-
assert.equal(value.materialized, false);
|
|
56
|
-
assert.equal(value.pendingIntent, pendingIntent);
|
|
57
|
-
assert.equal(Object.hasOwn(value, 'pendingCard'), false);
|
|
58
|
-
assert.equal(Object.hasOwn(value, 'pendingRefs'), false);
|
|
59
|
-
assert.equal(Object.hasOwn(value, 'pendingCheckpoint'), false);
|
|
60
|
-
assert.deepEqual(value.waiting, [
|
|
61
|
-
{ state: 'waiting', reason: 'physical-state-mismatch' },
|
|
62
|
-
]);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('verification keeps the open successor visible after its predecessor is numbered', () => {
|
|
66
|
-
assert.deepEqual(pendingIntentValue({
|
|
67
|
-
base: { through: 4 },
|
|
68
|
-
semanticDigest: 'predecessor',
|
|
69
|
-
publication: { mutationId: 'mutation-a' },
|
|
70
|
-
terminal: null,
|
|
71
|
-
successor: {
|
|
72
|
-
predecessorSemanticDigest: 'predecessor',
|
|
73
|
-
semanticDigest: 'successor',
|
|
74
|
-
terminal: null,
|
|
75
|
-
},
|
|
76
|
-
}, false), {
|
|
77
|
-
baseThrough: 4,
|
|
78
|
-
semanticDigest: 'predecessor',
|
|
79
|
-
mutationId: 'mutation-a',
|
|
80
|
-
terminalCode: null,
|
|
81
|
-
successor: {
|
|
82
|
-
predecessorSemanticDigest: 'predecessor',
|
|
83
|
-
semanticDigest: 'successor',
|
|
84
|
-
mutationId: null,
|
|
85
|
-
terminalCode: null,
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test('auto-update state reflects only the runtime launch policy', () => {
|
|
91
|
-
assert.equal(autoUpdateDisabled({ AMALGM_DISABLE_AUTO_UPDATE: '1' }), true);
|
|
92
|
-
assert.equal(autoUpdateDisabled({ AMALGM_AUTO_UPDATE: 'off' }), true);
|
|
93
|
-
assert.equal(autoUpdateDisabled({ AMALGM_AUTO_UPDATE: '1' }), false);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('the sync fingerprint follows the complete state and workspace trees', () => {
|
|
97
|
-
for (const file of [
|
|
98
|
-
'state/doc-disk.js',
|
|
99
|
-
'state/docs.js',
|
|
100
|
-
'workspace/native-file-transaction/client.js',
|
|
101
|
-
'workspace/native-file-transaction/main.go',
|
|
102
|
-
'workspace/native-file-transaction/manifest.json',
|
|
103
|
-
'workspace/transition.js',
|
|
104
|
-
]) {
|
|
105
|
-
assert.ok(syncFingerprintFiles.includes(file), `${file} must be release-bound`);
|
|
106
|
-
}
|
|
107
|
-
assert.ok(
|
|
108
|
-
syncFingerprintFiles.some((file) => (
|
|
109
|
-
file === 'workspace/native-file-transaction/bin/darwin-arm64/amalgm-file-transaction'
|
|
110
|
-
)),
|
|
111
|
-
'the Darwin helper must be release-bound',
|
|
112
|
-
);
|
|
113
|
-
assert.ok(
|
|
114
|
-
syncFingerprintFiles.some((file) => (
|
|
115
|
-
file === 'workspace/native-file-transaction/bin/linux-x64/amalgm-file-transaction'
|
|
116
|
-
)),
|
|
117
|
-
'the Linux helper must be release-bound',
|
|
118
|
-
);
|
|
119
|
-
});
|