amalgm 0.1.189 → 0.1.190
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,6 +31,7 @@ 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,
|
|
@@ -71,6 +72,60 @@ test('no commit means no shared card', () => {
|
|
|
71
72
|
assert.equal(isCommittedCard({ head: { branch: 'main', oid: 'a'.repeat(40) } }), true);
|
|
72
73
|
});
|
|
73
74
|
|
|
75
|
+
test('only a value different from both the materialized baseline and the rail is new work', () => {
|
|
76
|
+
const oidA = 'a'.repeat(40);
|
|
77
|
+
const oidB = 'b'.repeat(40);
|
|
78
|
+
const oidC = 'c'.repeat(40);
|
|
79
|
+
const local = {
|
|
80
|
+
head: { branch: 'main', oid: oidA, detached: false },
|
|
81
|
+
refs: [{ name: 'main', oid: oidA }],
|
|
82
|
+
};
|
|
83
|
+
const plan = {
|
|
84
|
+
card: { head: { branch: 'main', oid: oidA, detached: false } },
|
|
85
|
+
branches: [
|
|
86
|
+
{ name: 'main', oid: oidA },
|
|
87
|
+
{ name: 'feature', oid: oidB },
|
|
88
|
+
],
|
|
89
|
+
transitions: [],
|
|
90
|
+
};
|
|
91
|
+
const baseline = {
|
|
92
|
+
branch: 'main',
|
|
93
|
+
baseOid: oidA,
|
|
94
|
+
branches: [{ name: 'main', oid: oidA }],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
assert.equal(hasLocalContribution(local, plan, baseline), false);
|
|
98
|
+
assert.equal(hasLocalContribution({
|
|
99
|
+
...local,
|
|
100
|
+
refs: [...local.refs, { name: 'feature', oid: oidB }],
|
|
101
|
+
}, plan, baseline), false);
|
|
102
|
+
assert.equal(hasLocalContribution({
|
|
103
|
+
...local,
|
|
104
|
+
head: { branch: 'main', oid: oidC, detached: false },
|
|
105
|
+
refs: [{ name: 'main', oid: oidC }],
|
|
106
|
+
}, plan, baseline), true);
|
|
107
|
+
assert.equal(hasLocalContribution(local, plan, {
|
|
108
|
+
...baseline,
|
|
109
|
+
branches: [...baseline.branches, { name: 'feature', oid: oidB }],
|
|
110
|
+
}), true);
|
|
111
|
+
|
|
112
|
+
const remoteAdvance = {
|
|
113
|
+
...plan,
|
|
114
|
+
card: { head: { branch: 'main', oid: oidC, detached: false } },
|
|
115
|
+
branches: [{ name: 'main', oid: oidC }],
|
|
116
|
+
};
|
|
117
|
+
assert.equal(hasLocalContribution(local, remoteAdvance, baseline), false);
|
|
118
|
+
assert.equal(hasLocalContribution(local, plan, baseline, {
|
|
119
|
+
checkpoint: 'repo-checkpoint@7',
|
|
120
|
+
machine: 'machine-a',
|
|
121
|
+
branch: 'main',
|
|
122
|
+
baseOid: oidA,
|
|
123
|
+
from: { revision: null, indexDiff: '', worktreeDiff: '' },
|
|
124
|
+
to: { revision: 'local-work', indexDiff: '', worktreeDiff: 'patch' },
|
|
125
|
+
parked: [],
|
|
126
|
+
}), true);
|
|
127
|
+
});
|
|
128
|
+
|
|
74
129
|
test('a collaborator binds the same repo to the owner project, not a parallel project', () => {
|
|
75
130
|
const shared = projectResourceId('repo-shared', '22222222-2222-4222-8222-222222222222');
|
|
76
131
|
const localPath = path.join(tempRoot, 'projects/shared');
|
|
@@ -129,7 +184,7 @@ test('a repo project carries exactly one line per machine, replaced in place', a
|
|
|
129
184
|
});
|
|
130
185
|
const sealed = publishWall(repoKey);
|
|
131
186
|
assert.equal(sealed.published, false);
|
|
132
|
-
assert.equal(sealed.reason, '
|
|
187
|
+
assert.equal(sealed.reason, 'shared-state-covered');
|
|
133
188
|
const sealedCard = readWall(repoKey)[0].cards[0];
|
|
134
189
|
assert.equal(sealedCard.positionMutationId, first.mutationId);
|
|
135
190
|
assert.equal(sealedCard.positionVersion, 1);
|
|
@@ -137,7 +192,7 @@ test('a repo project carries exactly one line per machine, replaced in place', a
|
|
|
137
192
|
|
|
138
193
|
const again = publishWall(repoKey);
|
|
139
194
|
assert.equal(again.published, false);
|
|
140
|
-
assert.equal(again.reason, '
|
|
195
|
+
assert.equal(again.reason, 'shared-state-covered');
|
|
141
196
|
|
|
142
197
|
fs.writeFileSync(path.join(repo, 'new.txt'), 'x\n');
|
|
143
198
|
await refreshRepoCards();
|
|
@@ -192,6 +247,34 @@ test('checkpoint transitions append until the next card and carry their official
|
|
|
192
247
|
assert.deepEqual(history.map((entry) => entry.mutationId), [first.mutationId, second.mutationId]);
|
|
193
248
|
});
|
|
194
249
|
|
|
250
|
+
test('side branches keep one rail operation while the checked-out card advances', async () => {
|
|
251
|
+
const repo = path.join(tempRoot, 'projects/app');
|
|
252
|
+
const before = readWall(repoKey)[0].cards[0];
|
|
253
|
+
const branch = 'storm/persistent-ref';
|
|
254
|
+
|
|
255
|
+
await run(repo, 'branch', branch);
|
|
256
|
+
await refreshRepoCards();
|
|
257
|
+
const created = publishWall(repoKey);
|
|
258
|
+
assert.equal(created.published, true);
|
|
259
|
+
let card = readWall(repoKey)[0].cards[0];
|
|
260
|
+
const ref = card.branches.find((entry) => entry.name === branch);
|
|
261
|
+
assert.equal(card.positionMutationId, before.positionMutationId);
|
|
262
|
+
assert.equal(ref.mutationId, created.mutationId);
|
|
263
|
+
|
|
264
|
+
acknowledgeCloudMutation(project.resourceId, created.mutationId, {
|
|
265
|
+
version: 3,
|
|
266
|
+
committedAt: '2026-07-23T00:00:04.000Z',
|
|
267
|
+
});
|
|
268
|
+
await run(repo, 'add', 'new.txt');
|
|
269
|
+
await run(repo, 'commit', '-m', 'advance without moving side branch');
|
|
270
|
+
await refreshRepoCards();
|
|
271
|
+
const advanced = publishWall(repoKey);
|
|
272
|
+
assert.equal(advanced.published, true);
|
|
273
|
+
card = readWall(repoKey)[0].cards[0];
|
|
274
|
+
assert.equal(card.positionMutationId, advanced.mutationId);
|
|
275
|
+
assert.equal(card.branches.find((entry) => entry.name === branch).mutationId, created.mutationId);
|
|
276
|
+
});
|
|
277
|
+
|
|
195
278
|
test('a peer machine line is preserved byte-for-byte through local publishes', async () => {
|
|
196
279
|
const peerLine = JSON.stringify({
|
|
197
280
|
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,27 @@ function officialVersion(resourceId, mutationId) {
|
|
|
236
281
|
return Number.isInteger(mutation?.officialCloudVersion) ? mutation.officialCloudVersion : null;
|
|
237
282
|
}
|
|
238
283
|
|
|
239
|
-
function stampBranches(refs, previousBranches, mutationId, resourceId) {
|
|
284
|
+
function stampBranches(refs, previousBranches, sharedBranches, mutationId, resourceId) {
|
|
240
285
|
const current = new Map((refs || []).map((ref) => [ref.name, ref]));
|
|
241
286
|
const previous = new Map((previousBranches || []).map((ref) => [ref.name, ref]));
|
|
287
|
+
const shared = new Map((sharedBranches || []).map((ref) => [ref.name, ref]));
|
|
242
288
|
const names = [...new Set([...current.keys(), ...previous.keys()])].sort();
|
|
243
289
|
return names.map((name) => {
|
|
244
290
|
const observed = current.get(name);
|
|
245
291
|
const before = previous.get(name);
|
|
292
|
+
const onRail = shared.get(name);
|
|
246
293
|
const oid = observed?.oid ?? null;
|
|
247
294
|
const unchanged = before && (before.oid ?? null) === oid;
|
|
248
|
-
const
|
|
295
|
+
const previousReusable = unchanged
|
|
249
296
|
&& before.mutationId
|
|
250
297
|
&& (validVersion(before.version) || knownMutation(resourceId, before.mutationId));
|
|
251
|
-
const
|
|
298
|
+
const railReusable = onRail
|
|
299
|
+
&& (onRail.oid ?? null) === oid
|
|
300
|
+
&& onRail.mutationId
|
|
301
|
+
&& validVersion(onRail.version);
|
|
302
|
+
const mutation = previousReusable
|
|
303
|
+
? before.mutationId
|
|
304
|
+
: railReusable ? onRail.mutationId : mutationId;
|
|
252
305
|
return {
|
|
253
306
|
name,
|
|
254
307
|
oid,
|
|
@@ -279,7 +332,7 @@ function isCommittedCard(card) {
|
|
|
279
332
|
return typeof card?.head?.oid === 'string' && /^[0-9a-f]{40,64}$/.test(card.head.oid);
|
|
280
333
|
}
|
|
281
334
|
|
|
282
|
-
function stampCards(cards, previousCards, mutationId, project) {
|
|
335
|
+
function stampCards(cards, previousCards, sharedPlan, mutationId, project) {
|
|
283
336
|
const previousByReplica = new Map(
|
|
284
337
|
(previousCards || []).filter((card) => card?.replica).map((card) => [card.replica, card]),
|
|
285
338
|
);
|
|
@@ -290,8 +343,13 @@ function stampCards(cards, previousCards, mutationId, project) {
|
|
|
290
343
|
&& (
|
|
291
344
|
validVersion(previous.positionVersion)
|
|
292
345
|
|| knownMutation(project.resourceId, previous.positionMutationId)
|
|
293
|
-
|
|
294
|
-
const
|
|
346
|
+
);
|
|
347
|
+
const reusableRailPosition = samePosition(sharedPlan?.card, card)
|
|
348
|
+
&& sharedPlan.card.positionMutationId
|
|
349
|
+
&& validVersion(sharedPlan.card.positionVersion);
|
|
350
|
+
const positionMutationId = reusablePosition
|
|
351
|
+
? previous.positionMutationId
|
|
352
|
+
: reusableRailPosition ? sharedPlan.card.positionMutationId : mutationId;
|
|
295
353
|
const checkpoint = readCheckpoint(machineId(), project.repoKey);
|
|
296
354
|
const currentCheckpoint = checkpoint
|
|
297
355
|
&& checkpoint.baseOid === card.head?.oid
|
|
@@ -314,7 +372,8 @@ function stampCards(cards, previousCards, mutationId, project) {
|
|
|
314
372
|
positionMutationId,
|
|
315
373
|
branches: stampBranches(
|
|
316
374
|
card.refs,
|
|
317
|
-
|
|
375
|
+
previous?.branches,
|
|
376
|
+
sharedPlan?.branches,
|
|
318
377
|
mutationId,
|
|
319
378
|
project.resourceId,
|
|
320
379
|
),
|
|
@@ -362,8 +421,23 @@ function publishProject(project, rawCards) {
|
|
|
362
421
|
}
|
|
363
422
|
}
|
|
364
423
|
|
|
424
|
+
const reducer = require('./reducer');
|
|
425
|
+
const sharedPlan = reducer.reduceWall(readProjectWall(project)).get(project.repoKey);
|
|
426
|
+
const baseline = reducer.readRepoState(project.repoKey);
|
|
427
|
+
const previousReplicas = new Set((previousEntry?.cards || []).map((card) => card.replica));
|
|
428
|
+
const currentReplicas = new Set(rawCards.map((card) => card.replica));
|
|
429
|
+
const removed = [...previousReplicas].some((replica) => !currentReplicas.has(replica));
|
|
430
|
+
const contributes = rawCards.some((card) => {
|
|
431
|
+
const checkpoint = readCheckpoint(machineId(), project.repoKey);
|
|
432
|
+
return hasLocalContribution(card, sharedPlan, baseline, checkpoint)
|
|
433
|
+
|| hasObjectUpgrade(card, sharedPlan);
|
|
434
|
+
});
|
|
435
|
+
if (!removed && !contributes) {
|
|
436
|
+
service.counters.publishSkips += 1;
|
|
437
|
+
return { published: false, reason: 'shared-state-covered', repoKey: project.repoKey };
|
|
438
|
+
}
|
|
365
439
|
const mutationId = `mut_project_${crypto.randomBytes(16).toString('base64url')}`;
|
|
366
|
-
const cards = stampCards(rawCards, previousEntry?.cards, mutationId, project);
|
|
440
|
+
const cards = stampCards(rawCards, previousEntry?.cards, sharedPlan, mutationId, project);
|
|
367
441
|
const mine = JSON.stringify({
|
|
368
442
|
wall: WALL_CONTRACT,
|
|
369
443
|
project: project.repoKey,
|
|
@@ -566,6 +640,7 @@ function wallStats() {
|
|
|
566
640
|
module.exports = {
|
|
567
641
|
WALL_CONTRACT,
|
|
568
642
|
bindProject,
|
|
643
|
+
hasLocalContribution,
|
|
569
644
|
isCommittedCard,
|
|
570
645
|
projectFile,
|
|
571
646
|
projectForRepo,
|