@lmzhen/dsh-evolution-merge 0.47.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +175 -758
- package/lib/types/adapters/engine-screen.d.ts +0 -3
- package/lib/types/authoring-flow.d.ts +5 -0
- package/lib/types/authoring-flow.js +17 -10
- package/lib/types/commit-execute.js +1 -22
- package/lib/types/contracts.d.ts +0 -1
- package/lib/types/contracts.js +0 -1
- package/lib/types/doctor.d.ts +0 -1
- package/lib/types/doctor.js +2 -31
- package/lib/types/domain/consistency.d.ts +0 -1
- package/lib/types/domain/consistency.js +2 -11
- package/lib/types/domain/merge-limits.d.ts +0 -10
- package/lib/types/domain/merge-limits.js +0 -3
- package/lib/types/domain/merge-snapshot.js +4 -6
- package/lib/types/domain/pair-ledger.d.ts +0 -1
- package/lib/types/domain/row-v3.d.ts +0 -45
- package/lib/types/domain/row-v3.js +0 -68
- package/lib/types/domain/row.d.ts +2 -84
- package/lib/types/domain/row.js +1 -110
- package/lib/types/domain/run-coordinator.d.ts +0 -24
- package/lib/types/domain/run-coordinator.js +0 -1
- package/lib/types/domain/stage-aggregate.d.ts +0 -42
- package/lib/types/domain/stage-aggregate.js +1 -116
- package/lib/types/domain/state.d.ts +1 -53
- package/lib/types/domain/state.js +0 -55
- package/lib/types/domain/undo-journal.d.ts +4 -4
- package/lib/types/domain/undo-journal.js +5 -7
- package/lib/types/index.d.ts +0 -1
- package/lib/types/index.js +0 -1
- package/lib/types/new-child-authoring.js +4 -10
- package/lib/types/prompts.d.ts +0 -1
- package/lib/types/prompts.js +0 -1
- package/lib/types/read-commands.d.ts +0 -1
- package/lib/types/read-commands.js +0 -4
- package/lib/types/recovery-projection.js +0 -3
- package/lib/types/round2-outcome.js +15 -37
- package/lib/types/scan-run.js +0 -3
- package/lib/types/skipped.d.ts +1 -2
- package/lib/types/skipped.js +0 -8
- package/lib/types/staging.d.ts +0 -2
- package/lib/types/staging.js +0 -9
- package/lib/types/state.d.ts +0 -2
- package/lib/types/state.js +0 -13
- package/lib/types/surface/merge-view.d.ts +1 -2
- package/lib/types/surface/merge-view.js +0 -1
- package/lib/types/undo-operation.js +0 -9
- package/lib/types/unit-protocol.d.ts +6 -0
- package/lib/types/unit-protocol.js +72 -102
- package/package.json +4 -4
- package/lib/types/commit-recovery.d.ts +0 -14
- package/lib/types/commit-recovery.js +0 -96
- package/lib/types/coordinator.d.ts +0 -77
- package/lib/types/coordinator.js +0 -137
- package/lib/types/domain/commit-journal-store.d.ts +0 -6
- package/lib/types/domain/commit-journal-store.js +0 -26
- package/lib/types/domain/commit-journal.d.ts +0 -16
- package/lib/types/domain/commit-journal.js +0 -26
- package/lib/types/domain/indexes.d.ts +0 -21
- package/lib/types/domain/indexes.js +0 -15
- package/lib/types/domain/merge-report.d.ts +0 -41
- package/lib/types/domain/merge-report.js +0 -2
- package/lib/types/domain/pair-index-store.d.ts +0 -6
- package/lib/types/domain/pair-index-store.js +0 -25
- package/lib/types/domain/pair-index.d.ts +0 -9
- package/lib/types/domain/pair-index.js +0 -28
- package/lib/types/domain/resolve-pair.d.ts +0 -4
- package/lib/types/domain/resolve-pair.js +0 -4
- package/lib/types/domain/row-tx.d.ts +0 -27
- package/lib/types/domain/row-tx.js +0 -31
- package/lib/types/domain/run-record.d.ts +0 -45
- package/lib/types/domain/run-record.js +0 -24
- package/lib/types/domain/state-v3.d.ts +0 -4
- package/lib/types/domain/state-v3.js +0 -4
package/lib/index.js
CHANGED
|
@@ -148,12 +148,6 @@ const MERGE_PAIR_STATES = [
|
|
|
148
148
|
"fuse",
|
|
149
149
|
"skipped"
|
|
150
150
|
];
|
|
151
|
-
const MERGE_QUEUES = [
|
|
152
|
-
"verify",
|
|
153
|
-
"pending",
|
|
154
|
-
"fuse",
|
|
155
|
-
"skipped"
|
|
156
|
-
];
|
|
157
151
|
/** User-facing queue of one data state. verify/fuse share retry, not two tabs. */
|
|
158
152
|
function queueOf(state) {
|
|
159
153
|
switch (state) {
|
|
@@ -1346,17 +1340,6 @@ async function loadMergeState(io, home) {
|
|
|
1346
1340
|
...parsed.note === void 0 ? {} : { note: parsed.note }
|
|
1347
1341
|
};
|
|
1348
1342
|
}
|
|
1349
|
-
/** Schema probe for doctor; the only other reader of mergeStatePath. */
|
|
1350
|
-
async function loadStateSchema(io, home) {
|
|
1351
|
-
try {
|
|
1352
|
-
const raw = await io.readText(mergeStatePath(home));
|
|
1353
|
-
if (raw === null) return null;
|
|
1354
|
-
const parsed = JSON.parse(raw);
|
|
1355
|
-
return typeof parsed.schemaVersion === "number" ? parsed.schemaVersion : null;
|
|
1356
|
-
} catch {
|
|
1357
|
-
return null;
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
1343
|
async function rowsOf(io, home, queue) {
|
|
1361
1344
|
const loaded = await loadMergeState(io, home);
|
|
1362
1345
|
return queue === void 0 ? loaded.state.rows : loaded.state.rows.filter((row) => row.queue === queue);
|
|
@@ -1619,7 +1602,7 @@ function v3State(body) {
|
|
|
1619
1602
|
rows
|
|
1620
1603
|
};
|
|
1621
1604
|
}
|
|
1622
|
-
async function readJournal
|
|
1605
|
+
async function readJournal(io, home) {
|
|
1623
1606
|
const raw = await readTextOrNull(io, migrationJournalPath(home));
|
|
1624
1607
|
if (raw === null) return null;
|
|
1625
1608
|
try {
|
|
@@ -1696,7 +1679,7 @@ async function readStateReadiness(io, home) {
|
|
|
1696
1679
|
if (version === 3) {
|
|
1697
1680
|
const state = v3State(body);
|
|
1698
1681
|
if (state === null) return blocked("merge-state-needs-repair", "v3 state has an invalid row");
|
|
1699
|
-
const journal = await readJournal
|
|
1682
|
+
const journal = await readJournal(io, home);
|
|
1700
1683
|
const report = await readReport(io, home);
|
|
1701
1684
|
const marker = readMarker(body);
|
|
1702
1685
|
if (body.migration !== void 0 && marker === null) return blocked("merge-state-needs-repair", "migration marker is invalid");
|
|
@@ -1755,7 +1738,7 @@ async function ensureMergeStateReady(io, home, fence) {
|
|
|
1755
1738
|
outcome = blocked("merge-state-needs-repair", "v3 state has an invalid row");
|
|
1756
1739
|
return current;
|
|
1757
1740
|
}
|
|
1758
|
-
const journal = await readJournal
|
|
1741
|
+
const journal = await readJournal(io, home);
|
|
1759
1742
|
if (journal !== null) {
|
|
1760
1743
|
outcome = await completeJournal(io, home, journal, current);
|
|
1761
1744
|
return current;
|
|
@@ -2000,15 +1983,6 @@ async function readStaging(io, home, runId) {
|
|
|
2000
1983
|
return probeUnknown("staging manifest is not JSON: " + (error instanceof Error ? error.message : String(error)));
|
|
2001
1984
|
}
|
|
2002
1985
|
}
|
|
2003
|
-
async function ensureStaging(io, home, input) {
|
|
2004
|
-
const existing = await readStaging(io, home, input.runId);
|
|
2005
|
-
if (existing.kind === "present") return {
|
|
2006
|
-
ok: true,
|
|
2007
|
-
path: stagingRoot(home, input.runId),
|
|
2008
|
-
manifest: existing.value.manifest
|
|
2009
|
-
};
|
|
2010
|
-
return createStaging(io, home, input);
|
|
2011
|
-
}
|
|
2012
1986
|
async function setStagingTarget(io, home, stageKey, target, mode) {
|
|
2013
1987
|
const view = await readStaging(io, home, stageKey);
|
|
2014
1988
|
if (view.kind !== "present") return false;
|
|
@@ -2016,9 +1990,6 @@ async function setStagingTarget(io, home, stageKey, target, mode) {
|
|
|
2016
1990
|
await io.writeText(join(stagingRoot(home, stageKey), "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
2017
1991
|
return true;
|
|
2018
1992
|
}
|
|
2019
|
-
async function dropStaging(io, home, stageKey) {
|
|
2020
|
-
await io.remove(stagingRoot(home, stageKey));
|
|
2021
|
-
}
|
|
2022
1993
|
/** Remove expired run-level staging trees; `keep` names runs a live row still points at. */
|
|
2023
1994
|
async function cleanupExpiredStaging(io, home, now, keep = /* @__PURE__ */ new Set()) {
|
|
2024
1995
|
let runs;
|
|
@@ -2175,6 +2146,7 @@ async function adoptLegacyProduction(io, home) {
|
|
|
2175
2146
|
wrote
|
|
2176
2147
|
};
|
|
2177
2148
|
}
|
|
2149
|
+
/** Production stage-tree facade. These wrappers keep the low-level tree module private to StageAggregate. */
|
|
2178
2150
|
async function createStageTree(io, home, input) {
|
|
2179
2151
|
return await createStaging(io, home, input);
|
|
2180
2152
|
}
|
|
@@ -2447,61 +2419,6 @@ async function readPairLedgerV4(io, home) {
|
|
|
2447
2419
|
};
|
|
2448
2420
|
}
|
|
2449
2421
|
//#endregion
|
|
2450
|
-
//#region lib/types/domain/pair-index.js
|
|
2451
|
-
function parsePairIndex(raw) {
|
|
2452
|
-
const index = /* @__PURE__ */ new Map();
|
|
2453
|
-
if (raw === null) return index;
|
|
2454
|
-
let parsed;
|
|
2455
|
-
try {
|
|
2456
|
-
parsed = JSON.parse(raw);
|
|
2457
|
-
} catch {
|
|
2458
|
-
return index;
|
|
2459
|
-
}
|
|
2460
|
-
const body = parsed;
|
|
2461
|
-
if (!Array.isArray(body.entries)) return index;
|
|
2462
|
-
for (const value of body.entries) {
|
|
2463
|
-
const entry = value;
|
|
2464
|
-
if (typeof entry.pairKey !== "string" || typeof entry.runId !== "string" || typeof entry.result !== "string") continue;
|
|
2465
|
-
if (![
|
|
2466
|
-
"merged",
|
|
2467
|
-
"kept",
|
|
2468
|
-
"failed",
|
|
2469
|
-
"cancelled",
|
|
2470
|
-
"undone"
|
|
2471
|
-
].includes(entry.result)) continue;
|
|
2472
|
-
index.set(entry.pairKey, entry);
|
|
2473
|
-
}
|
|
2474
|
-
return index;
|
|
2475
|
-
}
|
|
2476
|
-
function serializePairIndex(index) {
|
|
2477
|
-
return JSON.stringify({
|
|
2478
|
-
schemaVersion: 1,
|
|
2479
|
-
entries: [...index.values()]
|
|
2480
|
-
}, null, 2);
|
|
2481
|
-
}
|
|
2482
|
-
//#endregion
|
|
2483
|
-
//#region lib/types/domain/pair-index-store.js
|
|
2484
|
-
/** Durable pairKey index at <home>/merge/pair-index.json. */
|
|
2485
|
-
function pairIndexPath(home) {
|
|
2486
|
-
return join(home, "merge", "pair-index.json");
|
|
2487
|
-
}
|
|
2488
|
-
async function loadPairIndex(io, home) {
|
|
2489
|
-
let raw = null;
|
|
2490
|
-
try {
|
|
2491
|
-
raw = await io.readText(pairIndexPath(home));
|
|
2492
|
-
} catch {
|
|
2493
|
-
return /* @__PURE__ */ new Map();
|
|
2494
|
-
}
|
|
2495
|
-
return parsePairIndex(raw);
|
|
2496
|
-
}
|
|
2497
|
-
async function recordPair(io, home, entry) {
|
|
2498
|
-
await transactIo(io, pairIndexPath(home), (current) => {
|
|
2499
|
-
const index = parsePairIndex(current);
|
|
2500
|
-
index.set(entry.pairKey, entry);
|
|
2501
|
-
return serializePairIndex(index);
|
|
2502
|
-
});
|
|
2503
|
-
}
|
|
2504
|
-
//#endregion
|
|
2505
2422
|
//#region lib/types/domain/run-coordinator.js
|
|
2506
2423
|
/** 1b-1 additive types for the merge run lifecycle; no writer is active in this phase. */
|
|
2507
2424
|
function runMetaPath(home, runId) {
|
|
@@ -2908,19 +2825,18 @@ async function readMergeSnapshot(options) {
|
|
|
2908
2825
|
});
|
|
2909
2826
|
bodyRefs.push(...bodies);
|
|
2910
2827
|
}
|
|
2911
|
-
const pairIndex = await loadPairIndex(options.io, options.home);
|
|
2912
2828
|
const runs = [];
|
|
2913
2829
|
for (const record of options.runs) {
|
|
2914
2830
|
const meta = await readRunMeta(options.io, options.home, record.id);
|
|
2915
|
-
const pairs = [...pairIndex.values()].filter((item) => item.runId === record.id).map((item) => ({
|
|
2916
|
-
pairKey: item.pairKey,
|
|
2917
|
-
runId: item.runId,
|
|
2918
|
-
result: item.result,
|
|
2919
|
-
...item.target === void 0 ? {} : { target: item.target }
|
|
2920
|
-
}));
|
|
2921
2831
|
const reportPath = mergeReportPath(options.home, record.id);
|
|
2922
2832
|
const probe = await readMergeReport(options.io, options.home, record.id);
|
|
2923
2833
|
const report = probe.kind === "present" ? probe.value : null;
|
|
2834
|
+
const pairs = (report?.pairs ?? []).map((pair) => ({
|
|
2835
|
+
pairKey: pair.pairKey,
|
|
2836
|
+
runId: record.id,
|
|
2837
|
+
result: pair.outcome,
|
|
2838
|
+
...pair.target === void 0 ? {} : { target: pair.target.requested }
|
|
2839
|
+
}));
|
|
2924
2840
|
runs.push({
|
|
2925
2841
|
record,
|
|
2926
2842
|
meta,
|
|
@@ -2992,8 +2908,9 @@ async function readMergeSnapshot(options) {
|
|
|
2992
2908
|
})).digest("hex");
|
|
2993
2909
|
const notes = [...options.notes ?? []];
|
|
2994
2910
|
if (historyDegraded) notes.push("history archive port unavailable; receipts only");
|
|
2995
|
-
const
|
|
2996
|
-
|
|
2911
|
+
const activePairKeys = new Set(rows.filter((item) => item.row.state === "verify" || item.row.state === "pending" || item.row.state === "approved" || item.row.state === "fuse").map((item) => item.row.pairKey));
|
|
2912
|
+
const ledgerConflicts = runs.flatMap((run) => run.pairs).filter((entry) => (entry.result === "merged" || entry.result === "undone") && activePairKeys.has(entry.pairKey));
|
|
2913
|
+
if (ledgerConflicts.length > 0) notes.push("ledger-conflict: a run says completed but the ledger still has it active (" + String(ledgerConflicts.length) + ")");
|
|
2997
2914
|
return {
|
|
2998
2915
|
wireVersion: 1,
|
|
2999
2916
|
schemaVersion: 4,
|
|
@@ -3205,34 +3122,10 @@ var MergeUnitTransactions = class {
|
|
|
3205
3122
|
await this.options.onPhase?.(phase);
|
|
3206
3123
|
};
|
|
3207
3124
|
try {
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
} else {
|
|
3213
|
-
const fallbackLease = await new HomeAuthority({
|
|
3214
|
-
home: this.options.home,
|
|
3215
|
-
waitMs: this.options.waitMs ?? 5e3
|
|
3216
|
-
}).lease("tree").catch(() => void 0);
|
|
3217
|
-
if (fallbackLease === void 0) return {
|
|
3218
|
-
ok: false,
|
|
3219
|
-
code: "unit-fence-failed",
|
|
3220
|
-
message: "tree lock unavailable"
|
|
3221
|
-
};
|
|
3222
|
-
fenceLease = {
|
|
3223
|
-
lock: leaseAsTreeLock(fallbackLease),
|
|
3224
|
-
release: async () => {
|
|
3225
|
-
await fallbackLease.release();
|
|
3226
|
-
}
|
|
3227
|
-
};
|
|
3228
|
-
lock = fenceLease.lock;
|
|
3229
|
-
this.options.onLock?.("tree");
|
|
3230
|
-
}
|
|
3231
|
-
if (!await lock.assertHeld()) return {
|
|
3232
|
-
ok: false,
|
|
3233
|
-
code: "unit-fence-failed",
|
|
3234
|
-
message: "tree fence lost"
|
|
3235
|
-
};
|
|
3125
|
+
const acquired = await this.acquireTreeFence();
|
|
3126
|
+
fenceLease = acquired.fenceLease;
|
|
3127
|
+
lock = acquired.lock;
|
|
3128
|
+
this.options.onLock?.("tree");
|
|
3236
3129
|
stage = "claim";
|
|
3237
3130
|
claim = await this.options.claim.acquire(stored.plan.target, stored.plan.runId);
|
|
3238
3131
|
this.options.onLock?.("claim");
|
|
@@ -3368,6 +3261,82 @@ var MergeUnitTransactions = class {
|
|
|
3368
3261
|
await lease.release();
|
|
3369
3262
|
}
|
|
3370
3263
|
}
|
|
3264
|
+
/** Acquire the one tree fence (or a HomeAuthority fallback) and prove it is held. */
|
|
3265
|
+
async acquireTreeFence() {
|
|
3266
|
+
let fenceLease;
|
|
3267
|
+
if (this.options.fence !== void 0) fenceLease = await this.options.fence.acquire();
|
|
3268
|
+
else {
|
|
3269
|
+
const fallbackLease = await new HomeAuthority({
|
|
3270
|
+
home: this.options.home,
|
|
3271
|
+
waitMs: this.options.waitMs ?? 5e3
|
|
3272
|
+
}).lease("tree").catch(() => void 0);
|
|
3273
|
+
if (fallbackLease === void 0) throw new Error("tree lock unavailable");
|
|
3274
|
+
fenceLease = {
|
|
3275
|
+
lock: leaseAsTreeLock(fallbackLease),
|
|
3276
|
+
release: async () => {
|
|
3277
|
+
await fallbackLease.release();
|
|
3278
|
+
}
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
if (!await fenceLease.lock.assertHeld()) throw new Error("tree fence lost");
|
|
3282
|
+
return {
|
|
3283
|
+
fenceLease,
|
|
3284
|
+
lock: fenceLease.lock
|
|
3285
|
+
};
|
|
3286
|
+
}
|
|
3287
|
+
/** Finish the idempotent support writes from the prepared snapshot, or name the drift. */
|
|
3288
|
+
async completeSupport(snapshot, journal) {
|
|
3289
|
+
let liveSupport = await Promise.all(snapshot.supportAfter.map(async (file) => ({
|
|
3290
|
+
path: file.path,
|
|
3291
|
+
content: await this.options.backend.readSupportFile(snapshot.target, file.path)
|
|
3292
|
+
})));
|
|
3293
|
+
const supportMatches = () => liveSupport.every((file) => file.content === (snapshot.supportAfter.find((item) => item.path === file.path)?.content ?? null));
|
|
3294
|
+
if (supportMatches()) return { ok: true };
|
|
3295
|
+
if (![
|
|
3296
|
+
"support-pending",
|
|
3297
|
+
"sources-archived",
|
|
3298
|
+
"unit-written"
|
|
3299
|
+
].includes(journal.phase) || this.options.backend.restoreSupportFile === void 0) return {
|
|
3300
|
+
ok: false,
|
|
3301
|
+
message: "support file live hash does not match the prepared support; manual recovery required"
|
|
3302
|
+
};
|
|
3303
|
+
for (const file of snapshot.supportAfter) await this.options.backend.restoreSupportFile(snapshot.target, file.path, file.content);
|
|
3304
|
+
liveSupport = await Promise.all(snapshot.supportAfter.map(async (file) => ({
|
|
3305
|
+
path: file.path,
|
|
3306
|
+
content: await this.options.backend.readSupportFile(snapshot.target, file.path)
|
|
3307
|
+
})));
|
|
3308
|
+
return supportMatches() ? { ok: true } : {
|
|
3309
|
+
ok: false,
|
|
3310
|
+
message: "support file could not be completed from the prepared snapshot"
|
|
3311
|
+
};
|
|
3312
|
+
}
|
|
3313
|
+
/** The complete evidence record both settlement paths write. */
|
|
3314
|
+
async evidenceFor(unitId, snapshot, journal, targetAfter) {
|
|
3315
|
+
const checkpoints = journal.checkpoints ?? [];
|
|
3316
|
+
return {
|
|
3317
|
+
schemaVersion: 1,
|
|
3318
|
+
unitId,
|
|
3319
|
+
runId: snapshot.runId,
|
|
3320
|
+
planDigest: snapshot.planDigest,
|
|
3321
|
+
state: "complete",
|
|
3322
|
+
target: {
|
|
3323
|
+
before: snapshot.targetBefore,
|
|
3324
|
+
after: targetAfter,
|
|
3325
|
+
supportDigest: createHash("sha256").update(JSON.stringify(snapshot.supportAfter)).digest("hex"),
|
|
3326
|
+
created: !snapshot.targetExists
|
|
3327
|
+
},
|
|
3328
|
+
sources: snapshot.sourceBefore.map((source) => ({
|
|
3329
|
+
name: source.name,
|
|
3330
|
+
before: source.body,
|
|
3331
|
+
after: null,
|
|
3332
|
+
archived: checkpoints.some((item) => item.source === source.name),
|
|
3333
|
+
absorbedInto: snapshot.target
|
|
3334
|
+
})),
|
|
3335
|
+
mutations: 0,
|
|
3336
|
+
...snapshot.validationPlan === void 0 ? {} : { validationPlan: snapshot.validationPlan },
|
|
3337
|
+
at: this.now()
|
|
3338
|
+
};
|
|
3339
|
+
}
|
|
3371
3340
|
async finalize(unitId) {
|
|
3372
3341
|
return await this.withRecoveryFence(async () => this.finalizeUnlocked(unitId));
|
|
3373
3342
|
}
|
|
@@ -3412,55 +3381,13 @@ var MergeUnitTransactions = class {
|
|
|
3412
3381
|
code: "unit-rollback-blocked",
|
|
3413
3382
|
message: "source is still live: " + liveSource.name
|
|
3414
3383
|
};
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
if (!supportMatches()) {
|
|
3421
|
-
if (![
|
|
3422
|
-
"support-pending",
|
|
3423
|
-
"sources-archived",
|
|
3424
|
-
"unit-written"
|
|
3425
|
-
].includes(journal.phase) || this.options.backend.restoreSupportFile === void 0) return {
|
|
3426
|
-
ok: false,
|
|
3427
|
-
code: "unit-rollback-blocked",
|
|
3428
|
-
message: "support file live hash does not match the prepared support; manual recovery required"
|
|
3429
|
-
};
|
|
3430
|
-
for (const file of snapshot.supportAfter) await this.options.backend.restoreSupportFile(snapshot.target, file.path, file.content);
|
|
3431
|
-
liveSupport = await Promise.all(snapshot.supportAfter.map(async (file) => ({
|
|
3432
|
-
path: file.path,
|
|
3433
|
-
content: await this.options.backend.readSupportFile(snapshot.target, file.path)
|
|
3434
|
-
})));
|
|
3435
|
-
if (!supportMatches()) return {
|
|
3436
|
-
ok: false,
|
|
3437
|
-
code: "unit-rollback-blocked",
|
|
3438
|
-
message: "support file could not be completed from the prepared snapshot"
|
|
3439
|
-
};
|
|
3440
|
-
}
|
|
3441
|
-
const evidence = {
|
|
3442
|
-
schemaVersion: 1,
|
|
3443
|
-
unitId,
|
|
3444
|
-
runId: snapshot.runId,
|
|
3445
|
-
planDigest: snapshot.planDigest,
|
|
3446
|
-
state: "complete",
|
|
3447
|
-
target: {
|
|
3448
|
-
before: snapshot.targetBefore,
|
|
3449
|
-
after: await this.options.backend.readSkill(snapshot.target) ?? "",
|
|
3450
|
-
supportDigest: createHash("sha256").update(JSON.stringify(snapshot.supportAfter)).digest("hex"),
|
|
3451
|
-
created: !snapshot.targetExists
|
|
3452
|
-
},
|
|
3453
|
-
sources: snapshot.sourceBefore.map((source) => ({
|
|
3454
|
-
name: source.name,
|
|
3455
|
-
before: source.body,
|
|
3456
|
-
after: null,
|
|
3457
|
-
archived: checkpoints.some((item) => item.source === source.name),
|
|
3458
|
-
absorbedInto: snapshot.target
|
|
3459
|
-
})),
|
|
3460
|
-
mutations: 0,
|
|
3461
|
-
...snapshot.validationPlan === void 0 ? {} : { validationPlan: snapshot.validationPlan },
|
|
3462
|
-
at: this.now()
|
|
3384
|
+
const support = await this.completeSupport(snapshot, journal);
|
|
3385
|
+
if (!support.ok) return {
|
|
3386
|
+
ok: false,
|
|
3387
|
+
code: "unit-rollback-blocked",
|
|
3388
|
+
message: support.message
|
|
3463
3389
|
};
|
|
3390
|
+
const evidence = await this.evidenceFor(unitId, snapshot, journal, await this.options.backend.readSkill(snapshot.target) ?? "");
|
|
3464
3391
|
if (receipt?.evidenceSha256 !== void 0 && unitEvidenceDigest(evidence) !== receipt.evidenceSha256) return {
|
|
3465
3392
|
ok: false,
|
|
3466
3393
|
code: "unit-rollback-blocked",
|
|
@@ -3522,55 +3449,13 @@ var MergeUnitTransactions = class {
|
|
|
3522
3449
|
code: "unit-rollback-blocked",
|
|
3523
3450
|
message: "source is still live: " + liveSource.name
|
|
3524
3451
|
};
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
if (!supportMatches()) {
|
|
3531
|
-
if (![
|
|
3532
|
-
"support-pending",
|
|
3533
|
-
"sources-archived",
|
|
3534
|
-
"unit-written"
|
|
3535
|
-
].includes(journal.phase) || this.options.backend.restoreSupportFile === void 0) return {
|
|
3536
|
-
ok: false,
|
|
3537
|
-
code: "unit-rollback-blocked",
|
|
3538
|
-
message: "support file live hash does not match the prepared support; manual recovery required"
|
|
3539
|
-
};
|
|
3540
|
-
for (const file of snapshot.supportAfter) await this.options.backend.restoreSupportFile(snapshot.target, file.path, file.content);
|
|
3541
|
-
liveSupport = await Promise.all(snapshot.supportAfter.map(async (file) => ({
|
|
3542
|
-
path: file.path,
|
|
3543
|
-
content: await this.options.backend.readSupportFile(snapshot.target, file.path)
|
|
3544
|
-
})));
|
|
3545
|
-
if (!supportMatches()) return {
|
|
3546
|
-
ok: false,
|
|
3547
|
-
code: "unit-rollback-blocked",
|
|
3548
|
-
message: "support file could not be completed from the prepared snapshot"
|
|
3549
|
-
};
|
|
3550
|
-
}
|
|
3551
|
-
const evidence = {
|
|
3552
|
-
schemaVersion: 1,
|
|
3553
|
-
unitId,
|
|
3554
|
-
runId: snapshot.runId,
|
|
3555
|
-
planDigest: snapshot.planDigest,
|
|
3556
|
-
state: "complete",
|
|
3557
|
-
target: {
|
|
3558
|
-
before: snapshot.targetBefore,
|
|
3559
|
-
after: targetAfter,
|
|
3560
|
-
supportDigest: createHash("sha256").update(JSON.stringify(snapshot.supportAfter)).digest("hex"),
|
|
3561
|
-
created: !snapshot.targetExists
|
|
3562
|
-
},
|
|
3563
|
-
sources: snapshot.sourceBefore.map((source) => ({
|
|
3564
|
-
name: source.name,
|
|
3565
|
-
before: source.body,
|
|
3566
|
-
after: null,
|
|
3567
|
-
archived: checkpoints.some((item) => item.source === source.name),
|
|
3568
|
-
absorbedInto: snapshot.target
|
|
3569
|
-
})),
|
|
3570
|
-
mutations: 0,
|
|
3571
|
-
...snapshot.validationPlan === void 0 ? {} : { validationPlan: snapshot.validationPlan },
|
|
3572
|
-
at: this.now()
|
|
3452
|
+
const support = await this.completeSupport(snapshot, journal);
|
|
3453
|
+
if (!support.ok) return {
|
|
3454
|
+
ok: false,
|
|
3455
|
+
code: "unit-rollback-blocked",
|
|
3456
|
+
message: support.message
|
|
3573
3457
|
};
|
|
3458
|
+
const evidence = await this.evidenceFor(unitId, snapshot, journal, targetAfter);
|
|
3574
3459
|
await writeUnitEvidence(this.options.io, this.options.home, evidence);
|
|
3575
3460
|
await writeUnitJournal(this.options.io, this.options.home, {
|
|
3576
3461
|
...journal,
|
|
@@ -3602,33 +3487,10 @@ var MergeUnitTransactions = class {
|
|
|
3602
3487
|
let lock;
|
|
3603
3488
|
let claim;
|
|
3604
3489
|
try {
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
} else {
|
|
3609
|
-
const fallbackLease = await new HomeAuthority({
|
|
3610
|
-
home: this.options.home,
|
|
3611
|
-
waitMs: this.options.waitMs ?? 5e3
|
|
3612
|
-
}).lease("tree").catch(() => void 0);
|
|
3613
|
-
if (fallbackLease === void 0) return {
|
|
3614
|
-
ok: false,
|
|
3615
|
-
code: "unit-fence-failed",
|
|
3616
|
-
message: "tree lock unavailable"
|
|
3617
|
-
};
|
|
3618
|
-
fenceLease = {
|
|
3619
|
-
lock: leaseAsTreeLock(fallbackLease),
|
|
3620
|
-
release: async () => {
|
|
3621
|
-
await fallbackLease.release();
|
|
3622
|
-
}
|
|
3623
|
-
};
|
|
3624
|
-
lock = fenceLease.lock;
|
|
3625
|
-
}
|
|
3490
|
+
const acquired = await this.acquireTreeFence();
|
|
3491
|
+
fenceLease = acquired.fenceLease;
|
|
3492
|
+
lock = acquired.lock;
|
|
3626
3493
|
this.options.onLock?.("tree");
|
|
3627
|
-
if (!await lock.assertHeld()) return {
|
|
3628
|
-
ok: false,
|
|
3629
|
-
code: "unit-fence-failed",
|
|
3630
|
-
message: "tree fence lost"
|
|
3631
|
-
};
|
|
3632
3494
|
claim = await this.options.claim.acquire(snapshot.target, snapshot.runId);
|
|
3633
3495
|
this.options.onLock?.("claim");
|
|
3634
3496
|
const currentTarget = await this.options.backend.readSkill(snapshot.target);
|
|
@@ -4668,78 +4530,6 @@ const ALLOWED = [
|
|
|
4668
4530
|
evidence: "none",
|
|
4669
4531
|
activeRuns: 0
|
|
4670
4532
|
},
|
|
4671
|
-
{
|
|
4672
|
-
row: "fuse",
|
|
4673
|
-
run: "none",
|
|
4674
|
-
staging: "none",
|
|
4675
|
-
journal: "none",
|
|
4676
|
-
evidence: "none",
|
|
4677
|
-
activeRuns: 0,
|
|
4678
|
-
recovery: true
|
|
4679
|
-
},
|
|
4680
|
-
{
|
|
4681
|
-
row: "fuse",
|
|
4682
|
-
run: "failed",
|
|
4683
|
-
staging: "none",
|
|
4684
|
-
journal: "none",
|
|
4685
|
-
evidence: "none",
|
|
4686
|
-
activeRuns: 0,
|
|
4687
|
-
recovery: true
|
|
4688
|
-
},
|
|
4689
|
-
{
|
|
4690
|
-
row: "fuse",
|
|
4691
|
-
run: "orphan",
|
|
4692
|
-
staging: "none",
|
|
4693
|
-
journal: "none",
|
|
4694
|
-
evidence: "none",
|
|
4695
|
-
activeRuns: 0,
|
|
4696
|
-
recovery: true
|
|
4697
|
-
},
|
|
4698
|
-
{
|
|
4699
|
-
row: "fuse",
|
|
4700
|
-
run: "running",
|
|
4701
|
-
staging: "none",
|
|
4702
|
-
journal: "none",
|
|
4703
|
-
evidence: "none",
|
|
4704
|
-
activeRuns: 1,
|
|
4705
|
-
recovery: true
|
|
4706
|
-
},
|
|
4707
|
-
{
|
|
4708
|
-
row: "fuse",
|
|
4709
|
-
run: "none",
|
|
4710
|
-
staging: "missing",
|
|
4711
|
-
journal: "none",
|
|
4712
|
-
evidence: "none",
|
|
4713
|
-
activeRuns: 0,
|
|
4714
|
-
recovery: true
|
|
4715
|
-
},
|
|
4716
|
-
{
|
|
4717
|
-
row: "fuse",
|
|
4718
|
-
run: "failed",
|
|
4719
|
-
staging: "missing",
|
|
4720
|
-
journal: "none",
|
|
4721
|
-
evidence: "none",
|
|
4722
|
-
activeRuns: 0,
|
|
4723
|
-
recovery: true
|
|
4724
|
-
},
|
|
4725
|
-
{
|
|
4726
|
-
row: "fuse",
|
|
4727
|
-
run: "orphan",
|
|
4728
|
-
staging: "missing",
|
|
4729
|
-
journal: "none",
|
|
4730
|
-
evidence: "none",
|
|
4731
|
-
activeRuns: 0,
|
|
4732
|
-
recovery: true
|
|
4733
|
-
},
|
|
4734
|
-
{
|
|
4735
|
-
row: "fuse",
|
|
4736
|
-
run: "running",
|
|
4737
|
-
staging: "missing",
|
|
4738
|
-
journal: "none",
|
|
4739
|
-
evidence: "none",
|
|
4740
|
-
activeRuns: 1,
|
|
4741
|
-
recovery: true
|
|
4742
|
-
},
|
|
4743
4533
|
{
|
|
4744
4534
|
row: "fuse",
|
|
4745
4535
|
run: "running",
|
|
@@ -4774,7 +4564,7 @@ const ALLOWED = [
|
|
|
4774
4564
|
}
|
|
4775
4565
|
];
|
|
4776
4566
|
function same(a, b) {
|
|
4777
|
-
return a.row === b.row && a.run === b.run && a.staging === b.staging && a.journal === b.journal && a.evidence === b.evidence && a.activeRuns === b.activeRuns
|
|
4567
|
+
return a.row === b.row && a.run === b.run && a.staging === b.staging && a.journal === b.journal && a.evidence === b.evidence && a.activeRuns === b.activeRuns;
|
|
4778
4568
|
}
|
|
4779
4569
|
function validateArtifacts(state) {
|
|
4780
4570
|
if (state.activeRuns > 1) return {
|
|
@@ -4794,7 +4584,7 @@ function validateArtifacts(state) {
|
|
|
4794
4584
|
ok: false,
|
|
4795
4585
|
reason: "skipped-running"
|
|
4796
4586
|
};
|
|
4797
|
-
if (state.row === "fuse" && state.staging === "missing"
|
|
4587
|
+
if (state.row === "fuse" && state.staging === "missing") return {
|
|
4798
4588
|
ok: false,
|
|
4799
4589
|
reason: "fuse-lost-staging"
|
|
4800
4590
|
};
|
|
@@ -4812,35 +4602,12 @@ function validateArtifacts(state) {
|
|
|
4812
4602
|
};
|
|
4813
4603
|
}
|
|
4814
4604
|
//#endregion
|
|
4815
|
-
//#region lib/types/domain/commit-journal-store.js
|
|
4816
|
-
/** Durable commit journal: <home>/merge/journals/<run>.json. */
|
|
4817
|
-
function journalPath(home, runId) {
|
|
4818
|
-
return join(home, "merge", "journals", runId.replace(/[^A-Za-z0-9_-]+/g, "_") + ".json");
|
|
4819
|
-
}
|
|
4820
|
-
async function writeJournal(io, home, journal) {
|
|
4821
|
-
const path = journalPath(home, journal.runId);
|
|
4822
|
-
const content = JSON.stringify(journal, null, 2);
|
|
4823
|
-
if (io.transact !== void 0) await io.transact(path, () => content);
|
|
4824
|
-
else await io.writeText(path, content);
|
|
4825
|
-
return path;
|
|
4826
|
-
}
|
|
4827
|
-
async function readJournal(io, home, runId) {
|
|
4828
|
-
const raw = await io.readText(journalPath(home, runId));
|
|
4829
|
-
if (raw === null) return null;
|
|
4830
|
-
try {
|
|
4831
|
-
return JSON.parse(raw);
|
|
4832
|
-
} catch {
|
|
4833
|
-
return null;
|
|
4834
|
-
}
|
|
4835
|
-
}
|
|
4836
|
-
//#endregion
|
|
4837
4605
|
//#region lib/types/doctor.js
|
|
4838
4606
|
/**
|
|
4839
4607
|
* Merge doctor rows: state, pending, gate cache and staging are each probed read-only.
|
|
4840
4608
|
* A missing file is an empty feature, not a failure; an unreadable file is a warning the
|
|
4841
4609
|
* operator can act on. This module never repairs or writes.
|
|
4842
4610
|
*/
|
|
4843
|
-
const MERGE_DOCTOR_SCHEMA_VERSION = 3;
|
|
4844
4611
|
/** Compose the one-line global-doctor fact from buildDoctorView + the last reconcile report. */
|
|
4845
4612
|
function mergeDoctorFact(view, report) {
|
|
4846
4613
|
const counts = view.counts;
|
|
@@ -4889,13 +4656,6 @@ async function mergeDoctor(io, home, configuredRoot) {
|
|
|
4889
4656
|
status: snapshot.blocked === void 0 || !hasState ? "ok" : "warn",
|
|
4890
4657
|
detail: snapshot.blocked === void 0 ? "pairs " + String(snapshot.rows.length) + ";verify " + String(counts.verify) + " / pending " + String(counts.pending) + " / fuse " + String(counts.fuse) + " / skipped " + String(counts.skipped) + " / expired " + String(snapshot.doctor.counts.expired) : snapshot.blocked.code + ": " + snapshot.blocked.message
|
|
4891
4658
|
});
|
|
4892
|
-
const recoveryRuns = /* @__PURE__ */ new Set();
|
|
4893
|
-
try {
|
|
4894
|
-
const raw = await io.readText(join(home, "merge", "recovery.json"));
|
|
4895
|
-
if (raw !== null) {
|
|
4896
|
-
for (const report of JSON.parse(raw)) if (report.ok === true && report.runId !== void 0) recoveryRuns.add(report.runId);
|
|
4897
|
-
}
|
|
4898
|
-
} catch {}
|
|
4899
4659
|
const invalid = [];
|
|
4900
4660
|
if (snapshot.blocked !== void 0) invalid.push({
|
|
4901
4661
|
id: "state",
|
|
@@ -4908,15 +4668,14 @@ async function mergeDoctor(io, home, configuredRoot) {
|
|
|
4908
4668
|
const run = runId === void 0 ? "none" : row.state === "pending" ? "awaiting-approval" : "running";
|
|
4909
4669
|
const staging = item.stage === null ? row.state === "fuse" ? "missing" : "none" : item.stage.state === "present" || item.stage.state === "reserved" ? "kept" : row.state === "fuse" ? "missing" : "none";
|
|
4910
4670
|
const receipt = runId === void 0 ? null : await readCommitReceipt(io, home, runId);
|
|
4911
|
-
const phase = receipt
|
|
4671
|
+
const phase = receipt === null ? null : await readUnitJournal(io, home, receipt.unitId);
|
|
4912
4672
|
const result = validateArtifacts({
|
|
4913
4673
|
row: artifactRow,
|
|
4914
4674
|
run,
|
|
4915
4675
|
staging,
|
|
4916
4676
|
journal: phase === null ? "none" : phase.phase === "prepared" || phase.phase === "target-pending" ? "prepared" : phase.phase === "target-written" || phase.phase === "sources-archived" || phase.phase === "support-pending" || phase.phase === "source-archiving" ? "committing" : phase.phase === "committed" ? "committed" : phase.phase === "rolled-back" ? "rolled-back" : "failed",
|
|
4917
4677
|
evidence: receipt === null ? "none" : "receipt",
|
|
4918
|
-
activeRuns: run === "running" || run === "awaiting-approval" ? 1 : 0
|
|
4919
|
-
...runId !== void 0 && recoveryRuns.has(runId) ? { recovery: true } : {}
|
|
4678
|
+
activeRuns: run === "running" || run === "awaiting-approval" ? 1 : 0
|
|
4920
4679
|
});
|
|
4921
4680
|
if (!result.ok) invalid.push({
|
|
4922
4681
|
id: row.id,
|
|
@@ -5059,26 +4818,6 @@ async function mergeDoctor(io, home, configuredRoot) {
|
|
|
5059
4818
|
status: "ok",
|
|
5060
4819
|
detail: stagingRoot(home, "<runId>")
|
|
5061
4820
|
});
|
|
5062
|
-
try {
|
|
5063
|
-
const raw = await io.readText(join(home, "merge", "recovery.json"));
|
|
5064
|
-
if (raw !== null) {
|
|
5065
|
-
const reports = JSON.parse(raw);
|
|
5066
|
-
const failed = reports.filter((report) => report.ok !== true);
|
|
5067
|
-
rows.push({
|
|
5068
|
-
key: "recovery",
|
|
5069
|
-
label: "提交恢复",
|
|
5070
|
-
status: failed.length === 0 ? "ok" : "warn",
|
|
5071
|
-
detail: failed.length === 0 ? String(reports.length) + " 条恢复报告,无待处理" : String(failed.length) + " 条待处理:" + failed.map((report) => (report.runId ?? "?") + "=" + (report.action ?? "?")).join(", ")
|
|
5072
|
-
});
|
|
5073
|
-
}
|
|
5074
|
-
} catch {
|
|
5075
|
-
rows.push({
|
|
5076
|
-
key: "recovery",
|
|
5077
|
-
label: "提交恢复",
|
|
5078
|
-
status: "unknown",
|
|
5079
|
-
detail: "无法读取 merge/recovery.json"
|
|
5080
|
-
});
|
|
5081
|
-
}
|
|
5082
4821
|
return rows;
|
|
5083
4822
|
}
|
|
5084
4823
|
//#endregion
|
|
@@ -5275,13 +5014,6 @@ async function projectRecoveredUnit(options) {
|
|
|
5275
5014
|
await options.onPhase?.("stage-drop");
|
|
5276
5015
|
await dropStage(options.io, options.home, stageRowId);
|
|
5277
5016
|
}
|
|
5278
|
-
await options.onPhase?.("pair-index");
|
|
5279
|
-
await recordPair(options.io, options.home, {
|
|
5280
|
-
pairKey,
|
|
5281
|
-
runId: options.runId,
|
|
5282
|
-
result: "merged",
|
|
5283
|
-
target
|
|
5284
|
-
});
|
|
5285
5017
|
await options.onPhase?.("run-meta");
|
|
5286
5018
|
const meta = await readRunMeta(options.io, options.home, options.runId);
|
|
5287
5019
|
await writeRunMeta(options.io, options.home, {
|
|
@@ -5996,9 +5728,6 @@ async function handleReadOnlyMergeCommand(command, io, home, cards, runs, approv
|
|
|
5996
5728
|
}
|
|
5997
5729
|
return formatSnapshotQueue(rows.filter((row) => row.queue === "skipped"), "skipped");
|
|
5998
5730
|
}
|
|
5999
|
-
function mergeCommandHelp() {
|
|
6000
|
-
return mergeUsage();
|
|
6001
|
-
}
|
|
6002
5731
|
//#endregion
|
|
6003
5732
|
//#region lib/types/merge-command.js
|
|
6004
5733
|
function createReadOnlyMergeService(io, home) {
|
|
@@ -6052,10 +5781,6 @@ function createMergeCommand(service, version = MERGE_PACKAGE_VERSION) {
|
|
|
6052
5781
|
}
|
|
6053
5782
|
//#endregion
|
|
6054
5783
|
//#region lib/types/skipped.js
|
|
6055
|
-
/**
|
|
6056
|
-
* Skipped filtering: a pair the operator marked as not-worth-merging stays out of automatic
|
|
6057
|
-
* screening until mergeSkippedTtlDays expires. Explicit /merge pair ignores this set.
|
|
6058
|
-
*/
|
|
6059
5784
|
function skippedPairKeys(rows, ttlDays, now) {
|
|
6060
5785
|
const keys = /* @__PURE__ */ new Set();
|
|
6061
5786
|
for (const row of rows) {
|
|
@@ -6069,9 +5794,6 @@ function skippedPairKeys(rows, ttlDays, now) {
|
|
|
6069
5794
|
}
|
|
6070
5795
|
return keys;
|
|
6071
5796
|
}
|
|
6072
|
-
function isSkippedPair(keys, a, b) {
|
|
6073
|
-
return keys.has(pairKey(a, b));
|
|
6074
|
-
}
|
|
6075
5797
|
//#endregion
|
|
6076
5798
|
//#region lib/types/domain/engine-criteria.js
|
|
6077
5799
|
function criteriaFrom(level, verdict, action) {
|
|
@@ -6324,11 +6046,6 @@ async function runScan(options) {
|
|
|
6324
6046
|
continue;
|
|
6325
6047
|
}
|
|
6326
6048
|
row = projected;
|
|
6327
|
-
await recordPair(options.io, options.home, {
|
|
6328
|
-
pairKey: row.pairKey,
|
|
6329
|
-
runId: row.runId ?? "merge",
|
|
6330
|
-
result: "kept"
|
|
6331
|
-
});
|
|
6332
6049
|
pairs.push(pairOf(row, candidate, "kept", {
|
|
6333
6050
|
...round1.decision === void 0 ? {} : { decision: round1.decision },
|
|
6334
6051
|
...round1.usage === void 0 ? {} : { usage: round1.usage }
|
|
@@ -6538,15 +6255,7 @@ async function runScan(options) {
|
|
|
6538
6255
|
if (await pairLedger(options.io, options.home).transact((tx) => {
|
|
6539
6256
|
const current = tx.rows().find((item) => item.id === row.id);
|
|
6540
6257
|
return current === void 0 ? false : tx.remove(row.id, "superseded", void 0, current.version).ok;
|
|
6541
|
-
}))
|
|
6542
|
-
await dropStage(options.io, options.home, row.id, row.stagingRef);
|
|
6543
|
-
await recordPair(options.io, options.home, {
|
|
6544
|
-
pairKey: row.pairKey,
|
|
6545
|
-
runId: row.runId ?? "merge",
|
|
6546
|
-
result: "failed",
|
|
6547
|
-
...row.decision?.target === void 0 ? {} : { target: row.decision.target }
|
|
6548
|
-
});
|
|
6549
|
-
}
|
|
6258
|
+
})) await dropStage(options.io, options.home, row.id, row.stagingRef);
|
|
6550
6259
|
pairs.push(pairOf(row, candidate, "failed", {
|
|
6551
6260
|
decision: mergeDecision,
|
|
6552
6261
|
failure: failed,
|
|
@@ -7048,12 +6757,22 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7048
6757
|
...outcome.criteria === void 0 ? {} : { criteria: outcome.criteria },
|
|
7049
6758
|
...outcome.validationIssues === void 0 ? {} : { validation: { issues: outcome.validationIssues } }
|
|
7050
6759
|
};
|
|
6760
|
+
const pair = (outcomeName, extra = {}, withDecision = true) => ({
|
|
6761
|
+
id: row.id,
|
|
6762
|
+
pairKey: row.pairKey,
|
|
6763
|
+
a: row.a,
|
|
6764
|
+
b: row.b,
|
|
6765
|
+
queue: row.queue,
|
|
6766
|
+
...withDecision && row.decision !== void 0 ? { decision: row.decision } : {},
|
|
6767
|
+
outcome: outcomeName,
|
|
6768
|
+
archived: [],
|
|
6769
|
+
...extra
|
|
6770
|
+
});
|
|
7051
6771
|
if (outcome.kind === "merged") {
|
|
7052
6772
|
const unitRef = {
|
|
7053
6773
|
unitId: outcome.unitId ?? "unknown",
|
|
7054
6774
|
evidenceSha256: outcome.evidenceSha256 ?? "unknown"
|
|
7055
6775
|
};
|
|
7056
|
-
const target = outcome.target?.actual ?? outcome.target?.requested ?? row.decision?.target;
|
|
7057
6776
|
const finalize = async () => {
|
|
7058
6777
|
if (!(await pairLedger(io, home, fence).transact((tx) => {
|
|
7059
6778
|
const current = tx.rows().find((item) => item.id === row.id);
|
|
@@ -7064,50 +6783,28 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7064
6783
|
} : tx.remove(row.id, "committed", unitRef, current.version);
|
|
7065
6784
|
})).ok) throw new Error("row changed before commit record: " + row.id);
|
|
7066
6785
|
await dropStage(io, home, row.id);
|
|
7067
|
-
await recordPair(io, home, {
|
|
7068
|
-
pairKey: row.pairKey,
|
|
7069
|
-
runId: row.runId ?? "merge",
|
|
7070
|
-
result: "merged",
|
|
7071
|
-
...target === void 0 ? {} : { target },
|
|
7072
|
-
...outcome.unitId === void 0 ? {} : { reportRef: outcome.unitId }
|
|
7073
|
-
});
|
|
7074
6786
|
};
|
|
7075
6787
|
if (deferProjection) return {
|
|
7076
6788
|
merged: true,
|
|
7077
6789
|
finalize,
|
|
7078
|
-
pair: {
|
|
7079
|
-
id: row.id,
|
|
7080
|
-
pairKey: row.pairKey,
|
|
7081
|
-
a: row.a,
|
|
7082
|
-
b: row.b,
|
|
7083
|
-
queue: row.queue,
|
|
7084
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7085
|
-
outcome: "merged",
|
|
7086
|
-
archived: outcome.archived ?? [],
|
|
6790
|
+
pair: pair("merged", {
|
|
7087
6791
|
...outcome.lengths === void 0 ? {} : { lengths: outcome.lengths },
|
|
7088
6792
|
...outcome.unitId === void 0 ? {} : { unitId: outcome.unitId },
|
|
7089
6793
|
...outcome.target === void 0 ? {} : { target: outcome.target },
|
|
7090
6794
|
...reportExtra
|
|
7091
|
-
}
|
|
6795
|
+
})
|
|
7092
6796
|
};
|
|
7093
6797
|
await finalize();
|
|
7094
6798
|
return {
|
|
7095
6799
|
merged: true,
|
|
7096
|
-
pair: {
|
|
7097
|
-
|
|
7098
|
-
pairKey: row.pairKey,
|
|
7099
|
-
a: row.a,
|
|
7100
|
-
b: row.b,
|
|
7101
|
-
queue: row.queue,
|
|
7102
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7103
|
-
outcome: "merged",
|
|
7104
|
-
archived: outcome.archived ?? [],
|
|
6800
|
+
pair: pair("merged", {
|
|
6801
|
+
...outcome.archived === void 0 ? {} : { archived: outcome.archived },
|
|
7105
6802
|
...outcome.lengths === void 0 ? {} : { lengths: outcome.lengths },
|
|
7106
6803
|
...reportExtra,
|
|
7107
6804
|
...outcome.unitId === void 0 ? {} : { unitId: outcome.unitId },
|
|
7108
6805
|
...outcome.target === void 0 ? {} : { target: outcome.target },
|
|
7109
6806
|
...outcome.validationPlan === void 0 ? {} : { validationPlan: outcome.validationPlan }
|
|
7110
|
-
}
|
|
6807
|
+
})
|
|
7111
6808
|
};
|
|
7112
6809
|
}
|
|
7113
6810
|
const failure = outcome.failure ?? {
|
|
@@ -7130,18 +6827,10 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7130
6827
|
})) await dropStage(io, home, row.id);
|
|
7131
6828
|
return {
|
|
7132
6829
|
merged: false,
|
|
7133
|
-
pair: {
|
|
7134
|
-
id: row.id,
|
|
7135
|
-
pairKey: row.pairKey,
|
|
7136
|
-
a: row.a,
|
|
7137
|
-
b: row.b,
|
|
7138
|
-
queue: row.queue,
|
|
7139
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7140
|
-
outcome: "failed",
|
|
7141
|
-
archived: [],
|
|
6830
|
+
pair: pair("failed", {
|
|
7142
6831
|
failure,
|
|
7143
6832
|
...reportExtra
|
|
7144
|
-
}
|
|
6833
|
+
})
|
|
7145
6834
|
};
|
|
7146
6835
|
}
|
|
7147
6836
|
const cas = casExpiredHook(failure.code);
|
|
@@ -7163,33 +6852,17 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7163
6852
|
await dropStage(io, home, row.id);
|
|
7164
6853
|
return {
|
|
7165
6854
|
merged: false,
|
|
7166
|
-
pair: {
|
|
7167
|
-
id: row.id,
|
|
7168
|
-
pairKey: row.pairKey,
|
|
7169
|
-
a: row.a,
|
|
7170
|
-
b: row.b,
|
|
7171
|
-
queue: row.queue,
|
|
7172
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7173
|
-
outcome: "failed",
|
|
7174
|
-
archived: [],
|
|
6855
|
+
pair: pair("failed", {
|
|
7175
6856
|
failure: terminalFailure,
|
|
7176
6857
|
...reportExtra
|
|
7177
|
-
}
|
|
6858
|
+
})
|
|
7178
6859
|
};
|
|
7179
6860
|
}
|
|
7180
6861
|
if (failure.code === "commit-failed" || failure.code === "validation-failed") {
|
|
7181
6862
|
if (await pairLedger(io, home, fence).transact((tx) => {
|
|
7182
6863
|
const current = tx.rows().find((item) => item.id === row.id);
|
|
7183
6864
|
return current === void 0 ? false : tx.remove(row.id, "superseded", void 0, current.version).ok;
|
|
7184
|
-
}))
|
|
7185
|
-
await dropStage(io, home, row.id, row.stagingRef);
|
|
7186
|
-
await recordPair(io, home, {
|
|
7187
|
-
pairKey: row.pairKey,
|
|
7188
|
-
runId: row.runId ?? "merge",
|
|
7189
|
-
result: "failed",
|
|
7190
|
-
...row.decision?.target === void 0 ? {} : { target: row.decision.target }
|
|
7191
|
-
});
|
|
7192
|
-
}
|
|
6865
|
+
})) await dropStage(io, home, row.id, row.stagingRef);
|
|
7193
6866
|
}
|
|
7194
6867
|
if (failure.code === "source-gone") {
|
|
7195
6868
|
if (await pairLedger(io, home, fence).transact((tx) => {
|
|
@@ -7198,16 +6871,7 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7198
6871
|
})) await dropStage(io, home, row.id, row.stagingRef);
|
|
7199
6872
|
return {
|
|
7200
6873
|
merged: false,
|
|
7201
|
-
pair: {
|
|
7202
|
-
id: row.id,
|
|
7203
|
-
pairKey: row.pairKey,
|
|
7204
|
-
a: row.a,
|
|
7205
|
-
b: row.b,
|
|
7206
|
-
queue: row.queue,
|
|
7207
|
-
outcome: "failed",
|
|
7208
|
-
archived: [],
|
|
7209
|
-
failure
|
|
7210
|
-
}
|
|
6874
|
+
pair: pair("failed", { failure }, false)
|
|
7211
6875
|
};
|
|
7212
6876
|
}
|
|
7213
6877
|
if (await pairLedger(io, home, fence).transact((tx) => {
|
|
@@ -7220,42 +6884,21 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7220
6884
|
return moved.ok && moved.row !== null ? v4ToLegacy(moved.row) : null;
|
|
7221
6885
|
}) === null) return {
|
|
7222
6886
|
merged: false,
|
|
7223
|
-
pair: {
|
|
7224
|
-
id: row.id,
|
|
7225
|
-
pairKey: row.pairKey,
|
|
7226
|
-
a: row.a,
|
|
7227
|
-
b: row.b,
|
|
7228
|
-
queue: row.queue,
|
|
7229
|
-
outcome: "failed",
|
|
7230
|
-
archived: [],
|
|
6887
|
+
pair: pair("failed", {
|
|
7231
6888
|
failure: {
|
|
7232
6889
|
...failure,
|
|
7233
6890
|
code: "row-changed",
|
|
7234
6891
|
message: "row changed before failure record"
|
|
7235
6892
|
},
|
|
7236
6893
|
...reportExtra
|
|
7237
|
-
}
|
|
6894
|
+
}, false)
|
|
7238
6895
|
};
|
|
7239
|
-
await recordPair(io, home, {
|
|
7240
|
-
pairKey: row.pairKey,
|
|
7241
|
-
runId: row.runId ?? "merge",
|
|
7242
|
-
result: "failed",
|
|
7243
|
-
...row.decision?.target === void 0 ? {} : { target: row.decision.target }
|
|
7244
|
-
});
|
|
7245
6896
|
return {
|
|
7246
6897
|
merged: false,
|
|
7247
|
-
pair: {
|
|
7248
|
-
id: row.id,
|
|
7249
|
-
pairKey: row.pairKey,
|
|
7250
|
-
a: row.a,
|
|
7251
|
-
b: row.b,
|
|
7252
|
-
queue: row.queue,
|
|
7253
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7254
|
-
outcome: "failed",
|
|
7255
|
-
archived: [],
|
|
6898
|
+
pair: pair("failed", {
|
|
7256
6899
|
failure,
|
|
7257
6900
|
...reportExtra
|
|
7258
|
-
}
|
|
6901
|
+
})
|
|
7259
6902
|
};
|
|
7260
6903
|
}
|
|
7261
6904
|
//#endregion
|
|
@@ -7704,14 +7347,6 @@ async function runUndoSteps(options) {
|
|
|
7704
7347
|
};
|
|
7705
7348
|
}
|
|
7706
7349
|
if (await readUndoReceipt(options.io, options.home, options.runId, pairKey) !== null) {
|
|
7707
|
-
await markPhase("pair-index");
|
|
7708
|
-
await options.onPhase?.("pair-index", pairKey);
|
|
7709
|
-
await recordPair(options.io, options.home, {
|
|
7710
|
-
pairKey,
|
|
7711
|
-
runId: options.runId,
|
|
7712
|
-
result: "undone",
|
|
7713
|
-
target: receipt.target
|
|
7714
|
-
});
|
|
7715
7350
|
await markPhase("run-meta");
|
|
7716
7351
|
await options.onPhase?.("run-meta", pairKey);
|
|
7717
7352
|
await settleRun(options.io, options.home, options.runId, pairKey, allPairKeys, options.now());
|
|
@@ -7738,14 +7373,6 @@ async function runUndoSteps(options) {
|
|
|
7738
7373
|
restoredSourceHashes: Object.fromEntries(checked.evidence.sources.map((source) => [source.name, contentHash(source.before)])),
|
|
7739
7374
|
at: options.now()
|
|
7740
7375
|
});
|
|
7741
|
-
await markPhase("pair-index");
|
|
7742
|
-
await options.onPhase?.("pair-index", pairKey);
|
|
7743
|
-
await recordPair(options.io, options.home, {
|
|
7744
|
-
pairKey,
|
|
7745
|
-
runId: options.runId,
|
|
7746
|
-
result: "undone",
|
|
7747
|
-
target: receipt.target
|
|
7748
|
-
});
|
|
7749
7376
|
await markPhase("run-meta");
|
|
7750
7377
|
await options.onPhase?.("run-meta", pairKey);
|
|
7751
7378
|
await settleRun(options.io, options.home, options.runId, pairKey, allPairKeys, options.now());
|
|
@@ -7805,13 +7432,6 @@ async function runUndoSteps(options) {
|
|
|
7805
7432
|
restoredSourceHashes: Object.fromEntries(checked.evidence.sources.map((source) => [source.name, contentHash(source.before)])),
|
|
7806
7433
|
at: options.now()
|
|
7807
7434
|
});
|
|
7808
|
-
await options.onPhase?.("pair-index", pairKey);
|
|
7809
|
-
await recordPair(options.io, options.home, {
|
|
7810
|
-
pairKey,
|
|
7811
|
-
runId: options.runId,
|
|
7812
|
-
result: "undone",
|
|
7813
|
-
target: receipt.target
|
|
7814
|
-
});
|
|
7815
7435
|
await options.onPhase?.("run-meta", pairKey);
|
|
7816
7436
|
await settleRun(options.io, options.home, options.runId, pairKey, allPairKeys, options.now());
|
|
7817
7437
|
undone.push(pairKey);
|
|
@@ -8042,9 +7662,6 @@ function buildRound2Prompt(row, decision, mode = "continue") {
|
|
|
8042
7662
|
...body
|
|
8043
7663
|
] : [...head, ...body]).join("\n");
|
|
8044
7664
|
}
|
|
8045
|
-
function buildStandbyPrompt() {
|
|
8046
|
-
return STANDBY_PROMPT;
|
|
8047
|
-
}
|
|
8048
7665
|
//#endregion
|
|
8049
7666
|
//#region lib/types/channel-port.js
|
|
8050
7667
|
async function runRound1OverChannel(options, candidate, signal) {
|
|
@@ -8552,14 +8169,6 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8552
8169
|
message: "target is blocked by curator: " + assembled.plan.target,
|
|
8553
8170
|
plan: assembled.plan
|
|
8554
8171
|
};
|
|
8555
|
-
const journal = {
|
|
8556
|
-
runId,
|
|
8557
|
-
target: assembled.plan.target,
|
|
8558
|
-
create: !assembled.plan.targetExists,
|
|
8559
|
-
sources: assembled.plan.sources,
|
|
8560
|
-
phase: "prepared",
|
|
8561
|
-
updatedAt: new Date(options.now()).toISOString()
|
|
8562
|
-
};
|
|
8563
8172
|
let result;
|
|
8564
8173
|
let evidenceSha256$1;
|
|
8565
8174
|
let warning;
|
|
@@ -8589,9 +8198,6 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8589
8198
|
...options.sourceRevisions === void 0 ? {} : { sourceRevisions: options.sourceRevisions },
|
|
8590
8199
|
...options.supportDigest === void 0 ? {} : { supportDigest: options.supportDigest }
|
|
8591
8200
|
};
|
|
8592
|
-
try {
|
|
8593
|
-
await writeJournal(io, home, journal);
|
|
8594
|
-
} catch {}
|
|
8595
8201
|
const prepared = await transaction.prepare(unitPlan);
|
|
8596
8202
|
if (!prepared.ok) return {
|
|
8597
8203
|
ok: false,
|
|
@@ -8599,21 +8205,12 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8599
8205
|
plan: assembled.plan
|
|
8600
8206
|
};
|
|
8601
8207
|
const committed = await transaction.commit(prepared.prepared, options.signal === void 0 ? void 0 : { signal: options.signal });
|
|
8602
|
-
if (!committed.ok) {
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
});
|
|
8609
|
-
} catch {}
|
|
8610
|
-
return {
|
|
8611
|
-
ok: false,
|
|
8612
|
-
message: committed.message,
|
|
8613
|
-
plan: assembled.plan,
|
|
8614
|
-
...committed.code === "target-changed" || committed.code === "source-changed" || committed.code === "support-changed" ? { code: committed.code } : {}
|
|
8615
|
-
};
|
|
8616
|
-
}
|
|
8208
|
+
if (!committed.ok) return {
|
|
8209
|
+
ok: false,
|
|
8210
|
+
message: committed.message,
|
|
8211
|
+
plan: assembled.plan,
|
|
8212
|
+
...committed.code === "target-changed" || committed.code === "source-changed" || committed.code === "support-changed" ? { code: committed.code } : {}
|
|
8213
|
+
};
|
|
8617
8214
|
const unitId = committed.evidence.unitId;
|
|
8618
8215
|
if (committed.evidence.unitId !== prepared.prepared.unitId && !prepared.prepared.unitId.startsWith("legacy:")) return {
|
|
8619
8216
|
ok: false,
|
|
@@ -8634,29 +8231,11 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8634
8231
|
mutations: committed.evidence.mutations
|
|
8635
8232
|
};
|
|
8636
8233
|
}
|
|
8637
|
-
if (!result.ok) {
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
phase: "failed",
|
|
8642
|
-
updatedAt: new Date(options.now()).toISOString()
|
|
8643
|
-
});
|
|
8644
|
-
} catch {}
|
|
8645
|
-
return {
|
|
8646
|
-
ok: false,
|
|
8647
|
-
message: result.message,
|
|
8648
|
-
plan: assembled.plan
|
|
8649
|
-
};
|
|
8650
|
-
}
|
|
8651
|
-
const committed = {
|
|
8652
|
-
...journal,
|
|
8653
|
-
phase: "committed",
|
|
8654
|
-
updatedAt: new Date(options.now()).toISOString(),
|
|
8655
|
-
...result.unitId === void 0 ? {} : { unitId: result.unitId }
|
|
8234
|
+
if (!result.ok) return {
|
|
8235
|
+
ok: false,
|
|
8236
|
+
message: result.message,
|
|
8237
|
+
plan: assembled.plan
|
|
8656
8238
|
};
|
|
8657
|
-
try {
|
|
8658
|
-
await writeJournal(io, home, committed);
|
|
8659
|
-
} catch {}
|
|
8660
8239
|
if (result.unitId === void 0) return {
|
|
8661
8240
|
ok: true,
|
|
8662
8241
|
plan: assembled.plan,
|
|
@@ -8938,32 +8517,38 @@ function missingManifestFile(files, stagedPaths) {
|
|
|
8938
8517
|
}
|
|
8939
8518
|
//#endregion
|
|
8940
8519
|
//#region lib/types/authoring-flow.js
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8520
|
+
/** The target facts both authoring entries may refuse on before writing anything. */
|
|
8521
|
+
async function targetAdmission(target, targetCard, createMode, isBlocked) {
|
|
8522
|
+
if (target.includes("/") || target.includes(":")) return {
|
|
8944
8523
|
code: "target-invalid",
|
|
8945
|
-
message: "target must be a bare skill name: " +
|
|
8524
|
+
message: "target must be a bare skill name: " + target
|
|
8946
8525
|
};
|
|
8947
|
-
const targetCard = options.cards.find((card) => card.name === options.target);
|
|
8948
|
-
const requestedMode = options.mode ?? (targetCard === void 0 ? "create-umbrella" : "merge-into-existing");
|
|
8949
|
-
const mode = requestedMode === "merge-into-existing" && targetCard === void 0 ? "create-umbrella" : requestedMode;
|
|
8950
|
-
const createMode = mode === "create-umbrella";
|
|
8951
8526
|
if (!createMode && targetCard !== void 0) {
|
|
8952
8527
|
if (targetCard.managed !== true) return {
|
|
8953
|
-
ok: false,
|
|
8954
8528
|
code: "target-not-managed",
|
|
8955
|
-
message: "target is not family-managed: " +
|
|
8529
|
+
message: "target is not family-managed: " + target
|
|
8956
8530
|
};
|
|
8957
8531
|
if (targetCard.protectionUnknown === true || targetCard.protectedBy != null) return {
|
|
8958
|
-
ok: false,
|
|
8959
8532
|
code: "target-protected",
|
|
8960
|
-
message: "target is protected (" + (targetCard.protectedBy ?? "unknown") + "): " +
|
|
8533
|
+
message: "target is protected (" + (targetCard.protectedBy ?? "unknown") + "): " + target
|
|
8961
8534
|
};
|
|
8962
8535
|
}
|
|
8963
|
-
if (!createMode && await
|
|
8964
|
-
ok: false,
|
|
8536
|
+
if (!createMode && await isBlocked?.(target) === true) return {
|
|
8965
8537
|
code: "target-blocked",
|
|
8966
|
-
message: "target is blocked by curator: " +
|
|
8538
|
+
message: "target is blocked by curator: " + target
|
|
8539
|
+
};
|
|
8540
|
+
return null;
|
|
8541
|
+
}
|
|
8542
|
+
async function runAuthoring(options) {
|
|
8543
|
+
const targetCard = options.cards.find((card) => card.name === options.target);
|
|
8544
|
+
const requestedMode = options.mode ?? (targetCard === void 0 ? "create-umbrella" : "merge-into-existing");
|
|
8545
|
+
const mode = requestedMode === "merge-into-existing" && targetCard === void 0 ? "create-umbrella" : requestedMode;
|
|
8546
|
+
const createMode = mode === "create-umbrella";
|
|
8547
|
+
const targetRefusal = await targetAdmission(options.target, targetCard, createMode, options.isBlocked);
|
|
8548
|
+
if (targetRefusal !== null) return {
|
|
8549
|
+
ok: false,
|
|
8550
|
+
code: targetRefusal.code,
|
|
8551
|
+
message: targetRefusal.message
|
|
8967
8552
|
};
|
|
8968
8553
|
const stageKey = options.stageKey ?? options.runId;
|
|
8969
8554
|
if (options.reuseStaging === true) {
|
|
@@ -9285,46 +8870,15 @@ const STALE_CAUSES = new Set([
|
|
|
9285
8870
|
"target-gone"
|
|
9286
8871
|
]);
|
|
9287
8872
|
async function runNewChildAuthoring(options, row, decision, signal) {
|
|
9288
|
-
if (decision.target.includes("/") || decision.target.includes(":")) return {
|
|
9289
|
-
kind: "failed",
|
|
9290
|
-
failure: {
|
|
9291
|
-
stage: "author",
|
|
9292
|
-
code: "target-invalid",
|
|
9293
|
-
message: "target must be a bare skill name: " + decision.target,
|
|
9294
|
-
retryable: false,
|
|
9295
|
-
retryFrom: "none"
|
|
9296
|
-
}
|
|
9297
|
-
};
|
|
9298
8873
|
const targetCard = options.cards.find((card) => card.name === decision.target);
|
|
9299
8874
|
const createMode = decision.mode === "create-umbrella";
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
kind: "failed",
|
|
9303
|
-
failure: {
|
|
9304
|
-
stage: "author",
|
|
9305
|
-
code: "target-not-managed",
|
|
9306
|
-
message: "target is not family-managed: " + decision.target,
|
|
9307
|
-
retryable: false,
|
|
9308
|
-
retryFrom: "none"
|
|
9309
|
-
}
|
|
9310
|
-
};
|
|
9311
|
-
if (targetCard.protectionUnknown === true || targetCard.protectedBy != null) return {
|
|
9312
|
-
kind: "failed",
|
|
9313
|
-
failure: {
|
|
9314
|
-
stage: "author",
|
|
9315
|
-
code: "target-protected",
|
|
9316
|
-
message: "target is protected: " + decision.target,
|
|
9317
|
-
retryable: false,
|
|
9318
|
-
retryFrom: "none"
|
|
9319
|
-
}
|
|
9320
|
-
};
|
|
9321
|
-
}
|
|
9322
|
-
if (!createMode && await options.isBlocked?.(decision.target) === true) return {
|
|
8875
|
+
const targetRefusal = await targetAdmission(decision.target, targetCard, createMode, options.isBlocked);
|
|
8876
|
+
if (targetRefusal !== null) return {
|
|
9323
8877
|
kind: "failed",
|
|
9324
8878
|
failure: {
|
|
9325
8879
|
stage: "author",
|
|
9326
|
-
code:
|
|
9327
|
-
message:
|
|
8880
|
+
code: targetRefusal.code,
|
|
8881
|
+
message: targetRefusal.message,
|
|
9328
8882
|
retryable: false,
|
|
9329
8883
|
retryFrom: "none"
|
|
9330
8884
|
}
|
|
@@ -10787,143 +10341,6 @@ async function supersedeMergeRuns(registry) {
|
|
|
10787
10341
|
return ids.length;
|
|
10788
10342
|
}
|
|
10789
10343
|
//#endregion
|
|
10790
|
-
//#region lib/types/coordinator.js
|
|
10791
|
-
/**
|
|
10792
|
-
* Pure merge transition table. No io, no run shell, no subagents.
|
|
10793
|
-
*
|
|
10794
|
-
* Every transition returns the whole next row (or a drop), so the caller can persist it
|
|
10795
|
-
* through one state transaction. Invalid transitions are refused by name;
|
|
10796
|
-
* a caller never "repairs" a row by guessing which state the operator meant.
|
|
10797
|
-
*/
|
|
10798
|
-
function invalid(event, state) {
|
|
10799
|
-
return {
|
|
10800
|
-
ok: false,
|
|
10801
|
-
code: "invalid-transition",
|
|
10802
|
-
message: "cannot apply " + event.type + " to " + (state ?? "no row")
|
|
10803
|
-
};
|
|
10804
|
-
}
|
|
10805
|
-
/** Drop fields that must not survive a transition; optional fields stay absent. */
|
|
10806
|
-
function base(row, at) {
|
|
10807
|
-
return {
|
|
10808
|
-
id: row.id,
|
|
10809
|
-
pairKey: row.pairKey,
|
|
10810
|
-
a: row.a,
|
|
10811
|
-
b: row.b,
|
|
10812
|
-
state: row.state,
|
|
10813
|
-
queue: row.queue,
|
|
10814
|
-
createdAt: row.createdAt,
|
|
10815
|
-
updatedAt: at,
|
|
10816
|
-
...row.runId === void 0 ? {} : { runId: row.runId },
|
|
10817
|
-
...row.unitId === void 0 ? {} : { unitId: row.unitId },
|
|
10818
|
-
...row.origin === void 0 ? {} : { origin: row.origin },
|
|
10819
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
10820
|
-
...row.sourceRevision === void 0 ? {} : { sourceRevision: row.sourceRevision },
|
|
10821
|
-
...row.targetRevision === void 0 ? {} : { targetRevision: row.targetRevision },
|
|
10822
|
-
...row.attempts === void 0 ? {} : { attempts: row.attempts },
|
|
10823
|
-
...row.stagingRef === void 0 ? {} : { stagingRef: row.stagingRef },
|
|
10824
|
-
...row.stagingExpiresAt === void 0 ? {} : { stagingExpiresAt: row.stagingExpiresAt },
|
|
10825
|
-
...row.expired === void 0 ? {} : { expired: row.expired },
|
|
10826
|
-
...row.reason === void 0 ? {} : { reason: row.reason },
|
|
10827
|
-
...row.target === void 0 ? {} : { target: row.target }
|
|
10828
|
-
};
|
|
10829
|
-
}
|
|
10830
|
-
function next(row, at, state, patch = {}) {
|
|
10831
|
-
return {
|
|
10832
|
-
ok: true,
|
|
10833
|
-
row: {
|
|
10834
|
-
...base(row, at),
|
|
10835
|
-
state,
|
|
10836
|
-
queue: queueOf(state),
|
|
10837
|
-
...patch
|
|
10838
|
-
}
|
|
10839
|
-
};
|
|
10840
|
-
}
|
|
10841
|
-
/** Legacy v2 projection only; runtime writes must use transitionV3/RowTx. */
|
|
10842
|
-
function transitionLegacyForProjection(current, event) {
|
|
10843
|
-
if (event.type === "candidate") {
|
|
10844
|
-
if (current !== void 0) return {
|
|
10845
|
-
ok: true,
|
|
10846
|
-
row: current
|
|
10847
|
-
};
|
|
10848
|
-
const key = pairKey(event.a, event.b);
|
|
10849
|
-
return {
|
|
10850
|
-
ok: true,
|
|
10851
|
-
row: {
|
|
10852
|
-
id: rowIdOf(key),
|
|
10853
|
-
pairKey: key,
|
|
10854
|
-
a: event.a,
|
|
10855
|
-
b: event.b,
|
|
10856
|
-
state: "verify",
|
|
10857
|
-
queue: "verify",
|
|
10858
|
-
createdAt: event.at,
|
|
10859
|
-
updatedAt: event.at
|
|
10860
|
-
}
|
|
10861
|
-
};
|
|
10862
|
-
}
|
|
10863
|
-
if (event.type === "source-gone") return {
|
|
10864
|
-
ok: true,
|
|
10865
|
-
row: null
|
|
10866
|
-
};
|
|
10867
|
-
if (event.type === "gate-keep") {
|
|
10868
|
-
if (current !== void 0) return {
|
|
10869
|
-
ok: true,
|
|
10870
|
-
row: current
|
|
10871
|
-
};
|
|
10872
|
-
const key = pairKey(event.a, event.b);
|
|
10873
|
-
return {
|
|
10874
|
-
ok: true,
|
|
10875
|
-
row: {
|
|
10876
|
-
id: rowIdOf(key),
|
|
10877
|
-
pairKey: key,
|
|
10878
|
-
a: event.a,
|
|
10879
|
-
b: event.b,
|
|
10880
|
-
state: "skipped",
|
|
10881
|
-
queue: "skipped",
|
|
10882
|
-
origin: "agent",
|
|
10883
|
-
createdAt: event.at,
|
|
10884
|
-
updatedAt: event.at
|
|
10885
|
-
}
|
|
10886
|
-
};
|
|
10887
|
-
}
|
|
10888
|
-
if (current === void 0) return invalid(event, void 0);
|
|
10889
|
-
switch (event.type) {
|
|
10890
|
-
case "round1-keep": return current.state === "verify" ? next(current, event.at, "skipped", { origin: "agent" }) : invalid(event, current.state);
|
|
10891
|
-
case "round1-merge":
|
|
10892
|
-
if (current.state !== "verify") return invalid(event, current.state);
|
|
10893
|
-
return event.approval === "on" ? next(current, event.at, "pending", {
|
|
10894
|
-
...event.decision === void 0 ? {} : { decision: event.decision },
|
|
10895
|
-
...event.stagingRef === void 0 ? {} : { stagingRef: event.stagingRef },
|
|
10896
|
-
...event.stagingExpiresAt === void 0 ? {} : { stagingExpiresAt: event.stagingExpiresAt },
|
|
10897
|
-
...event.sourceRevision === void 0 ? {} : { sourceRevision: event.sourceRevision },
|
|
10898
|
-
...event.targetRevision === void 0 ? {} : { targetRevision: event.targetRevision }
|
|
10899
|
-
}) : next(current, event.at, "approved", {
|
|
10900
|
-
...event.decision === void 0 ? {} : { decision: event.decision },
|
|
10901
|
-
...event.stagingRef === void 0 ? {} : { stagingRef: event.stagingRef },
|
|
10902
|
-
...event.stagingExpiresAt === void 0 ? {} : { stagingExpiresAt: event.stagingExpiresAt },
|
|
10903
|
-
...event.sourceRevision === void 0 ? {} : { sourceRevision: event.sourceRevision },
|
|
10904
|
-
...event.targetRevision === void 0 ? {} : { targetRevision: event.targetRevision }
|
|
10905
|
-
});
|
|
10906
|
-
case "round1-fail": return current.state === "verify" ? next(current, event.at, "verify", {
|
|
10907
|
-
failure: event.failure,
|
|
10908
|
-
attempts: (current.attempts ?? 0) + 1
|
|
10909
|
-
}) : invalid(event, current.state);
|
|
10910
|
-
case "approve": return current.state === "pending" ? next(current, event.at, "approved", event.runId === void 0 ? {} : { runId: event.runId }) : invalid(event, current.state);
|
|
10911
|
-
case "reject": return current.state === "pending" ? next(current, event.at, "skipped", { origin: "human" }) : invalid(event, current.state);
|
|
10912
|
-
case "round2-cancel": return current.state === "fuse" || current.state === "approved" ? next(current, event.at, "approved") : invalid(event, current.state);
|
|
10913
|
-
case "round2-fail": return current.state === "fuse" || current.state === "approved" ? next(current, event.at, "approved", {
|
|
10914
|
-
failure: event.failure,
|
|
10915
|
-
attempts: (current.attempts ?? 0) + 1
|
|
10916
|
-
}) : invalid(event, current.state);
|
|
10917
|
-
case "round2-success": return current.state === "fuse" || current.state === "approved" ? {
|
|
10918
|
-
ok: true,
|
|
10919
|
-
row: null
|
|
10920
|
-
} : invalid(event, current.state);
|
|
10921
|
-
case "target-taken":
|
|
10922
|
-
case "source-changed": return current.state === "pending" || current.state === "approved" || current.state === "fuse" ? next(current, event.at, current.state, { expired: event.type }) : invalid(event, current.state);
|
|
10923
|
-
case "restore": return current.state === "skipped" ? next(current, event.at, "verify") : invalid(event, current.state);
|
|
10924
|
-
}
|
|
10925
|
-
}
|
|
10926
|
-
//#endregion
|
|
10927
10344
|
//#region lib/types/pair-command.js
|
|
10928
10345
|
async function runPairCommand(options) {
|
|
10929
10346
|
return await runScanCommand({
|
|
@@ -11386,4 +10803,4 @@ function apply(ctx, rawConfig = {}) {
|
|
|
11386
10803
|
});
|
|
11387
10804
|
}
|
|
11388
10805
|
//#endregion
|
|
11389
|
-
export { Config,
|
|
10806
|
+
export { Config, MERGE_LIFECYCLE_VERBS, MERGE_MAX_ATTEMPTS, MERGE_PAIR_STATES, MERGE_PARAM_DEFAULTS, MERGE_PROMPT_VERSION, MERGE_ROUTES, MERGE_STAGE_TOOL_NAME, MERGE_STATE_VERSION, STAGING_SCHEMA_VERSION, STANDBY_PROMPT, StageToolRegistry, apply, applyStageTool, approvePending, assembleStagedCommit, buildCommitPlan, buildRound1Prompt, buildRound2Prompt, busyTarget, canRetry, cleanupExpiredStaging, commitReceiptPath, commitStagedRun, committedPairs, configureMergePresentation, copyStagedFile, countRows, createChannelScanPorts, createEngineRunner, createEngineScreening, createMergeCommand, createMergeRuntime, createMergeStageTool, createNewChildRound2, createReadOnlyMergeService, createStageForCards, createStaging, durableReceiptDir, durableReceiptPath, emptyMergeState, engineConfigFromRoot, forcedDecisionFor, formatFacts, formatQueue, formatRunDetail, formatRunsView, formatSnapshotQueue, formatSnapshotStatus, formatStatus, handleReadOnlyMergeCommand, hasBlockingFinding, inject, listStagedFiles, liveRowFactsOf, loadMergeState, makeMergeRoutes, manifestFilesOf, mergeDoctor, mergeDoctorAvailability, mergeDoctorFact, mergeReportDigestPath, mergeReportPath, mergeRunIdsToSupersede, mergeStatePath, mergeUsage, missingManifestFile, pairKey, parseAuthoringManifest, parseDecision, parseMergeCommand, pendingExpiry, persistedExpiry, promptHashOf, queueOf, readCommitReceipt, readCommitReceipts, readMergeReport, readStagedFile, readStagedTree, readStaging, recordRound2Outcome, rejectPending, resolveMergeParams, resolveTargetName, retryMergeReport, rewriteFrontmatterName, rowIdOf, rowsOf, runApproveCommand, runAuthoring, runMergeCommand, runNewChildAuthoring, runPairCommand, runResumeCommand, runRound1OverChannel, runScan, runScanCommand, setStagingTarget, skillLibraryPort, skillLibraryUndoPort, skippedPairKeys, snapshotCards, sourceBlock, stageKeyOf, stageOf, stagingRoot, subagentChannelAdapter, supersedeMergeRuns, targetAdmission, undoMergeReceipt, unitFor, validateStagedTree, withMergeRun, writeCommitReceipt, writeMergeReport, writeStagedFile };
|