amalgm 0.1.189 → 0.1.191
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/package.json
CHANGED
|
@@ -31,12 +31,14 @@ const { refreshRepoCards } = require('../workspace/cards');
|
|
|
31
31
|
const { checkpointFile, repoKeyOfCard } = require('../workspace/checkpoint');
|
|
32
32
|
const {
|
|
33
33
|
bindProject,
|
|
34
|
+
hasLocalContribution,
|
|
34
35
|
isCommittedCard,
|
|
35
36
|
projectForRepo,
|
|
36
37
|
projectResourceId,
|
|
37
38
|
publishedCardFor,
|
|
38
39
|
publishWall,
|
|
39
40
|
readWall,
|
|
41
|
+
stampCards,
|
|
40
42
|
wallStats,
|
|
41
43
|
} = require('../workspace/wall');
|
|
42
44
|
|
|
@@ -71,6 +73,115 @@ test('no commit means no shared card', () => {
|
|
|
71
73
|
assert.equal(isCommittedCard({ head: { branch: 'main', oid: 'a'.repeat(40) } }), true);
|
|
72
74
|
});
|
|
73
75
|
|
|
76
|
+
test('only a value different from both the materialized baseline and the rail is new work', () => {
|
|
77
|
+
const oidA = 'a'.repeat(40);
|
|
78
|
+
const oidB = 'b'.repeat(40);
|
|
79
|
+
const oidC = 'c'.repeat(40);
|
|
80
|
+
const local = {
|
|
81
|
+
head: { branch: 'main', oid: oidA, detached: false },
|
|
82
|
+
refs: [{ name: 'main', oid: oidA }],
|
|
83
|
+
};
|
|
84
|
+
const plan = {
|
|
85
|
+
card: { head: { branch: 'main', oid: oidA, detached: false } },
|
|
86
|
+
branches: [
|
|
87
|
+
{ name: 'main', oid: oidA },
|
|
88
|
+
{ name: 'feature', oid: oidB },
|
|
89
|
+
],
|
|
90
|
+
transitions: [],
|
|
91
|
+
};
|
|
92
|
+
const baseline = {
|
|
93
|
+
branch: 'main',
|
|
94
|
+
baseOid: oidA,
|
|
95
|
+
branches: [{ name: 'main', oid: oidA }],
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
assert.equal(hasLocalContribution(local, plan, baseline), false);
|
|
99
|
+
assert.equal(hasLocalContribution({
|
|
100
|
+
...local,
|
|
101
|
+
refs: [...local.refs, { name: 'feature', oid: oidB }],
|
|
102
|
+
}, plan, baseline), false);
|
|
103
|
+
assert.equal(hasLocalContribution({
|
|
104
|
+
...local,
|
|
105
|
+
head: { branch: 'main', oid: oidC, detached: false },
|
|
106
|
+
refs: [{ name: 'main', oid: oidC }],
|
|
107
|
+
}, plan, baseline), true);
|
|
108
|
+
assert.equal(hasLocalContribution(local, plan, {
|
|
109
|
+
...baseline,
|
|
110
|
+
branches: [...baseline.branches, { name: 'feature', oid: oidB }],
|
|
111
|
+
}), true);
|
|
112
|
+
|
|
113
|
+
const remoteAdvance = {
|
|
114
|
+
...plan,
|
|
115
|
+
card: { head: { branch: 'main', oid: oidC, detached: false } },
|
|
116
|
+
branches: [{ name: 'main', oid: oidC }],
|
|
117
|
+
};
|
|
118
|
+
assert.equal(hasLocalContribution(local, remoteAdvance, baseline), false);
|
|
119
|
+
assert.equal(hasLocalContribution(local, plan, baseline, {
|
|
120
|
+
checkpoint: 'repo-checkpoint@7',
|
|
121
|
+
machine: 'machine-a',
|
|
122
|
+
branch: 'main',
|
|
123
|
+
baseOid: oidA,
|
|
124
|
+
from: { revision: null, indexDiff: '', worktreeDiff: '' },
|
|
125
|
+
to: { revision: 'local-work', indexDiff: '', worktreeDiff: 'patch' },
|
|
126
|
+
parked: [],
|
|
127
|
+
}), true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('checkpoint work on the materialized baseline keeps the baseline card and branch numbers', () => {
|
|
131
|
+
const baselineOid = 'a'.repeat(40);
|
|
132
|
+
const railOid = 'b'.repeat(40);
|
|
133
|
+
const card = {
|
|
134
|
+
card: 'repo-card@2',
|
|
135
|
+
machine: 'machine-a',
|
|
136
|
+
replica: 'rpl_baseline',
|
|
137
|
+
kind: 'primary',
|
|
138
|
+
head: { branch: 'main', oid: baselineOid, detached: false },
|
|
139
|
+
refs: [{ name: 'main', oid: baselineOid }],
|
|
140
|
+
health: 'healthy',
|
|
141
|
+
};
|
|
142
|
+
const stamped = stampCards(
|
|
143
|
+
[card],
|
|
144
|
+
[{
|
|
145
|
+
...card,
|
|
146
|
+
head: { branch: 'old', oid: 'c'.repeat(40), detached: false },
|
|
147
|
+
positionMutationId: 'mut_stale_card_01',
|
|
148
|
+
positionVersion: 8,
|
|
149
|
+
branches: [],
|
|
150
|
+
}],
|
|
151
|
+
{
|
|
152
|
+
card: {
|
|
153
|
+
...card,
|
|
154
|
+
head: { branch: 'main', oid: railOid, detached: false },
|
|
155
|
+
positionMutationId: 'mut_winning_card1',
|
|
156
|
+
positionVersion: 12,
|
|
157
|
+
},
|
|
158
|
+
branches: [{
|
|
159
|
+
name: 'main',
|
|
160
|
+
oid: railOid,
|
|
161
|
+
mutationId: 'mut_winning_ref01',
|
|
162
|
+
version: 12,
|
|
163
|
+
}],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
branch: 'main',
|
|
167
|
+
baseOid: baselineOid,
|
|
168
|
+
cardMutationId: 'mut_baseline_card',
|
|
169
|
+
cardVersion: 9,
|
|
170
|
+
branches: [{
|
|
171
|
+
name: 'main',
|
|
172
|
+
oid: baselineOid,
|
|
173
|
+
mutationId: 'mut_baseline_ref1',
|
|
174
|
+
version: 9,
|
|
175
|
+
}],
|
|
176
|
+
},
|
|
177
|
+
'mut_checkpoint_only',
|
|
178
|
+
{ repoKey: 'root:baseline-stamp', resourceId: 'shr_baseline_stamp_test' },
|
|
179
|
+
)[0];
|
|
180
|
+
|
|
181
|
+
assert.equal(stamped.positionMutationId, 'mut_baseline_card');
|
|
182
|
+
assert.equal(stamped.branches[0].mutationId, 'mut_baseline_ref1');
|
|
183
|
+
});
|
|
184
|
+
|
|
74
185
|
test('a collaborator binds the same repo to the owner project, not a parallel project', () => {
|
|
75
186
|
const shared = projectResourceId('repo-shared', '22222222-2222-4222-8222-222222222222');
|
|
76
187
|
const localPath = path.join(tempRoot, 'projects/shared');
|
|
@@ -129,7 +240,7 @@ test('a repo project carries exactly one line per machine, replaced in place', a
|
|
|
129
240
|
});
|
|
130
241
|
const sealed = publishWall(repoKey);
|
|
131
242
|
assert.equal(sealed.published, false);
|
|
132
|
-
assert.equal(sealed.reason, '
|
|
243
|
+
assert.equal(sealed.reason, 'shared-state-covered');
|
|
133
244
|
const sealedCard = readWall(repoKey)[0].cards[0];
|
|
134
245
|
assert.equal(sealedCard.positionMutationId, first.mutationId);
|
|
135
246
|
assert.equal(sealedCard.positionVersion, 1);
|
|
@@ -137,7 +248,7 @@ test('a repo project carries exactly one line per machine, replaced in place', a
|
|
|
137
248
|
|
|
138
249
|
const again = publishWall(repoKey);
|
|
139
250
|
assert.equal(again.published, false);
|
|
140
|
-
assert.equal(again.reason, '
|
|
251
|
+
assert.equal(again.reason, 'shared-state-covered');
|
|
141
252
|
|
|
142
253
|
fs.writeFileSync(path.join(repo, 'new.txt'), 'x\n');
|
|
143
254
|
await refreshRepoCards();
|
|
@@ -192,6 +303,34 @@ test('checkpoint transitions append until the next card and carry their official
|
|
|
192
303
|
assert.deepEqual(history.map((entry) => entry.mutationId), [first.mutationId, second.mutationId]);
|
|
193
304
|
});
|
|
194
305
|
|
|
306
|
+
test('side branches keep one rail operation while the checked-out card advances', async () => {
|
|
307
|
+
const repo = path.join(tempRoot, 'projects/app');
|
|
308
|
+
const before = readWall(repoKey)[0].cards[0];
|
|
309
|
+
const branch = 'storm/persistent-ref';
|
|
310
|
+
|
|
311
|
+
await run(repo, 'branch', branch);
|
|
312
|
+
await refreshRepoCards();
|
|
313
|
+
const created = publishWall(repoKey);
|
|
314
|
+
assert.equal(created.published, true);
|
|
315
|
+
let card = readWall(repoKey)[0].cards[0];
|
|
316
|
+
const ref = card.branches.find((entry) => entry.name === branch);
|
|
317
|
+
assert.equal(card.positionMutationId, before.positionMutationId);
|
|
318
|
+
assert.equal(ref.mutationId, created.mutationId);
|
|
319
|
+
|
|
320
|
+
acknowledgeCloudMutation(project.resourceId, created.mutationId, {
|
|
321
|
+
version: 3,
|
|
322
|
+
committedAt: '2026-07-23T00:00:04.000Z',
|
|
323
|
+
});
|
|
324
|
+
await run(repo, 'add', 'new.txt');
|
|
325
|
+
await run(repo, 'commit', '-m', 'advance without moving side branch');
|
|
326
|
+
await refreshRepoCards();
|
|
327
|
+
const advanced = publishWall(repoKey);
|
|
328
|
+
assert.equal(advanced.published, true);
|
|
329
|
+
card = readWall(repoKey)[0].cards[0];
|
|
330
|
+
assert.equal(card.positionMutationId, advanced.mutationId);
|
|
331
|
+
assert.equal(card.branches.find((entry) => entry.name === branch).mutationId, created.mutationId);
|
|
332
|
+
});
|
|
333
|
+
|
|
195
334
|
test('a peer machine line is preserved byte-for-byte through local publishes', async () => {
|
|
196
335
|
const peerLine = JSON.stringify({
|
|
197
336
|
wall: 'code-project@3',
|
|
@@ -197,17 +197,9 @@ function publishedCardFor(card) {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
function samePosition(left, right) {
|
|
200
|
-
|
|
200
|
+
return left?.head?.branch === right?.head?.branch
|
|
201
201
|
&& left?.head?.oid === right?.head?.oid
|
|
202
202
|
&& Boolean(left?.head?.detached) === Boolean(right?.head?.detached);
|
|
203
|
-
if (!sameHead) return false;
|
|
204
|
-
const previousRefs = new Map((left?.branches || []).map((ref) => [ref.name, ref.oid ?? null]));
|
|
205
|
-
const currentRefs = new Map((right?.refs || []).map((ref) => [ref.name, ref.oid]));
|
|
206
|
-
const names = new Set([...previousRefs.keys(), ...currentRefs.keys()]);
|
|
207
|
-
for (const name of names) {
|
|
208
|
-
if ((previousRefs.get(name) ?? null) !== (currentRefs.get(name) ?? null)) return false;
|
|
209
|
-
}
|
|
210
|
-
return true;
|
|
211
203
|
}
|
|
212
204
|
|
|
213
205
|
function checkpointIdentity(checkpoint) {
|
|
@@ -221,6 +213,59 @@ function checkpointIdentity(checkpoint) {
|
|
|
221
213
|
});
|
|
222
214
|
}
|
|
223
215
|
|
|
216
|
+
function oidMap(refs) {
|
|
217
|
+
return new Map((refs || []).map((ref) => [ref.name, ref.oid ?? null]));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Publishing is a transition from the last shared state this checkout
|
|
222
|
+
* materialized. A local value equal to either that baseline or the current
|
|
223
|
+
* rail is not new work. Anything else is a local contribution.
|
|
224
|
+
*/
|
|
225
|
+
function hasLocalContribution(card, plan, baseline, checkpoint = null) {
|
|
226
|
+
if (!plan?.card) return true;
|
|
227
|
+
const onRail = samePosition(card, plan.card);
|
|
228
|
+
const atBaseline = baseline
|
|
229
|
+
&& card.head?.branch === baseline.branch
|
|
230
|
+
&& card.head?.oid === baseline.baseOid;
|
|
231
|
+
if (!onRail && !atBaseline) return true;
|
|
232
|
+
|
|
233
|
+
const currentRefs = oidMap(card.refs);
|
|
234
|
+
const railRefs = oidMap(plan.branches);
|
|
235
|
+
const baselineRefs = oidMap(baseline?.branches);
|
|
236
|
+
for (const name of new Set([...currentRefs.keys(), ...baselineRefs.keys()])) {
|
|
237
|
+
const current = currentRefs.get(name) ?? null;
|
|
238
|
+
const shared = railRefs.get(name) ?? null;
|
|
239
|
+
const previous = baselineRefs.get(name) ?? null;
|
|
240
|
+
if (current !== shared && (!baselineRefs.has(name) || current !== previous)) return true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (
|
|
244
|
+
checkpoint
|
|
245
|
+
&& checkpoint.baseOid === card.head?.oid
|
|
246
|
+
&& checkpoint.branch === card.head?.branch
|
|
247
|
+
) {
|
|
248
|
+
const latest = [...(plan.transitions || [])]
|
|
249
|
+
.reverse()
|
|
250
|
+
.find((entry) => entry.machine === checkpoint.machine);
|
|
251
|
+
if (checkpointIdentity(latest) !== checkpointIdentity(checkpoint)) return true;
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function hasObjectUpgrade(card, plan) {
|
|
257
|
+
if (!plan?.card || !samePosition(card, plan.card)) return false;
|
|
258
|
+
if (card.objects?.kind === 'bundle' && plan.card.objects?.kind !== 'bundle') return true;
|
|
259
|
+
const shared = new Map((plan.branches || []).map((ref) => [ref.name, ref]));
|
|
260
|
+
return (card.refs || []).some((ref) => {
|
|
261
|
+
const onRail = shared.get(ref.name);
|
|
262
|
+
return onRail
|
|
263
|
+
&& onRail.oid === ref.oid
|
|
264
|
+
&& ref.objects?.kind === 'bundle'
|
|
265
|
+
&& onRail.objects?.kind !== 'bundle';
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
224
269
|
function validVersion(value) {
|
|
225
270
|
return Number.isInteger(value) && value > 0;
|
|
226
271
|
}
|
|
@@ -236,19 +281,42 @@ function officialVersion(resourceId, mutationId) {
|
|
|
236
281
|
return Number.isInteger(mutation?.officialCloudVersion) ? mutation.officialCloudVersion : null;
|
|
237
282
|
}
|
|
238
283
|
|
|
239
|
-
function stampBranches(
|
|
284
|
+
function stampBranches(
|
|
285
|
+
refs,
|
|
286
|
+
previousBranches,
|
|
287
|
+
sharedBranches,
|
|
288
|
+
baselineBranches,
|
|
289
|
+
mutationId,
|
|
290
|
+
resourceId,
|
|
291
|
+
) {
|
|
240
292
|
const current = new Map((refs || []).map((ref) => [ref.name, ref]));
|
|
241
293
|
const previous = new Map((previousBranches || []).map((ref) => [ref.name, ref]));
|
|
294
|
+
const shared = new Map((sharedBranches || []).map((ref) => [ref.name, ref]));
|
|
295
|
+
const baseline = new Map((baselineBranches || []).map((ref) => [ref.name, ref]));
|
|
242
296
|
const names = [...new Set([...current.keys(), ...previous.keys()])].sort();
|
|
243
297
|
return names.map((name) => {
|
|
244
298
|
const observed = current.get(name);
|
|
245
299
|
const before = previous.get(name);
|
|
300
|
+
const onRail = shared.get(name);
|
|
301
|
+
const materialized = baseline.get(name);
|
|
246
302
|
const oid = observed?.oid ?? null;
|
|
247
303
|
const unchanged = before && (before.oid ?? null) === oid;
|
|
248
|
-
const
|
|
304
|
+
const previousReusable = unchanged
|
|
249
305
|
&& before.mutationId
|
|
250
306
|
&& (validVersion(before.version) || knownMutation(resourceId, before.mutationId));
|
|
251
|
-
const
|
|
307
|
+
const railReusable = onRail
|
|
308
|
+
&& (onRail.oid ?? null) === oid
|
|
309
|
+
&& onRail.mutationId
|
|
310
|
+
&& validVersion(onRail.version);
|
|
311
|
+
const baselineReusable = materialized
|
|
312
|
+
&& (materialized.oid ?? null) === oid
|
|
313
|
+
&& materialized.mutationId
|
|
314
|
+
&& validVersion(materialized.version);
|
|
315
|
+
const mutation = previousReusable
|
|
316
|
+
? before.mutationId
|
|
317
|
+
: railReusable
|
|
318
|
+
? onRail.mutationId
|
|
319
|
+
: baselineReusable ? materialized.mutationId : mutationId;
|
|
252
320
|
return {
|
|
253
321
|
name,
|
|
254
322
|
oid,
|
|
@@ -279,7 +347,7 @@ function isCommittedCard(card) {
|
|
|
279
347
|
return typeof card?.head?.oid === 'string' && /^[0-9a-f]{40,64}$/.test(card.head.oid);
|
|
280
348
|
}
|
|
281
349
|
|
|
282
|
-
function stampCards(cards, previousCards, mutationId, project) {
|
|
350
|
+
function stampCards(cards, previousCards, sharedPlan, baseline, mutationId, project) {
|
|
283
351
|
const previousByReplica = new Map(
|
|
284
352
|
(previousCards || []).filter((card) => card?.replica).map((card) => [card.replica, card]),
|
|
285
353
|
);
|
|
@@ -290,8 +358,20 @@ function stampCards(cards, previousCards, mutationId, project) {
|
|
|
290
358
|
&& (
|
|
291
359
|
validVersion(previous.positionVersion)
|
|
292
360
|
|| knownMutation(project.resourceId, previous.positionMutationId)
|
|
293
|
-
|
|
294
|
-
const
|
|
361
|
+
);
|
|
362
|
+
const reusableRailPosition = samePosition(sharedPlan?.card, card)
|
|
363
|
+
&& sharedPlan.card.positionMutationId
|
|
364
|
+
&& validVersion(sharedPlan.card.positionVersion);
|
|
365
|
+
const reusableBaselinePosition = baseline
|
|
366
|
+
&& card.head?.branch === baseline.branch
|
|
367
|
+
&& card.head?.oid === baseline.baseOid
|
|
368
|
+
&& baseline.cardMutationId
|
|
369
|
+
&& validVersion(baseline.cardVersion);
|
|
370
|
+
const positionMutationId = reusablePosition
|
|
371
|
+
? previous.positionMutationId
|
|
372
|
+
: reusableRailPosition
|
|
373
|
+
? sharedPlan.card.positionMutationId
|
|
374
|
+
: reusableBaselinePosition ? baseline.cardMutationId : mutationId;
|
|
295
375
|
const checkpoint = readCheckpoint(machineId(), project.repoKey);
|
|
296
376
|
const currentCheckpoint = checkpoint
|
|
297
377
|
&& checkpoint.baseOid === card.head?.oid
|
|
@@ -314,7 +394,9 @@ function stampCards(cards, previousCards, mutationId, project) {
|
|
|
314
394
|
positionMutationId,
|
|
315
395
|
branches: stampBranches(
|
|
316
396
|
card.refs,
|
|
317
|
-
|
|
397
|
+
previous?.branches,
|
|
398
|
+
sharedPlan?.branches,
|
|
399
|
+
baseline?.branches,
|
|
318
400
|
mutationId,
|
|
319
401
|
project.resourceId,
|
|
320
402
|
),
|
|
@@ -362,8 +444,30 @@ function publishProject(project, rawCards) {
|
|
|
362
444
|
}
|
|
363
445
|
}
|
|
364
446
|
|
|
447
|
+
const reducer = require('./reducer');
|
|
448
|
+
const sharedPlan = reducer.reduceWall(readProjectWall(project)).get(project.repoKey);
|
|
449
|
+
const baseline = reducer.readRepoState(project.repoKey);
|
|
450
|
+
const previousReplicas = new Set((previousEntry?.cards || []).map((card) => card.replica));
|
|
451
|
+
const currentReplicas = new Set(rawCards.map((card) => card.replica));
|
|
452
|
+
const removed = [...previousReplicas].some((replica) => !currentReplicas.has(replica));
|
|
453
|
+
const contributes = rawCards.some((card) => {
|
|
454
|
+
const checkpoint = readCheckpoint(machineId(), project.repoKey);
|
|
455
|
+
return hasLocalContribution(card, sharedPlan, baseline, checkpoint)
|
|
456
|
+
|| hasObjectUpgrade(card, sharedPlan);
|
|
457
|
+
});
|
|
458
|
+
if (!removed && !contributes) {
|
|
459
|
+
service.counters.publishSkips += 1;
|
|
460
|
+
return { published: false, reason: 'shared-state-covered', repoKey: project.repoKey };
|
|
461
|
+
}
|
|
365
462
|
const mutationId = `mut_project_${crypto.randomBytes(16).toString('base64url')}`;
|
|
366
|
-
const cards = stampCards(
|
|
463
|
+
const cards = stampCards(
|
|
464
|
+
rawCards,
|
|
465
|
+
previousEntry?.cards,
|
|
466
|
+
sharedPlan,
|
|
467
|
+
baseline,
|
|
468
|
+
mutationId,
|
|
469
|
+
project,
|
|
470
|
+
);
|
|
367
471
|
const mine = JSON.stringify({
|
|
368
472
|
wall: WALL_CONTRACT,
|
|
369
473
|
project: project.repoKey,
|
|
@@ -566,6 +670,7 @@ function wallStats() {
|
|
|
566
670
|
module.exports = {
|
|
567
671
|
WALL_CONTRACT,
|
|
568
672
|
bindProject,
|
|
673
|
+
hasLocalContribution,
|
|
569
674
|
isCommittedCard,
|
|
570
675
|
projectFile,
|
|
571
676
|
projectForRepo,
|
|
@@ -573,6 +678,7 @@ module.exports = {
|
|
|
573
678
|
publishedCardFor,
|
|
574
679
|
publishWall,
|
|
575
680
|
readWall,
|
|
681
|
+
stampCards,
|
|
576
682
|
startWallService,
|
|
577
683
|
stopWallService,
|
|
578
684
|
wallStats,
|