@lmzhen/dsh-evolution-merge 0.46.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 +248 -1224
- 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 -6
- package/lib/types/merge-routes.d.ts +5 -21
- package/lib/types/merge-routes.js +53 -93
- 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 +1 -39
- package/lib/types/state.js +2 -78
- package/lib/types/surface/merge-view.d.ts +1 -2
- package/lib/types/surface/merge-view.js +1 -2
- 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/types/facts.d.ts +0 -26
- package/lib/types/facts.js +0 -65
- package/lib/types/metrics.d.ts +0 -16
- package/lib/types/metrics.js +0 -27
- package/lib/types/wire-projection.d.ts +0 -36
- package/lib/types/wire-projection.js +0 -77
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) {
|
|
@@ -1273,7 +1267,7 @@ function parseV4State(raw) {
|
|
|
1273
1267
|
* The one merge-state ledger: <home>/merge/merge-state.json.
|
|
1274
1268
|
*
|
|
1275
1269
|
* Reads are pure projections (no write, no reconciliation side effect). Every write goes
|
|
1276
|
-
* through
|
|
1270
|
+
* through pairLedger and a single transactIo, so there is no second file and no
|
|
1277
1271
|
* incremental writer. A row's queue is always derived from its state on read; a hand-edited
|
|
1278
1272
|
* mismatch is repaired by the next write, never by a GET.
|
|
1279
1273
|
*/
|
|
@@ -1346,107 +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
|
-
/** G3-5 runtime write API: only createVerify/createSkipped/transition. v2 writes are rejected. */
|
|
1361
|
-
async function transactRows(_io, _home, _fn) {
|
|
1362
|
-
throw new Error("legacy-writer-removed");
|
|
1363
|
-
}
|
|
1364
|
-
/** The ONE write point. The callback returns the whole row set, not a delta. */
|
|
1365
|
-
async function mutateMergeState(_io, _home, _now, _fn) {
|
|
1366
|
-
throw new Error("legacy-writer-removed");
|
|
1367
|
-
}
|
|
1368
|
-
async function upsertRow(io, home, now, row, expect = "any", cas) {
|
|
1369
|
-
return await mutateMergeState(io, home, now, (rows) => {
|
|
1370
|
-
const index = rows.findIndex((item) => item.pairKey === row.pairKey);
|
|
1371
|
-
const current = index < 0 ? void 0 : rows[index];
|
|
1372
|
-
if (cas !== void 0 && (cas === null && current !== void 0 || cas !== null && current?.updatedAt !== cas)) return {
|
|
1373
|
-
rows,
|
|
1374
|
-
result: {
|
|
1375
|
-
ok: false,
|
|
1376
|
-
current: current ?? row
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1379
|
-
if (current !== void 0 && expect !== "any" && (expect === "absent" || queueOf(current.state) !== expect)) return {
|
|
1380
|
-
rows,
|
|
1381
|
-
result: {
|
|
1382
|
-
ok: false,
|
|
1383
|
-
current
|
|
1384
|
-
}
|
|
1385
|
-
};
|
|
1386
|
-
if (current === void 0 && expect !== "any" && expect !== "absent" && expect !== "verify") return {
|
|
1387
|
-
rows,
|
|
1388
|
-
result: {
|
|
1389
|
-
ok: false,
|
|
1390
|
-
current: row
|
|
1391
|
-
}
|
|
1392
|
-
};
|
|
1393
|
-
const normalized = {
|
|
1394
|
-
...row,
|
|
1395
|
-
queue: queueOf(row.state)
|
|
1396
|
-
};
|
|
1397
|
-
const next = [...rows];
|
|
1398
|
-
if (current === void 0) next.push(normalized);
|
|
1399
|
-
else next[index] = {
|
|
1400
|
-
...normalized,
|
|
1401
|
-
createdAt: current.createdAt
|
|
1402
|
-
};
|
|
1403
|
-
return {
|
|
1404
|
-
rows: next,
|
|
1405
|
-
result: { ok: true }
|
|
1406
|
-
};
|
|
1407
|
-
});
|
|
1408
|
-
}
|
|
1409
|
-
async function moveRow(io, home, now, id, patch) {
|
|
1410
|
-
return await mutateMergeState(io, home, now, (rows) => {
|
|
1411
|
-
const index = rows.findIndex((item) => item.id === id);
|
|
1412
|
-
if (index < 0) return {
|
|
1413
|
-
rows,
|
|
1414
|
-
result: void 0
|
|
1415
|
-
};
|
|
1416
|
-
const current = rows[index];
|
|
1417
|
-
const state = patch.state ?? current.state;
|
|
1418
|
-
const next = {
|
|
1419
|
-
...current,
|
|
1420
|
-
state,
|
|
1421
|
-
queue: queueOf(state),
|
|
1422
|
-
updatedAt: new Date(now()).toISOString(),
|
|
1423
|
-
...patch.failure === void 0 ? {} : { failure: patch.failure },
|
|
1424
|
-
...patch.runId === void 0 ? {} : { runId: patch.runId },
|
|
1425
|
-
...patch.unitId === void 0 ? {} : { unitId: patch.unitId },
|
|
1426
|
-
...patch.origin === void 0 ? {} : { origin: patch.origin },
|
|
1427
|
-
...patch.attempts === void 0 ? {} : { attempts: patch.attempts }
|
|
1428
|
-
};
|
|
1429
|
-
const copy = [...rows];
|
|
1430
|
-
copy[index] = next;
|
|
1431
|
-
return {
|
|
1432
|
-
rows: copy,
|
|
1433
|
-
result: next
|
|
1434
|
-
};
|
|
1435
|
-
});
|
|
1436
|
-
}
|
|
1437
|
-
/** G3-5 v3-aware drop: only terminal events. */
|
|
1438
|
-
async function dropRowV3(_io, _home, _id, _event, _unitId = "unknown") {
|
|
1439
|
-
throw new Error("legacy-writer-removed");
|
|
1440
|
-
}
|
|
1441
|
-
async function dropRow(io, home, now, id) {
|
|
1442
|
-
return await mutateMergeState(io, home, now, (rows) => {
|
|
1443
|
-
const next = rows.filter((item) => item.id !== id);
|
|
1444
|
-
return {
|
|
1445
|
-
rows: next,
|
|
1446
|
-
result: next.length !== rows.length
|
|
1447
|
-
};
|
|
1448
|
-
});
|
|
1449
|
-
}
|
|
1450
1343
|
async function rowsOf(io, home, queue) {
|
|
1451
1344
|
const loaded = await loadMergeState(io, home);
|
|
1452
1345
|
return queue === void 0 ? loaded.state.rows : loaded.state.rows.filter((row) => row.queue === queue);
|
|
@@ -1709,7 +1602,7 @@ function v3State(body) {
|
|
|
1709
1602
|
rows
|
|
1710
1603
|
};
|
|
1711
1604
|
}
|
|
1712
|
-
async function readJournal
|
|
1605
|
+
async function readJournal(io, home) {
|
|
1713
1606
|
const raw = await readTextOrNull(io, migrationJournalPath(home));
|
|
1714
1607
|
if (raw === null) return null;
|
|
1715
1608
|
try {
|
|
@@ -1786,7 +1679,7 @@ async function readStateReadiness(io, home) {
|
|
|
1786
1679
|
if (version === 3) {
|
|
1787
1680
|
const state = v3State(body);
|
|
1788
1681
|
if (state === null) return blocked("merge-state-needs-repair", "v3 state has an invalid row");
|
|
1789
|
-
const journal = await readJournal
|
|
1682
|
+
const journal = await readJournal(io, home);
|
|
1790
1683
|
const report = await readReport(io, home);
|
|
1791
1684
|
const marker = readMarker(body);
|
|
1792
1685
|
if (body.migration !== void 0 && marker === null) return blocked("merge-state-needs-repair", "migration marker is invalid");
|
|
@@ -1845,7 +1738,7 @@ async function ensureMergeStateReady(io, home, fence) {
|
|
|
1845
1738
|
outcome = blocked("merge-state-needs-repair", "v3 state has an invalid row");
|
|
1846
1739
|
return current;
|
|
1847
1740
|
}
|
|
1848
|
-
const journal = await readJournal
|
|
1741
|
+
const journal = await readJournal(io, home);
|
|
1849
1742
|
if (journal !== null) {
|
|
1850
1743
|
outcome = await completeJournal(io, home, journal, current);
|
|
1851
1744
|
return current;
|
|
@@ -2090,15 +1983,6 @@ async function readStaging(io, home, runId) {
|
|
|
2090
1983
|
return probeUnknown("staging manifest is not JSON: " + (error instanceof Error ? error.message : String(error)));
|
|
2091
1984
|
}
|
|
2092
1985
|
}
|
|
2093
|
-
async function ensureStaging(io, home, input) {
|
|
2094
|
-
const existing = await readStaging(io, home, input.runId);
|
|
2095
|
-
if (existing.kind === "present") return {
|
|
2096
|
-
ok: true,
|
|
2097
|
-
path: stagingRoot(home, input.runId),
|
|
2098
|
-
manifest: existing.value.manifest
|
|
2099
|
-
};
|
|
2100
|
-
return createStaging(io, home, input);
|
|
2101
|
-
}
|
|
2102
1986
|
async function setStagingTarget(io, home, stageKey, target, mode) {
|
|
2103
1987
|
const view = await readStaging(io, home, stageKey);
|
|
2104
1988
|
if (view.kind !== "present") return false;
|
|
@@ -2106,9 +1990,6 @@ async function setStagingTarget(io, home, stageKey, target, mode) {
|
|
|
2106
1990
|
await io.writeText(join(stagingRoot(home, stageKey), "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
2107
1991
|
return true;
|
|
2108
1992
|
}
|
|
2109
|
-
async function dropStaging(io, home, stageKey) {
|
|
2110
|
-
await io.remove(stagingRoot(home, stageKey));
|
|
2111
|
-
}
|
|
2112
1993
|
/** Remove expired run-level staging trees; `keep` names runs a live row still points at. */
|
|
2113
1994
|
async function cleanupExpiredStaging(io, home, now, keep = /* @__PURE__ */ new Set()) {
|
|
2114
1995
|
let runs;
|
|
@@ -2265,6 +2146,7 @@ async function adoptLegacyProduction(io, home) {
|
|
|
2265
2146
|
wrote
|
|
2266
2147
|
};
|
|
2267
2148
|
}
|
|
2149
|
+
/** Production stage-tree facade. These wrappers keep the low-level tree module private to StageAggregate. */
|
|
2268
2150
|
async function createStageTree(io, home, input) {
|
|
2269
2151
|
return await createStaging(io, home, input);
|
|
2270
2152
|
}
|
|
@@ -2537,61 +2419,6 @@ async function readPairLedgerV4(io, home) {
|
|
|
2537
2419
|
};
|
|
2538
2420
|
}
|
|
2539
2421
|
//#endregion
|
|
2540
|
-
//#region lib/types/domain/pair-index.js
|
|
2541
|
-
function parsePairIndex(raw) {
|
|
2542
|
-
const index = /* @__PURE__ */ new Map();
|
|
2543
|
-
if (raw === null) return index;
|
|
2544
|
-
let parsed;
|
|
2545
|
-
try {
|
|
2546
|
-
parsed = JSON.parse(raw);
|
|
2547
|
-
} catch {
|
|
2548
|
-
return index;
|
|
2549
|
-
}
|
|
2550
|
-
const body = parsed;
|
|
2551
|
-
if (!Array.isArray(body.entries)) return index;
|
|
2552
|
-
for (const value of body.entries) {
|
|
2553
|
-
const entry = value;
|
|
2554
|
-
if (typeof entry.pairKey !== "string" || typeof entry.runId !== "string" || typeof entry.result !== "string") continue;
|
|
2555
|
-
if (![
|
|
2556
|
-
"merged",
|
|
2557
|
-
"kept",
|
|
2558
|
-
"failed",
|
|
2559
|
-
"cancelled",
|
|
2560
|
-
"undone"
|
|
2561
|
-
].includes(entry.result)) continue;
|
|
2562
|
-
index.set(entry.pairKey, entry);
|
|
2563
|
-
}
|
|
2564
|
-
return index;
|
|
2565
|
-
}
|
|
2566
|
-
function serializePairIndex(index) {
|
|
2567
|
-
return JSON.stringify({
|
|
2568
|
-
schemaVersion: 1,
|
|
2569
|
-
entries: [...index.values()]
|
|
2570
|
-
}, null, 2);
|
|
2571
|
-
}
|
|
2572
|
-
//#endregion
|
|
2573
|
-
//#region lib/types/domain/pair-index-store.js
|
|
2574
|
-
/** Durable pairKey index at <home>/merge/pair-index.json. */
|
|
2575
|
-
function pairIndexPath(home) {
|
|
2576
|
-
return join(home, "merge", "pair-index.json");
|
|
2577
|
-
}
|
|
2578
|
-
async function loadPairIndex(io, home) {
|
|
2579
|
-
let raw = null;
|
|
2580
|
-
try {
|
|
2581
|
-
raw = await io.readText(pairIndexPath(home));
|
|
2582
|
-
} catch {
|
|
2583
|
-
return /* @__PURE__ */ new Map();
|
|
2584
|
-
}
|
|
2585
|
-
return parsePairIndex(raw);
|
|
2586
|
-
}
|
|
2587
|
-
async function recordPair(io, home, entry) {
|
|
2588
|
-
await transactIo(io, pairIndexPath(home), (current) => {
|
|
2589
|
-
const index = parsePairIndex(current);
|
|
2590
|
-
index.set(entry.pairKey, entry);
|
|
2591
|
-
return serializePairIndex(index);
|
|
2592
|
-
});
|
|
2593
|
-
}
|
|
2594
|
-
//#endregion
|
|
2595
2422
|
//#region lib/types/domain/run-coordinator.js
|
|
2596
2423
|
/** 1b-1 additive types for the merge run lifecycle; no writer is active in this phase. */
|
|
2597
2424
|
function runMetaPath(home, runId) {
|
|
@@ -2924,7 +2751,7 @@ const emptyCounts = {
|
|
|
2924
2751
|
},
|
|
2925
2752
|
expired: 0
|
|
2926
2753
|
};
|
|
2927
|
-
const queueOf$
|
|
2754
|
+
const queueOf$1 = (state) => state === "approved" || state === "fuse" ? "fuse" : state === "verify" ? "verify" : state === "pending" ? "pending" : "skipped";
|
|
2928
2755
|
async function readMergeSnapshot(options) {
|
|
2929
2756
|
const readAt = (options.now ?? (() => Date.now()))();
|
|
2930
2757
|
const hostOnly = options.hostOnly === void 0 ? void 0 : await options.hostOnly().catch((error) => ({
|
|
@@ -2976,7 +2803,7 @@ async function readMergeSnapshot(options) {
|
|
|
2976
2803
|
const live = options.live !== void 0 && (ledger?.rows ?? []).some((row) => row.state === "pending" && row.expired === void 0 || row.state === "verify" || row.state === "fuse" || row.state === "approved") ? await options.live().catch(() => void 0) : void 0;
|
|
2977
2804
|
for (const row of ledger?.rows ?? []) {
|
|
2978
2805
|
const stage = stages.find((item) => item.rowId === row.id) ?? null;
|
|
2979
|
-
const queue = queueOf$
|
|
2806
|
+
const queue = queueOf$1(row.state);
|
|
2980
2807
|
const bSide = live !== void 0 && live.managed(row.b) ? "live" : "archive";
|
|
2981
2808
|
const bodies = [{
|
|
2982
2809
|
rowId: row.id,
|
|
@@ -2998,19 +2825,18 @@ async function readMergeSnapshot(options) {
|
|
|
2998
2825
|
});
|
|
2999
2826
|
bodyRefs.push(...bodies);
|
|
3000
2827
|
}
|
|
3001
|
-
const pairIndex = await loadPairIndex(options.io, options.home);
|
|
3002
2828
|
const runs = [];
|
|
3003
2829
|
for (const record of options.runs) {
|
|
3004
2830
|
const meta = await readRunMeta(options.io, options.home, record.id);
|
|
3005
|
-
const pairs = [...pairIndex.values()].filter((item) => item.runId === record.id).map((item) => ({
|
|
3006
|
-
pairKey: item.pairKey,
|
|
3007
|
-
runId: item.runId,
|
|
3008
|
-
result: item.result,
|
|
3009
|
-
...item.target === void 0 ? {} : { target: item.target }
|
|
3010
|
-
}));
|
|
3011
2831
|
const reportPath = mergeReportPath(options.home, record.id);
|
|
3012
2832
|
const probe = await readMergeReport(options.io, options.home, record.id);
|
|
3013
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
|
+
}));
|
|
3014
2840
|
runs.push({
|
|
3015
2841
|
record,
|
|
3016
2842
|
meta,
|
|
@@ -3082,8 +2908,9 @@ async function readMergeSnapshot(options) {
|
|
|
3082
2908
|
})).digest("hex");
|
|
3083
2909
|
const notes = [...options.notes ?? []];
|
|
3084
2910
|
if (historyDegraded) notes.push("history archive port unavailable; receipts only");
|
|
3085
|
-
const
|
|
3086
|
-
|
|
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) + ")");
|
|
3087
2914
|
return {
|
|
3088
2915
|
wireVersion: 1,
|
|
3089
2916
|
schemaVersion: 4,
|
|
@@ -3295,34 +3122,10 @@ var MergeUnitTransactions = class {
|
|
|
3295
3122
|
await this.options.onPhase?.(phase);
|
|
3296
3123
|
};
|
|
3297
3124
|
try {
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
} else {
|
|
3303
|
-
const fallbackLease = await new HomeAuthority({
|
|
3304
|
-
home: this.options.home,
|
|
3305
|
-
waitMs: this.options.waitMs ?? 5e3
|
|
3306
|
-
}).lease("tree").catch(() => void 0);
|
|
3307
|
-
if (fallbackLease === void 0) return {
|
|
3308
|
-
ok: false,
|
|
3309
|
-
code: "unit-fence-failed",
|
|
3310
|
-
message: "tree lock unavailable"
|
|
3311
|
-
};
|
|
3312
|
-
fenceLease = {
|
|
3313
|
-
lock: leaseAsTreeLock(fallbackLease),
|
|
3314
|
-
release: async () => {
|
|
3315
|
-
await fallbackLease.release();
|
|
3316
|
-
}
|
|
3317
|
-
};
|
|
3318
|
-
lock = fenceLease.lock;
|
|
3319
|
-
this.options.onLock?.("tree");
|
|
3320
|
-
}
|
|
3321
|
-
if (!await lock.assertHeld()) return {
|
|
3322
|
-
ok: false,
|
|
3323
|
-
code: "unit-fence-failed",
|
|
3324
|
-
message: "tree fence lost"
|
|
3325
|
-
};
|
|
3125
|
+
const acquired = await this.acquireTreeFence();
|
|
3126
|
+
fenceLease = acquired.fenceLease;
|
|
3127
|
+
lock = acquired.lock;
|
|
3128
|
+
this.options.onLock?.("tree");
|
|
3326
3129
|
stage = "claim";
|
|
3327
3130
|
claim = await this.options.claim.acquire(stored.plan.target, stored.plan.runId);
|
|
3328
3131
|
this.options.onLock?.("claim");
|
|
@@ -3458,6 +3261,82 @@ var MergeUnitTransactions = class {
|
|
|
3458
3261
|
await lease.release();
|
|
3459
3262
|
}
|
|
3460
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
|
+
}
|
|
3461
3340
|
async finalize(unitId) {
|
|
3462
3341
|
return await this.withRecoveryFence(async () => this.finalizeUnlocked(unitId));
|
|
3463
3342
|
}
|
|
@@ -3502,55 +3381,13 @@ var MergeUnitTransactions = class {
|
|
|
3502
3381
|
code: "unit-rollback-blocked",
|
|
3503
3382
|
message: "source is still live: " + liveSource.name
|
|
3504
3383
|
};
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
if (!supportMatches()) {
|
|
3511
|
-
if (![
|
|
3512
|
-
"support-pending",
|
|
3513
|
-
"sources-archived",
|
|
3514
|
-
"unit-written"
|
|
3515
|
-
].includes(journal.phase) || this.options.backend.restoreSupportFile === void 0) return {
|
|
3516
|
-
ok: false,
|
|
3517
|
-
code: "unit-rollback-blocked",
|
|
3518
|
-
message: "support file live hash does not match the prepared support; manual recovery required"
|
|
3519
|
-
};
|
|
3520
|
-
for (const file of snapshot.supportAfter) await this.options.backend.restoreSupportFile(snapshot.target, file.path, file.content);
|
|
3521
|
-
liveSupport = await Promise.all(snapshot.supportAfter.map(async (file) => ({
|
|
3522
|
-
path: file.path,
|
|
3523
|
-
content: await this.options.backend.readSupportFile(snapshot.target, file.path)
|
|
3524
|
-
})));
|
|
3525
|
-
if (!supportMatches()) return {
|
|
3526
|
-
ok: false,
|
|
3527
|
-
code: "unit-rollback-blocked",
|
|
3528
|
-
message: "support file could not be completed from the prepared snapshot"
|
|
3529
|
-
};
|
|
3530
|
-
}
|
|
3531
|
-
const evidence = {
|
|
3532
|
-
schemaVersion: 1,
|
|
3533
|
-
unitId,
|
|
3534
|
-
runId: snapshot.runId,
|
|
3535
|
-
planDigest: snapshot.planDigest,
|
|
3536
|
-
state: "complete",
|
|
3537
|
-
target: {
|
|
3538
|
-
before: snapshot.targetBefore,
|
|
3539
|
-
after: await this.options.backend.readSkill(snapshot.target) ?? "",
|
|
3540
|
-
supportDigest: createHash("sha256").update(JSON.stringify(snapshot.supportAfter)).digest("hex"),
|
|
3541
|
-
created: !snapshot.targetExists
|
|
3542
|
-
},
|
|
3543
|
-
sources: snapshot.sourceBefore.map((source) => ({
|
|
3544
|
-
name: source.name,
|
|
3545
|
-
before: source.body,
|
|
3546
|
-
after: null,
|
|
3547
|
-
archived: checkpoints.some((item) => item.source === source.name),
|
|
3548
|
-
absorbedInto: snapshot.target
|
|
3549
|
-
})),
|
|
3550
|
-
mutations: 0,
|
|
3551
|
-
...snapshot.validationPlan === void 0 ? {} : { validationPlan: snapshot.validationPlan },
|
|
3552
|
-
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
|
|
3553
3389
|
};
|
|
3390
|
+
const evidence = await this.evidenceFor(unitId, snapshot, journal, await this.options.backend.readSkill(snapshot.target) ?? "");
|
|
3554
3391
|
if (receipt?.evidenceSha256 !== void 0 && unitEvidenceDigest(evidence) !== receipt.evidenceSha256) return {
|
|
3555
3392
|
ok: false,
|
|
3556
3393
|
code: "unit-rollback-blocked",
|
|
@@ -3612,55 +3449,13 @@ var MergeUnitTransactions = class {
|
|
|
3612
3449
|
code: "unit-rollback-blocked",
|
|
3613
3450
|
message: "source is still live: " + liveSource.name
|
|
3614
3451
|
};
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
if (!supportMatches()) {
|
|
3621
|
-
if (![
|
|
3622
|
-
"support-pending",
|
|
3623
|
-
"sources-archived",
|
|
3624
|
-
"unit-written"
|
|
3625
|
-
].includes(journal.phase) || this.options.backend.restoreSupportFile === void 0) return {
|
|
3626
|
-
ok: false,
|
|
3627
|
-
code: "unit-rollback-blocked",
|
|
3628
|
-
message: "support file live hash does not match the prepared support; manual recovery required"
|
|
3629
|
-
};
|
|
3630
|
-
for (const file of snapshot.supportAfter) await this.options.backend.restoreSupportFile(snapshot.target, file.path, file.content);
|
|
3631
|
-
liveSupport = await Promise.all(snapshot.supportAfter.map(async (file) => ({
|
|
3632
|
-
path: file.path,
|
|
3633
|
-
content: await this.options.backend.readSupportFile(snapshot.target, file.path)
|
|
3634
|
-
})));
|
|
3635
|
-
if (!supportMatches()) return {
|
|
3636
|
-
ok: false,
|
|
3637
|
-
code: "unit-rollback-blocked",
|
|
3638
|
-
message: "support file could not be completed from the prepared snapshot"
|
|
3639
|
-
};
|
|
3640
|
-
}
|
|
3641
|
-
const evidence = {
|
|
3642
|
-
schemaVersion: 1,
|
|
3643
|
-
unitId,
|
|
3644
|
-
runId: snapshot.runId,
|
|
3645
|
-
planDigest: snapshot.planDigest,
|
|
3646
|
-
state: "complete",
|
|
3647
|
-
target: {
|
|
3648
|
-
before: snapshot.targetBefore,
|
|
3649
|
-
after: targetAfter,
|
|
3650
|
-
supportDigest: createHash("sha256").update(JSON.stringify(snapshot.supportAfter)).digest("hex"),
|
|
3651
|
-
created: !snapshot.targetExists
|
|
3652
|
-
},
|
|
3653
|
-
sources: snapshot.sourceBefore.map((source) => ({
|
|
3654
|
-
name: source.name,
|
|
3655
|
-
before: source.body,
|
|
3656
|
-
after: null,
|
|
3657
|
-
archived: checkpoints.some((item) => item.source === source.name),
|
|
3658
|
-
absorbedInto: snapshot.target
|
|
3659
|
-
})),
|
|
3660
|
-
mutations: 0,
|
|
3661
|
-
...snapshot.validationPlan === void 0 ? {} : { validationPlan: snapshot.validationPlan },
|
|
3662
|
-
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
|
|
3663
3457
|
};
|
|
3458
|
+
const evidence = await this.evidenceFor(unitId, snapshot, journal, targetAfter);
|
|
3664
3459
|
await writeUnitEvidence(this.options.io, this.options.home, evidence);
|
|
3665
3460
|
await writeUnitJournal(this.options.io, this.options.home, {
|
|
3666
3461
|
...journal,
|
|
@@ -3692,33 +3487,10 @@ var MergeUnitTransactions = class {
|
|
|
3692
3487
|
let lock;
|
|
3693
3488
|
let claim;
|
|
3694
3489
|
try {
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
} else {
|
|
3699
|
-
const fallbackLease = await new HomeAuthority({
|
|
3700
|
-
home: this.options.home,
|
|
3701
|
-
waitMs: this.options.waitMs ?? 5e3
|
|
3702
|
-
}).lease("tree").catch(() => void 0);
|
|
3703
|
-
if (fallbackLease === void 0) return {
|
|
3704
|
-
ok: false,
|
|
3705
|
-
code: "unit-fence-failed",
|
|
3706
|
-
message: "tree lock unavailable"
|
|
3707
|
-
};
|
|
3708
|
-
fenceLease = {
|
|
3709
|
-
lock: leaseAsTreeLock(fallbackLease),
|
|
3710
|
-
release: async () => {
|
|
3711
|
-
await fallbackLease.release();
|
|
3712
|
-
}
|
|
3713
|
-
};
|
|
3714
|
-
lock = fenceLease.lock;
|
|
3715
|
-
}
|
|
3490
|
+
const acquired = await this.acquireTreeFence();
|
|
3491
|
+
fenceLease = acquired.fenceLease;
|
|
3492
|
+
lock = acquired.lock;
|
|
3716
3493
|
this.options.onLock?.("tree");
|
|
3717
|
-
if (!await lock.assertHeld()) return {
|
|
3718
|
-
ok: false,
|
|
3719
|
-
code: "unit-fence-failed",
|
|
3720
|
-
message: "tree fence lost"
|
|
3721
|
-
};
|
|
3722
3494
|
claim = await this.options.claim.acquire(snapshot.target, snapshot.runId);
|
|
3723
3495
|
this.options.onLock?.("claim");
|
|
3724
3496
|
const currentTarget = await this.options.backend.readSkill(snapshot.target);
|
|
@@ -4438,7 +4210,7 @@ function verifyState(row) {
|
|
|
4438
4210
|
if (row.row.verifySubState === "screened") return "running";
|
|
4439
4211
|
return "queued";
|
|
4440
4212
|
}
|
|
4441
|
-
function toRowFact
|
|
4213
|
+
function toRowFact(row) {
|
|
4442
4214
|
const state = row.row;
|
|
4443
4215
|
const target = state.state === "pending" || state.state === "approved" || state.state === "fuse" ? {
|
|
4444
4216
|
requested: state.target,
|
|
@@ -4548,7 +4320,7 @@ function runView(run, readAt, includeResultRef = false) {
|
|
|
4548
4320
|
]
|
|
4549
4321
|
};
|
|
4550
4322
|
}
|
|
4551
|
-
function buildFacts
|
|
4323
|
+
function buildFacts(snapshot) {
|
|
4552
4324
|
const ordered = [...snapshot.runs].sort((a, b) => b.record.startedAt - a.record.startedAt);
|
|
4553
4325
|
const active = ordered.find((run) => run.record.state === "running");
|
|
4554
4326
|
const last = ordered.find((run) => run.record.state !== "running");
|
|
@@ -4597,7 +4369,7 @@ function buildQueuePage(snapshot, queue, expiredOnly, cursor, limit = 50) {
|
|
|
4597
4369
|
queue,
|
|
4598
4370
|
expiredOnly,
|
|
4599
4371
|
counts: counts(snapshot.rows),
|
|
4600
|
-
rows: page.map(toRowFact
|
|
4372
|
+
rows: page.map(toRowFact),
|
|
4601
4373
|
...next === void 0 ? {} : { nextCursor: next },
|
|
4602
4374
|
notes: snapshot.notes
|
|
4603
4375
|
};
|
|
@@ -4638,7 +4410,7 @@ function buildRunDetail(snapshot, runId) {
|
|
|
4638
4410
|
pairKey: pair.pairKey,
|
|
4639
4411
|
a: pair.pairKey.split("\0")[0] ?? "",
|
|
4640
4412
|
b: pair.pairKey.split("\0")[1] ?? "",
|
|
4641
|
-
outcome: pair.result === "kept" ? "kept" : pair.result === "failed" ? "failed" : pair.result === "cancelled" ? "cancelled" : "merged",
|
|
4413
|
+
outcome: pair.result === "kept" ? "kept" : pair.result === "failed" ? "failed" : pair.result === "cancelled" ? "cancelled" : pair.result === "undone" ? "undone" : "merged",
|
|
4642
4414
|
...pair.target === void 0 ? {} : { target: { requested: pair.target } }
|
|
4643
4415
|
})),
|
|
4644
4416
|
pairsTruncated: false
|
|
@@ -4758,78 +4530,6 @@ const ALLOWED = [
|
|
|
4758
4530
|
evidence: "none",
|
|
4759
4531
|
activeRuns: 0
|
|
4760
4532
|
},
|
|
4761
|
-
{
|
|
4762
|
-
row: "fuse",
|
|
4763
|
-
run: "none",
|
|
4764
|
-
staging: "none",
|
|
4765
|
-
journal: "none",
|
|
4766
|
-
evidence: "none",
|
|
4767
|
-
activeRuns: 0,
|
|
4768
|
-
recovery: true
|
|
4769
|
-
},
|
|
4770
|
-
{
|
|
4771
|
-
row: "fuse",
|
|
4772
|
-
run: "failed",
|
|
4773
|
-
staging: "none",
|
|
4774
|
-
journal: "none",
|
|
4775
|
-
evidence: "none",
|
|
4776
|
-
activeRuns: 0,
|
|
4777
|
-
recovery: true
|
|
4778
|
-
},
|
|
4779
|
-
{
|
|
4780
|
-
row: "fuse",
|
|
4781
|
-
run: "orphan",
|
|
4782
|
-
staging: "none",
|
|
4783
|
-
journal: "none",
|
|
4784
|
-
evidence: "none",
|
|
4785
|
-
activeRuns: 0,
|
|
4786
|
-
recovery: true
|
|
4787
|
-
},
|
|
4788
|
-
{
|
|
4789
|
-
row: "fuse",
|
|
4790
|
-
run: "running",
|
|
4791
|
-
staging: "none",
|
|
4792
|
-
journal: "none",
|
|
4793
|
-
evidence: "none",
|
|
4794
|
-
activeRuns: 1,
|
|
4795
|
-
recovery: true
|
|
4796
|
-
},
|
|
4797
|
-
{
|
|
4798
|
-
row: "fuse",
|
|
4799
|
-
run: "none",
|
|
4800
|
-
staging: "missing",
|
|
4801
|
-
journal: "none",
|
|
4802
|
-
evidence: "none",
|
|
4803
|
-
activeRuns: 0,
|
|
4804
|
-
recovery: true
|
|
4805
|
-
},
|
|
4806
|
-
{
|
|
4807
|
-
row: "fuse",
|
|
4808
|
-
run: "failed",
|
|
4809
|
-
staging: "missing",
|
|
4810
|
-
journal: "none",
|
|
4811
|
-
evidence: "none",
|
|
4812
|
-
activeRuns: 0,
|
|
4813
|
-
recovery: true
|
|
4814
|
-
},
|
|
4815
|
-
{
|
|
4816
|
-
row: "fuse",
|
|
4817
|
-
run: "orphan",
|
|
4818
|
-
staging: "missing",
|
|
4819
|
-
journal: "none",
|
|
4820
|
-
evidence: "none",
|
|
4821
|
-
activeRuns: 0,
|
|
4822
|
-
recovery: true
|
|
4823
|
-
},
|
|
4824
|
-
{
|
|
4825
|
-
row: "fuse",
|
|
4826
|
-
run: "running",
|
|
4827
|
-
staging: "missing",
|
|
4828
|
-
journal: "none",
|
|
4829
|
-
evidence: "none",
|
|
4830
|
-
activeRuns: 1,
|
|
4831
|
-
recovery: true
|
|
4832
|
-
},
|
|
4833
4533
|
{
|
|
4834
4534
|
row: "fuse",
|
|
4835
4535
|
run: "running",
|
|
@@ -4864,7 +4564,7 @@ const ALLOWED = [
|
|
|
4864
4564
|
}
|
|
4865
4565
|
];
|
|
4866
4566
|
function same(a, b) {
|
|
4867
|
-
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;
|
|
4868
4568
|
}
|
|
4869
4569
|
function validateArtifacts(state) {
|
|
4870
4570
|
if (state.activeRuns > 1) return {
|
|
@@ -4884,7 +4584,7 @@ function validateArtifacts(state) {
|
|
|
4884
4584
|
ok: false,
|
|
4885
4585
|
reason: "skipped-running"
|
|
4886
4586
|
};
|
|
4887
|
-
if (state.row === "fuse" && state.staging === "missing"
|
|
4587
|
+
if (state.row === "fuse" && state.staging === "missing") return {
|
|
4888
4588
|
ok: false,
|
|
4889
4589
|
reason: "fuse-lost-staging"
|
|
4890
4590
|
};
|
|
@@ -4902,35 +4602,12 @@ function validateArtifacts(state) {
|
|
|
4902
4602
|
};
|
|
4903
4603
|
}
|
|
4904
4604
|
//#endregion
|
|
4905
|
-
//#region lib/types/domain/commit-journal-store.js
|
|
4906
|
-
/** Durable commit journal: <home>/merge/journals/<run>.json. */
|
|
4907
|
-
function journalPath(home, runId) {
|
|
4908
|
-
return join(home, "merge", "journals", runId.replace(/[^A-Za-z0-9_-]+/g, "_") + ".json");
|
|
4909
|
-
}
|
|
4910
|
-
async function writeJournal(io, home, journal) {
|
|
4911
|
-
const path = journalPath(home, journal.runId);
|
|
4912
|
-
const content = JSON.stringify(journal, null, 2);
|
|
4913
|
-
if (io.transact !== void 0) await io.transact(path, () => content);
|
|
4914
|
-
else await io.writeText(path, content);
|
|
4915
|
-
return path;
|
|
4916
|
-
}
|
|
4917
|
-
async function readJournal(io, home, runId) {
|
|
4918
|
-
const raw = await io.readText(journalPath(home, runId));
|
|
4919
|
-
if (raw === null) return null;
|
|
4920
|
-
try {
|
|
4921
|
-
return JSON.parse(raw);
|
|
4922
|
-
} catch {
|
|
4923
|
-
return null;
|
|
4924
|
-
}
|
|
4925
|
-
}
|
|
4926
|
-
//#endregion
|
|
4927
4605
|
//#region lib/types/doctor.js
|
|
4928
4606
|
/**
|
|
4929
4607
|
* Merge doctor rows: state, pending, gate cache and staging are each probed read-only.
|
|
4930
4608
|
* A missing file is an empty feature, not a failure; an unreadable file is a warning the
|
|
4931
4609
|
* operator can act on. This module never repairs or writes.
|
|
4932
4610
|
*/
|
|
4933
|
-
const MERGE_DOCTOR_SCHEMA_VERSION = 3;
|
|
4934
4611
|
/** Compose the one-line global-doctor fact from buildDoctorView + the last reconcile report. */
|
|
4935
4612
|
function mergeDoctorFact(view, report) {
|
|
4936
4613
|
const counts = view.counts;
|
|
@@ -4979,13 +4656,6 @@ async function mergeDoctor(io, home, configuredRoot) {
|
|
|
4979
4656
|
status: snapshot.blocked === void 0 || !hasState ? "ok" : "warn",
|
|
4980
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
|
|
4981
4658
|
});
|
|
4982
|
-
const recoveryRuns = /* @__PURE__ */ new Set();
|
|
4983
|
-
try {
|
|
4984
|
-
const raw = await io.readText(join(home, "merge", "recovery.json"));
|
|
4985
|
-
if (raw !== null) {
|
|
4986
|
-
for (const report of JSON.parse(raw)) if (report.ok === true && report.runId !== void 0) recoveryRuns.add(report.runId);
|
|
4987
|
-
}
|
|
4988
|
-
} catch {}
|
|
4989
4659
|
const invalid = [];
|
|
4990
4660
|
if (snapshot.blocked !== void 0) invalid.push({
|
|
4991
4661
|
id: "state",
|
|
@@ -4998,15 +4668,14 @@ async function mergeDoctor(io, home, configuredRoot) {
|
|
|
4998
4668
|
const run = runId === void 0 ? "none" : row.state === "pending" ? "awaiting-approval" : "running";
|
|
4999
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";
|
|
5000
4670
|
const receipt = runId === void 0 ? null : await readCommitReceipt(io, home, runId);
|
|
5001
|
-
const phase = receipt
|
|
4671
|
+
const phase = receipt === null ? null : await readUnitJournal(io, home, receipt.unitId);
|
|
5002
4672
|
const result = validateArtifacts({
|
|
5003
4673
|
row: artifactRow,
|
|
5004
4674
|
run,
|
|
5005
4675
|
staging,
|
|
5006
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",
|
|
5007
4677
|
evidence: receipt === null ? "none" : "receipt",
|
|
5008
|
-
activeRuns: run === "running" || run === "awaiting-approval" ? 1 : 0
|
|
5009
|
-
...runId !== void 0 && recoveryRuns.has(runId) ? { recovery: true } : {}
|
|
4678
|
+
activeRuns: run === "running" || run === "awaiting-approval" ? 1 : 0
|
|
5010
4679
|
});
|
|
5011
4680
|
if (!result.ok) invalid.push({
|
|
5012
4681
|
id: row.id,
|
|
@@ -5149,26 +4818,6 @@ async function mergeDoctor(io, home, configuredRoot) {
|
|
|
5149
4818
|
status: "ok",
|
|
5150
4819
|
detail: stagingRoot(home, "<runId>")
|
|
5151
4820
|
});
|
|
5152
|
-
try {
|
|
5153
|
-
const raw = await io.readText(join(home, "merge", "recovery.json"));
|
|
5154
|
-
if (raw !== null) {
|
|
5155
|
-
const reports = JSON.parse(raw);
|
|
5156
|
-
const failed = reports.filter((report) => report.ok !== true);
|
|
5157
|
-
rows.push({
|
|
5158
|
-
key: "recovery",
|
|
5159
|
-
label: "提交恢复",
|
|
5160
|
-
status: failed.length === 0 ? "ok" : "warn",
|
|
5161
|
-
detail: failed.length === 0 ? String(reports.length) + " 条恢复报告,无待处理" : String(failed.length) + " 条待处理:" + failed.map((report) => (report.runId ?? "?") + "=" + (report.action ?? "?")).join(", ")
|
|
5162
|
-
});
|
|
5163
|
-
}
|
|
5164
|
-
} catch {
|
|
5165
|
-
rows.push({
|
|
5166
|
-
key: "recovery",
|
|
5167
|
-
label: "提交恢复",
|
|
5168
|
-
status: "unknown",
|
|
5169
|
-
detail: "无法读取 merge/recovery.json"
|
|
5170
|
-
});
|
|
5171
|
-
}
|
|
5172
4821
|
return rows;
|
|
5173
4822
|
}
|
|
5174
4823
|
//#endregion
|
|
@@ -5365,13 +5014,6 @@ async function projectRecoveredUnit(options) {
|
|
|
5365
5014
|
await options.onPhase?.("stage-drop");
|
|
5366
5015
|
await dropStage(options.io, options.home, stageRowId);
|
|
5367
5016
|
}
|
|
5368
|
-
await options.onPhase?.("pair-index");
|
|
5369
|
-
await recordPair(options.io, options.home, {
|
|
5370
|
-
pairKey,
|
|
5371
|
-
runId: options.runId,
|
|
5372
|
-
result: "merged",
|
|
5373
|
-
target
|
|
5374
|
-
});
|
|
5375
5017
|
await options.onPhase?.("run-meta");
|
|
5376
5018
|
const meta = await readRunMeta(options.io, options.home, options.runId);
|
|
5377
5019
|
await writeRunMeta(options.io, options.home, {
|
|
@@ -5603,258 +5245,32 @@ async function recoverCommitUnits(options) {
|
|
|
5603
5245
|
branch,
|
|
5604
5246
|
action: "rollForward",
|
|
5605
5247
|
ok: false,
|
|
5606
|
-
code: result.code,
|
|
5607
|
-
message: result.message
|
|
5608
|
-
});
|
|
5609
|
-
continue;
|
|
5610
|
-
}
|
|
5611
|
-
reports.push({
|
|
5612
|
-
unitId: journal.unitId,
|
|
5613
|
-
runId: journal.runId,
|
|
5614
|
-
phase: journal.phase,
|
|
5615
|
-
branch,
|
|
5616
|
-
action: "blocked",
|
|
5617
|
-
ok: false,
|
|
5618
|
-
code: "unit-recovery-blocked"
|
|
5619
|
-
});
|
|
5620
|
-
}
|
|
5621
|
-
return reports;
|
|
5622
|
-
}
|
|
5623
|
-
//#endregion
|
|
5624
|
-
//#region lib/types/facts.js
|
|
5625
|
-
const queueOf$2 = (row) => row.state === "approved" ? "fuse" : row.queue;
|
|
5626
|
-
const isExpired = (row) => row.expired !== void 0;
|
|
5627
|
-
function countsOf(rows) {
|
|
5628
|
-
const active = {
|
|
5629
|
-
verify: 0,
|
|
5630
|
-
pending: 0,
|
|
5631
|
-
fuse: 0,
|
|
5632
|
-
skipped: 0
|
|
5633
|
-
};
|
|
5634
|
-
let expired = 0;
|
|
5635
|
-
for (const row of rows) {
|
|
5636
|
-
if (isExpired(row)) {
|
|
5637
|
-
expired += 1;
|
|
5638
|
-
continue;
|
|
5639
|
-
}
|
|
5640
|
-
active[queueOf$2(row)] += 1;
|
|
5641
|
-
}
|
|
5642
|
-
return {
|
|
5643
|
-
active,
|
|
5644
|
-
expired
|
|
5645
|
-
};
|
|
5646
|
-
}
|
|
5647
|
-
function toRunView(record, readAt, meta = null) {
|
|
5648
|
-
const state = record.state;
|
|
5649
|
-
return {
|
|
5650
|
-
wireVersion: 1,
|
|
5651
|
-
readAt,
|
|
5652
|
-
id: record.id,
|
|
5653
|
-
state,
|
|
5654
|
-
command: record.command ?? "scan",
|
|
5655
|
-
...record.stage === void 0 ? {} : { stage: record.stage },
|
|
5656
|
-
progress: record.progress === void 0 ? null : {
|
|
5657
|
-
done: record.progress.done,
|
|
5658
|
-
total: record.progress.total
|
|
5659
|
-
},
|
|
5660
|
-
startedAt: record.startedAt,
|
|
5661
|
-
...record.endedAt === void 0 ? {} : { endedAt: record.endedAt },
|
|
5662
|
-
...record.failure === void 0 ? {} : { failure: {
|
|
5663
|
-
stage: "settle",
|
|
5664
|
-
code: "run-failed",
|
|
5665
|
-
retryable: false,
|
|
5666
|
-
retryFrom: "none",
|
|
5667
|
-
detail: record.failure
|
|
5668
|
-
} },
|
|
5669
|
-
...record.parentRunId === void 0 ? {} : { parentRunId: record.parentRunId },
|
|
5670
|
-
actions: [
|
|
5671
|
-
{
|
|
5672
|
-
id: "status",
|
|
5673
|
-
command: "/evolution merge status " + record.id,
|
|
5674
|
-
confirm: false,
|
|
5675
|
-
enabled: true
|
|
5676
|
-
},
|
|
5677
|
-
{
|
|
5678
|
-
id: "report",
|
|
5679
|
-
command: "/evolution merge report " + record.id,
|
|
5680
|
-
confirm: false,
|
|
5681
|
-
enabled: record.resultRef !== void 0
|
|
5682
|
-
},
|
|
5683
|
-
{
|
|
5684
|
-
id: "cancel",
|
|
5685
|
-
command: "/evolution merge cancel " + record.id,
|
|
5686
|
-
confirm: false,
|
|
5687
|
-
enabled: state === "running"
|
|
5688
|
-
}
|
|
5689
|
-
]
|
|
5690
|
-
};
|
|
5691
|
-
}
|
|
5692
|
-
function buildFacts(input) {
|
|
5693
|
-
const ordered = [...input.runs].sort((a, b) => b.startedAt - a.startedAt);
|
|
5694
|
-
const active = ordered.find((run) => run.state === "running");
|
|
5695
|
-
const last = ordered.find((run) => run.state !== "running");
|
|
5696
|
-
const notes = input.notes ?? [];
|
|
5697
|
-
return {
|
|
5698
|
-
wireVersion: 1,
|
|
5699
|
-
readAt: input.readAt,
|
|
5700
|
-
approval: { mergeApproval: input.approval },
|
|
5701
|
-
counts: countsOf(input.rows),
|
|
5702
|
-
active: active === void 0 ? null : toRunView(active, input.readAt, input.runMeta?.get(active.id) ?? null),
|
|
5703
|
-
last: last === void 0 ? null : toRunView(last, input.readAt, input.runMeta?.get(last.id) ?? null),
|
|
5704
|
-
startCommands: {
|
|
5705
|
-
scan: "/evolution merge scan",
|
|
5706
|
-
pair: "/evolution merge pair <a> <b>"
|
|
5707
|
-
},
|
|
5708
|
-
fallback: MERGE_COMMAND_SURFACE.fallback,
|
|
5709
|
-
notes,
|
|
5710
|
-
degraded: notes.length > 0
|
|
5711
|
-
};
|
|
5712
|
-
}
|
|
5713
|
-
//#endregion
|
|
5714
|
-
//#region lib/types/wire-projection.js
|
|
5715
|
-
const queueOf$1 = (row) => row.state === "approved" ? "fuse" : row.queue;
|
|
5716
|
-
const expiredOf = (row) => row.expired !== void 0;
|
|
5717
|
-
/** Host-owned row actions; client only renders/copies them. */
|
|
5718
|
-
function actionRefs(row) {
|
|
5719
|
-
const base = "/evolution merge ";
|
|
5720
|
-
const disabled = row.expired === void 0 ? void 0 : "expired";
|
|
5721
|
-
const action = (id, confirm = false, enabled = true) => ({
|
|
5722
|
-
id,
|
|
5723
|
-
command: base + id + " " + row.id,
|
|
5724
|
-
confirm,
|
|
5725
|
-
enabled,
|
|
5726
|
-
...enabled ? {} : { disabledReason: disabled ?? "invalid" }
|
|
5727
|
-
});
|
|
5728
|
-
if (row.state === "pending" && row.expired !== void 0) return [{
|
|
5729
|
-
id: "discard",
|
|
5730
|
-
command: "/evolution merge discard " + row.id,
|
|
5731
|
-
confirm: true,
|
|
5732
|
-
enabled: true
|
|
5733
|
-
}, {
|
|
5734
|
-
id: "pair",
|
|
5735
|
-
command: "/evolution merge pair " + row.a + " " + row.b,
|
|
5736
|
-
confirm: true,
|
|
5737
|
-
enabled: true
|
|
5738
|
-
}];
|
|
5739
|
-
if (row.state === "pending") return [
|
|
5740
|
-
action("approve"),
|
|
5741
|
-
action("reject", true),
|
|
5742
|
-
action("discard", true)
|
|
5743
|
-
];
|
|
5744
|
-
if (row.state === "approved" || row.state === "fuse") {
|
|
5745
|
-
if (row.failure !== void 0 && row.failure.retryable === false) return [{
|
|
5746
|
-
id: "pair",
|
|
5747
|
-
command: "/evolution merge pair " + row.a + " " + row.b,
|
|
5748
|
-
confirm: true,
|
|
5749
|
-
enabled: true
|
|
5750
|
-
}, action("discard", true)];
|
|
5751
|
-
return [
|
|
5752
|
-
{
|
|
5753
|
-
id: "retry-resume",
|
|
5754
|
-
command: "/evolution merge resume --retry " + row.id,
|
|
5755
|
-
confirm: true,
|
|
5756
|
-
enabled: true
|
|
5757
|
-
},
|
|
5758
|
-
action("discard", true),
|
|
5759
|
-
action("status")
|
|
5760
|
-
];
|
|
5761
|
-
}
|
|
5762
|
-
if (row.state === "skipped") return [action("restore", true)];
|
|
5763
|
-
if (row.state === "verify") return [{
|
|
5764
|
-
id: "retry-candidates",
|
|
5765
|
-
command: "/evolution merge candidates --retry " + row.id,
|
|
5766
|
-
confirm: false,
|
|
5767
|
-
enabled: true
|
|
5768
|
-
}];
|
|
5769
|
-
return [action("pair")];
|
|
5770
|
-
}
|
|
5771
|
-
function toRowFact(row, actions = actionRefs(row)) {
|
|
5772
|
-
return {
|
|
5773
|
-
id: row.id,
|
|
5774
|
-
state: row.state,
|
|
5775
|
-
queue: queueOf$1(row),
|
|
5776
|
-
...row.state === "verify" ? { verifySubState: "queued" } : {},
|
|
5777
|
-
a: row.a,
|
|
5778
|
-
b: row.b,
|
|
5779
|
-
...row.target === void 0 ? {} : { target: {
|
|
5780
|
-
requested: row.target.requested,
|
|
5781
|
-
...row.target.actual === void 0 ? {} : { actual: row.target.actual },
|
|
5782
|
-
...row.target.created === void 0 ? {} : { created: row.target.created }
|
|
5783
|
-
} },
|
|
5784
|
-
...row.state === "pending" ? { summary: {
|
|
5785
|
-
a: null,
|
|
5786
|
-
b: null,
|
|
5787
|
-
rationale: row.decision?.rationale ?? null
|
|
5788
|
-
} } : {},
|
|
5789
|
-
...row.reason === void 0 ? {} : { reason: row.reason },
|
|
5790
|
-
...row.state === "skipped" ? { origin: row.origin ?? "system" } : {},
|
|
5791
|
-
...row.failure === void 0 ? {} : { failure: {
|
|
5792
|
-
stage: row.failure.stage === "screening" ? "screening" : row.failure.stage === "decide" ? "decide" : row.failure.stage === "author" ? "author" : row.failure.stage === "validate" ? "validate" : "commit",
|
|
5793
|
-
code: row.failure.code,
|
|
5794
|
-
retryable: row.failure.retryable,
|
|
5795
|
-
retryFrom: row.failure.retryFrom
|
|
5796
|
-
} },
|
|
5797
|
-
...row.stagingRef === void 0 ? {} : { staging: {
|
|
5798
|
-
state: "kept",
|
|
5799
|
-
...row.stagingExpiresAt === void 0 ? {} : { expiresAt: row.stagingExpiresAt }
|
|
5800
|
-
} },
|
|
5801
|
-
...row.expired === void 0 ? {} : { expired: {
|
|
5802
|
-
kind: row.expired,
|
|
5803
|
-
at: Date.parse(row.updatedAt)
|
|
5804
|
-
} },
|
|
5805
|
-
...row.attempts === void 0 ? {} : { attempts: row.attempts },
|
|
5806
|
-
...row.decision?.confidence === void 0 ? {} : { confidence: row.decision.confidence },
|
|
5807
|
-
...row.state === "skipped" && row.stagingExpiresAt !== void 0 ? { expiresAt: row.stagingExpiresAt } : {},
|
|
5808
|
-
createdAt: Date.parse(row.createdAt),
|
|
5809
|
-
updatedAt: Date.parse(row.updatedAt),
|
|
5810
|
-
actions
|
|
5811
|
-
};
|
|
5812
|
-
}
|
|
5813
|
-
function toQueuePage(rows, queue, expiredOnly, readAt, limit = 50) {
|
|
5814
|
-
const filtered = rows.filter((row) => queueOf$1(row) === queue && (expiredOnly ? expiredOf(row) : !expiredOf(row)));
|
|
5815
|
-
const page = filtered.slice(0, Math.max(0, Math.min(200, limit)));
|
|
5816
|
-
return {
|
|
5817
|
-
wireVersion: 1,
|
|
5818
|
-
readAt,
|
|
5819
|
-
queue,
|
|
5820
|
-
expiredOnly,
|
|
5821
|
-
counts: countsOf(rows),
|
|
5822
|
-
rows: page.map((row) => toRowFact(row)),
|
|
5823
|
-
...filtered.length > page.length ? { nextCursor: String(page.length) } : {},
|
|
5824
|
-
notes: []
|
|
5825
|
-
};
|
|
5826
|
-
}
|
|
5827
|
-
function toBodyView(name, side, text, readAt) {
|
|
5828
|
-
return {
|
|
5829
|
-
wireVersion: 1,
|
|
5830
|
-
readAt,
|
|
5831
|
-
name,
|
|
5832
|
-
side,
|
|
5833
|
-
text,
|
|
5834
|
-
markdown: true,
|
|
5835
|
-
truncated: false,
|
|
5836
|
-
totalBytes: Buffer.byteLength(text, "utf8")
|
|
5837
|
-
};
|
|
5838
|
-
}
|
|
5839
|
-
function toHistoryView(items, readAt) {
|
|
5840
|
-
return {
|
|
5841
|
-
wireVersion: 1,
|
|
5842
|
-
readAt,
|
|
5843
|
-
items: items.map((item) => {
|
|
5844
|
-
const parsed = item.archivedAt === null ? null : typeof item.archivedAt === "number" ? item.archivedAt : Date.parse(item.archivedAt);
|
|
5845
|
-
return {
|
|
5846
|
-
name: item.name,
|
|
5847
|
-
kind: item.kind,
|
|
5848
|
-
reason: item.reason,
|
|
5849
|
-
lastVersion: item.lastVersion,
|
|
5850
|
-
archivedAt: parsed === null || Number.isFinite(parsed) ? parsed : null,
|
|
5851
|
-
...item.sourceRunId === void 0 ? {} : { sourceRunId: item.sourceRunId }
|
|
5852
|
-
};
|
|
5853
|
-
})
|
|
5854
|
-
};
|
|
5248
|
+
code: result.code,
|
|
5249
|
+
message: result.message
|
|
5250
|
+
});
|
|
5251
|
+
continue;
|
|
5252
|
+
}
|
|
5253
|
+
reports.push({
|
|
5254
|
+
unitId: journal.unitId,
|
|
5255
|
+
runId: journal.runId,
|
|
5256
|
+
phase: journal.phase,
|
|
5257
|
+
branch,
|
|
5258
|
+
action: "blocked",
|
|
5259
|
+
ok: false,
|
|
5260
|
+
code: "unit-recovery-blocked"
|
|
5261
|
+
});
|
|
5262
|
+
}
|
|
5263
|
+
return reports;
|
|
5855
5264
|
}
|
|
5856
5265
|
//#endregion
|
|
5857
5266
|
//#region lib/types/merge-routes.js
|
|
5267
|
+
/**
|
|
5268
|
+
* Four read-only merge routes: view / rows / body / history.
|
|
5269
|
+
* The host loads one snapshot; these handlers only project wire envelopes.
|
|
5270
|
+
* There is no second (legacy rows/runs/history) source: the production constructor has
|
|
5271
|
+
* always provided the snapshot, and the legacy branches were the only consumers of
|
|
5272
|
+
* facts.ts / wire-projection.ts (W11 D2b).
|
|
5273
|
+
*/
|
|
5858
5274
|
const MERGE_PATHS = HOST_ROUTES.merge;
|
|
5859
5275
|
const MERGE_BASE = MERGE_PATHS.view.slice(0, -4);
|
|
5860
5276
|
const MERGE_ROUTES = {
|
|
@@ -5870,21 +5286,16 @@ function makeMergeRoutes(deps, _audit) {
|
|
|
5870
5286
|
code: "E-325",
|
|
5871
5287
|
message: "merge service is not mounted"
|
|
5872
5288
|
});
|
|
5873
|
-
const blocked = (
|
|
5289
|
+
const blocked = (snapshot) => snapshot.blocked === void 0 ? null : json(503, {
|
|
5874
5290
|
wireVersion: 1,
|
|
5875
5291
|
code: "merge-state-blocked",
|
|
5876
|
-
readiness
|
|
5292
|
+
readiness: snapshot.blocked.readiness
|
|
5877
5293
|
});
|
|
5878
5294
|
const hostOnly = (snapshot) => snapshot.hostOnly === void 0 ? null : json(503, {
|
|
5879
5295
|
wireVersion: 1,
|
|
5880
5296
|
code: "E-323",
|
|
5881
5297
|
message: snapshot.hostOnly.detail ?? "host data plane unavailable"
|
|
5882
5298
|
});
|
|
5883
|
-
const notReady = async (source) => {
|
|
5884
|
-
if (source.readiness === void 0) return null;
|
|
5885
|
-
const readiness = await source.readiness();
|
|
5886
|
-
return readiness.ok ? null : blocked(readiness);
|
|
5887
|
-
};
|
|
5888
5299
|
const bad = (message) => json(400, {
|
|
5889
5300
|
wireVersion: 1,
|
|
5890
5301
|
code: "merge-bad-query",
|
|
@@ -5892,6 +5303,11 @@ function makeMergeRoutes(deps, _audit) {
|
|
|
5892
5303
|
});
|
|
5893
5304
|
const get = (request) => request.method === "GET" ? null : methodNotAllowed(["GET"]);
|
|
5894
5305
|
const url = (request) => new URL(request.url, "http://local");
|
|
5306
|
+
const snapshotOf = async () => {
|
|
5307
|
+
const source = deps.getSource();
|
|
5308
|
+
return source === void 0 ? null : await source.snapshot();
|
|
5309
|
+
};
|
|
5310
|
+
const unavailable = (snapshot) => snapshot === null ? absent() : blocked(snapshot) ?? hostOnly(snapshot);
|
|
5895
5311
|
return [
|
|
5896
5312
|
{
|
|
5897
5313
|
path: MERGE_ROUTES.view,
|
|
@@ -5900,28 +5316,10 @@ function makeMergeRoutes(deps, _audit) {
|
|
|
5900
5316
|
fetch: async (request) => {
|
|
5901
5317
|
const denied = get(request);
|
|
5902
5318
|
if (denied !== null) return denied;
|
|
5903
|
-
const
|
|
5904
|
-
|
|
5905
|
-
if (
|
|
5906
|
-
|
|
5907
|
-
if (snapshot.blocked !== void 0) return json(503, {
|
|
5908
|
-
wireVersion: 1,
|
|
5909
|
-
code: "merge-state-blocked",
|
|
5910
|
-
readiness: snapshot.blocked.readiness
|
|
5911
|
-
});
|
|
5912
|
-
const capability = hostOnly(snapshot);
|
|
5913
|
-
if (capability !== null) return capability;
|
|
5914
|
-
return json(200, buildFacts$1(snapshot));
|
|
5915
|
-
}
|
|
5916
|
-
const readiness = await notReady(source);
|
|
5917
|
-
if (readiness !== null) return readiness;
|
|
5918
|
-
const readAt = Date.now();
|
|
5919
|
-
return json(200, buildFacts({
|
|
5920
|
-
rows: await source.rows?.() ?? [],
|
|
5921
|
-
runs: await source.runs?.(void 0, 20) ?? [],
|
|
5922
|
-
approval: source.approval?.() === true,
|
|
5923
|
-
readAt
|
|
5924
|
-
}));
|
|
5319
|
+
const snapshot = await snapshotOf();
|
|
5320
|
+
const notReady = unavailable(snapshot);
|
|
5321
|
+
if (notReady !== null) return notReady;
|
|
5322
|
+
return json(200, buildFacts(snapshot));
|
|
5925
5323
|
}
|
|
5926
5324
|
},
|
|
5927
5325
|
{
|
|
@@ -5931,37 +5329,20 @@ function makeMergeRoutes(deps, _audit) {
|
|
|
5931
5329
|
fetch: async (request) => {
|
|
5932
5330
|
const denied = get(request);
|
|
5933
5331
|
if (denied !== null) return denied;
|
|
5934
|
-
const source = deps.getSource();
|
|
5935
|
-
if (source === void 0) return absent();
|
|
5936
5332
|
const query = url(request).searchParams;
|
|
5937
5333
|
const queue = query.get("queue") ?? "verify";
|
|
5938
5334
|
if (queue !== "verify" && queue !== "pending" && queue !== "fuse" && queue !== "skipped") return bad("queue must be verify/pending/fuse/skipped");
|
|
5939
5335
|
const expiredOnly = query.get("expired") === "1";
|
|
5940
5336
|
if (expiredOnly && queue !== "pending") return bad("expired is only allowed for pending");
|
|
5941
5337
|
const limit = Number.parseInt(query.get("limit") ?? "50", 10);
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
const capability = hostOnly(snapshot);
|
|
5950
|
-
if (capability !== null) return capability;
|
|
5951
|
-
try {
|
|
5952
|
-
return json(200, buildQueuePage(snapshot, queue, expiredOnly, query.get("cursor") ?? void 0, Number.isFinite(limit) ? limit : 50));
|
|
5953
|
-
} catch (error) {
|
|
5954
|
-
return bad(error instanceof Error ? error.message : "queue cursor is stale");
|
|
5955
|
-
}
|
|
5338
|
+
const snapshot = await snapshotOf();
|
|
5339
|
+
const notReady = unavailable(snapshot);
|
|
5340
|
+
if (notReady !== null) return notReady;
|
|
5341
|
+
try {
|
|
5342
|
+
return json(200, buildQueuePage(snapshot, queue, expiredOnly, query.get("cursor") ?? void 0, Number.isFinite(limit) ? limit : 50));
|
|
5343
|
+
} catch (error) {
|
|
5344
|
+
return bad(error instanceof Error ? error.message : "queue cursor is stale");
|
|
5956
5345
|
}
|
|
5957
|
-
const readiness = await notReady(source);
|
|
5958
|
-
if (readiness !== null) return readiness;
|
|
5959
|
-
const offset = Number.parseInt(query.get("cursor") ?? "0", 10);
|
|
5960
|
-
const page = toQueuePage(await source.rows?.() ?? [], queue, expiredOnly, Date.now(), Number.isFinite(limit) ? limit : 50);
|
|
5961
|
-
return json(200, Number.isFinite(offset) && offset > 0 ? {
|
|
5962
|
-
...page,
|
|
5963
|
-
rows: page.rows.slice(offset)
|
|
5964
|
-
} : page);
|
|
5965
5346
|
}
|
|
5966
5347
|
},
|
|
5967
5348
|
{
|
|
@@ -5982,39 +5363,25 @@ function makeMergeRoutes(deps, _audit) {
|
|
|
5982
5363
|
code: "merge-body-not-found",
|
|
5983
5364
|
message: "merge body requires id or name"
|
|
5984
5365
|
});
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
});
|
|
5999
|
-
if (refs.length > 1) return bad("merge body is ambiguous; pass id, name and side");
|
|
6000
|
-
const row = snapshot.rows.find((item) => item.row.id === refs[0].rowId);
|
|
6001
|
-
if (row?.stage?.state === "lost" || row?.stage?.state === "expired") return json(404, {
|
|
6002
|
-
wireVersion: 1,
|
|
6003
|
-
code: "merge-body-not-found",
|
|
6004
|
-
message: "merge stage is lost"
|
|
6005
|
-
});
|
|
6006
|
-
const ref = refs[0];
|
|
6007
|
-
return json(200, buildBodyView(snapshot, ref, (source.bodyRef === void 0 ? null : await source.bodyRef(ref)) ?? ""));
|
|
6008
|
-
}
|
|
6009
|
-
const readiness = await notReady(source);
|
|
6010
|
-
if (readiness !== null) return readiness;
|
|
6011
|
-
if (id === null || id === "" || side !== "a" && side !== "b") return bad("id and side=a|b are required");
|
|
6012
|
-
const content = await source.body?.(id, side) ?? null;
|
|
6013
|
-
return content === null ? json(200, {
|
|
5366
|
+
const snapshot = await source.snapshot();
|
|
5367
|
+
const notReady = blocked(snapshot);
|
|
5368
|
+
if (notReady !== null) return notReady;
|
|
5369
|
+
const sideFilter = side === "a" ? "live" : side === "b" ? "archive" : side === "live" || side === "archive" ? side : void 0;
|
|
5370
|
+
const refs = snapshot.bodyRefs.filter((ref) => (id === null || id === "" || ref.rowId === id) && (name === null || name === "" || ref.name === name) && (sideFilter === void 0 || ref.side === sideFilter));
|
|
5371
|
+
if (refs.length === 0) return json(404, {
|
|
5372
|
+
wireVersion: 1,
|
|
5373
|
+
code: "merge-body-not-found",
|
|
5374
|
+
message: "merge body not found"
|
|
5375
|
+
});
|
|
5376
|
+
if (refs.length > 1) return bad("merge body is ambiguous; pass id, name and side");
|
|
5377
|
+
const row = snapshot.rows.find((item) => item.row.id === refs[0].rowId);
|
|
5378
|
+
if (row?.stage?.state === "lost" || row?.stage?.state === "expired") return json(404, {
|
|
6014
5379
|
wireVersion: 1,
|
|
6015
|
-
code: "merge-body-
|
|
6016
|
-
message: "merge
|
|
6017
|
-
})
|
|
5380
|
+
code: "merge-body-not-found",
|
|
5381
|
+
message: "merge stage is lost"
|
|
5382
|
+
});
|
|
5383
|
+
const ref = refs[0];
|
|
5384
|
+
return json(200, buildBodyView(snapshot, ref, (source.bodyRef === void 0 ? null : await source.bodyRef(ref)) ?? ""));
|
|
6018
5385
|
}
|
|
6019
5386
|
},
|
|
6020
5387
|
{
|
|
@@ -6024,20 +5391,11 @@ function makeMergeRoutes(deps, _audit) {
|
|
|
6024
5391
|
fetch: async (request) => {
|
|
6025
5392
|
const denied = get(request);
|
|
6026
5393
|
if (denied !== null) return denied;
|
|
6027
|
-
const
|
|
6028
|
-
if (
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
wireVersion: 1,
|
|
6033
|
-
code: "merge-state-blocked",
|
|
6034
|
-
readiness: snapshot.blocked.readiness
|
|
6035
|
-
});
|
|
6036
|
-
return json(200, buildHistoryView(snapshot));
|
|
6037
|
-
}
|
|
6038
|
-
const readiness = await notReady(source);
|
|
6039
|
-
if (readiness !== null) return readiness;
|
|
6040
|
-
return json(200, toHistoryView(await source.history?.() ?? [], Date.now()));
|
|
5394
|
+
const snapshot = await snapshotOf();
|
|
5395
|
+
if (snapshot === null) return absent();
|
|
5396
|
+
const notReady = blocked(snapshot);
|
|
5397
|
+
if (notReady !== null) return notReady;
|
|
5398
|
+
return json(200, buildHistoryView(snapshot));
|
|
6041
5399
|
}
|
|
6042
5400
|
},
|
|
6043
5401
|
{
|
|
@@ -6351,13 +5709,13 @@ async function handleReadOnlyMergeCommand(command, io, home, cards, runs, approv
|
|
|
6351
5709
|
...live === void 0 ? {} : { live }
|
|
6352
5710
|
});
|
|
6353
5711
|
if (snapshot.blocked !== void 0) throw new Error(snapshot.blocked.code + ": " + snapshot.blocked.message);
|
|
6354
|
-
const rows = snapshot.rows.map(toRowFact
|
|
5712
|
+
const rows = snapshot.rows.map(toRowFact);
|
|
6355
5713
|
if (command.verb === "status") {
|
|
6356
5714
|
if (command.id !== void 0) {
|
|
6357
5715
|
const row = rows.find((item) => item.id === command.id);
|
|
6358
5716
|
return row === void 0 ? "merge row not found: " + command.id : formatSnapshotStatus([row]);
|
|
6359
5717
|
}
|
|
6360
|
-
return formatFacts(buildFacts
|
|
5718
|
+
return formatFacts(buildFacts(snapshot));
|
|
6361
5719
|
}
|
|
6362
5720
|
if (command.verb === "pending") {
|
|
6363
5721
|
const live = command.expired === true ? rows.filter((row) => row.expired !== void 0) : rows.filter((row) => row.queue === "pending" && row.expired === void 0);
|
|
@@ -6370,9 +5728,6 @@ async function handleReadOnlyMergeCommand(command, io, home, cards, runs, approv
|
|
|
6370
5728
|
}
|
|
6371
5729
|
return formatSnapshotQueue(rows.filter((row) => row.queue === "skipped"), "skipped");
|
|
6372
5730
|
}
|
|
6373
|
-
function mergeCommandHelp() {
|
|
6374
|
-
return mergeUsage();
|
|
6375
|
-
}
|
|
6376
5731
|
//#endregion
|
|
6377
5732
|
//#region lib/types/merge-command.js
|
|
6378
5733
|
function createReadOnlyMergeService(io, home) {
|
|
@@ -6426,10 +5781,6 @@ function createMergeCommand(service, version = MERGE_PACKAGE_VERSION) {
|
|
|
6426
5781
|
}
|
|
6427
5782
|
//#endregion
|
|
6428
5783
|
//#region lib/types/skipped.js
|
|
6429
|
-
/**
|
|
6430
|
-
* Skipped filtering: a pair the operator marked as not-worth-merging stays out of automatic
|
|
6431
|
-
* screening until mergeSkippedTtlDays expires. Explicit /merge pair ignores this set.
|
|
6432
|
-
*/
|
|
6433
5784
|
function skippedPairKeys(rows, ttlDays, now) {
|
|
6434
5785
|
const keys = /* @__PURE__ */ new Set();
|
|
6435
5786
|
for (const row of rows) {
|
|
@@ -6443,9 +5794,6 @@ function skippedPairKeys(rows, ttlDays, now) {
|
|
|
6443
5794
|
}
|
|
6444
5795
|
return keys;
|
|
6445
5796
|
}
|
|
6446
|
-
function isSkippedPair(keys, a, b) {
|
|
6447
|
-
return keys.has(pairKey(a, b));
|
|
6448
|
-
}
|
|
6449
5797
|
//#endregion
|
|
6450
5798
|
//#region lib/types/domain/engine-criteria.js
|
|
6451
5799
|
function criteriaFrom(level, verdict, action) {
|
|
@@ -6698,11 +6046,6 @@ async function runScan(options) {
|
|
|
6698
6046
|
continue;
|
|
6699
6047
|
}
|
|
6700
6048
|
row = projected;
|
|
6701
|
-
await recordPair(options.io, options.home, {
|
|
6702
|
-
pairKey: row.pairKey,
|
|
6703
|
-
runId: row.runId ?? "merge",
|
|
6704
|
-
result: "kept"
|
|
6705
|
-
});
|
|
6706
6049
|
pairs.push(pairOf(row, candidate, "kept", {
|
|
6707
6050
|
...round1.decision === void 0 ? {} : { decision: round1.decision },
|
|
6708
6051
|
...round1.usage === void 0 ? {} : { usage: round1.usage }
|
|
@@ -6912,15 +6255,7 @@ async function runScan(options) {
|
|
|
6912
6255
|
if (await pairLedger(options.io, options.home).transact((tx) => {
|
|
6913
6256
|
const current = tx.rows().find((item) => item.id === row.id);
|
|
6914
6257
|
return current === void 0 ? false : tx.remove(row.id, "superseded", void 0, current.version).ok;
|
|
6915
|
-
}))
|
|
6916
|
-
await dropStage(options.io, options.home, row.id, row.stagingRef);
|
|
6917
|
-
await recordPair(options.io, options.home, {
|
|
6918
|
-
pairKey: row.pairKey,
|
|
6919
|
-
runId: row.runId ?? "merge",
|
|
6920
|
-
result: "failed",
|
|
6921
|
-
...row.decision?.target === void 0 ? {} : { target: row.decision.target }
|
|
6922
|
-
});
|
|
6923
|
-
}
|
|
6258
|
+
})) await dropStage(options.io, options.home, row.id, row.stagingRef);
|
|
6924
6259
|
pairs.push(pairOf(row, candidate, "failed", {
|
|
6925
6260
|
decision: mergeDecision,
|
|
6926
6261
|
failure: failed,
|
|
@@ -7422,12 +6757,22 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7422
6757
|
...outcome.criteria === void 0 ? {} : { criteria: outcome.criteria },
|
|
7423
6758
|
...outcome.validationIssues === void 0 ? {} : { validation: { issues: outcome.validationIssues } }
|
|
7424
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
|
+
});
|
|
7425
6771
|
if (outcome.kind === "merged") {
|
|
7426
6772
|
const unitRef = {
|
|
7427
6773
|
unitId: outcome.unitId ?? "unknown",
|
|
7428
6774
|
evidenceSha256: outcome.evidenceSha256 ?? "unknown"
|
|
7429
6775
|
};
|
|
7430
|
-
const target = outcome.target?.actual ?? outcome.target?.requested ?? row.decision?.target;
|
|
7431
6776
|
const finalize = async () => {
|
|
7432
6777
|
if (!(await pairLedger(io, home, fence).transact((tx) => {
|
|
7433
6778
|
const current = tx.rows().find((item) => item.id === row.id);
|
|
@@ -7438,50 +6783,28 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7438
6783
|
} : tx.remove(row.id, "committed", unitRef, current.version);
|
|
7439
6784
|
})).ok) throw new Error("row changed before commit record: " + row.id);
|
|
7440
6785
|
await dropStage(io, home, row.id);
|
|
7441
|
-
await recordPair(io, home, {
|
|
7442
|
-
pairKey: row.pairKey,
|
|
7443
|
-
runId: row.runId ?? "merge",
|
|
7444
|
-
result: "merged",
|
|
7445
|
-
...target === void 0 ? {} : { target },
|
|
7446
|
-
...outcome.unitId === void 0 ? {} : { reportRef: outcome.unitId }
|
|
7447
|
-
});
|
|
7448
6786
|
};
|
|
7449
6787
|
if (deferProjection) return {
|
|
7450
6788
|
merged: true,
|
|
7451
6789
|
finalize,
|
|
7452
|
-
pair: {
|
|
7453
|
-
id: row.id,
|
|
7454
|
-
pairKey: row.pairKey,
|
|
7455
|
-
a: row.a,
|
|
7456
|
-
b: row.b,
|
|
7457
|
-
queue: row.queue,
|
|
7458
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7459
|
-
outcome: "merged",
|
|
7460
|
-
archived: outcome.archived ?? [],
|
|
6790
|
+
pair: pair("merged", {
|
|
7461
6791
|
...outcome.lengths === void 0 ? {} : { lengths: outcome.lengths },
|
|
7462
6792
|
...outcome.unitId === void 0 ? {} : { unitId: outcome.unitId },
|
|
7463
6793
|
...outcome.target === void 0 ? {} : { target: outcome.target },
|
|
7464
6794
|
...reportExtra
|
|
7465
|
-
}
|
|
6795
|
+
})
|
|
7466
6796
|
};
|
|
7467
6797
|
await finalize();
|
|
7468
6798
|
return {
|
|
7469
6799
|
merged: true,
|
|
7470
|
-
pair: {
|
|
7471
|
-
|
|
7472
|
-
pairKey: row.pairKey,
|
|
7473
|
-
a: row.a,
|
|
7474
|
-
b: row.b,
|
|
7475
|
-
queue: row.queue,
|
|
7476
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7477
|
-
outcome: "merged",
|
|
7478
|
-
archived: outcome.archived ?? [],
|
|
6800
|
+
pair: pair("merged", {
|
|
6801
|
+
...outcome.archived === void 0 ? {} : { archived: outcome.archived },
|
|
7479
6802
|
...outcome.lengths === void 0 ? {} : { lengths: outcome.lengths },
|
|
7480
6803
|
...reportExtra,
|
|
7481
6804
|
...outcome.unitId === void 0 ? {} : { unitId: outcome.unitId },
|
|
7482
6805
|
...outcome.target === void 0 ? {} : { target: outcome.target },
|
|
7483
6806
|
...outcome.validationPlan === void 0 ? {} : { validationPlan: outcome.validationPlan }
|
|
7484
|
-
}
|
|
6807
|
+
})
|
|
7485
6808
|
};
|
|
7486
6809
|
}
|
|
7487
6810
|
const failure = outcome.failure ?? {
|
|
@@ -7504,18 +6827,10 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7504
6827
|
})) await dropStage(io, home, row.id);
|
|
7505
6828
|
return {
|
|
7506
6829
|
merged: false,
|
|
7507
|
-
pair: {
|
|
7508
|
-
id: row.id,
|
|
7509
|
-
pairKey: row.pairKey,
|
|
7510
|
-
a: row.a,
|
|
7511
|
-
b: row.b,
|
|
7512
|
-
queue: row.queue,
|
|
7513
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7514
|
-
outcome: "failed",
|
|
7515
|
-
archived: [],
|
|
6830
|
+
pair: pair("failed", {
|
|
7516
6831
|
failure,
|
|
7517
6832
|
...reportExtra
|
|
7518
|
-
}
|
|
6833
|
+
})
|
|
7519
6834
|
};
|
|
7520
6835
|
}
|
|
7521
6836
|
const cas = casExpiredHook(failure.code);
|
|
@@ -7537,33 +6852,17 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7537
6852
|
await dropStage(io, home, row.id);
|
|
7538
6853
|
return {
|
|
7539
6854
|
merged: false,
|
|
7540
|
-
pair: {
|
|
7541
|
-
id: row.id,
|
|
7542
|
-
pairKey: row.pairKey,
|
|
7543
|
-
a: row.a,
|
|
7544
|
-
b: row.b,
|
|
7545
|
-
queue: row.queue,
|
|
7546
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7547
|
-
outcome: "failed",
|
|
7548
|
-
archived: [],
|
|
6855
|
+
pair: pair("failed", {
|
|
7549
6856
|
failure: terminalFailure,
|
|
7550
6857
|
...reportExtra
|
|
7551
|
-
}
|
|
6858
|
+
})
|
|
7552
6859
|
};
|
|
7553
6860
|
}
|
|
7554
6861
|
if (failure.code === "commit-failed" || failure.code === "validation-failed") {
|
|
7555
6862
|
if (await pairLedger(io, home, fence).transact((tx) => {
|
|
7556
6863
|
const current = tx.rows().find((item) => item.id === row.id);
|
|
7557
6864
|
return current === void 0 ? false : tx.remove(row.id, "superseded", void 0, current.version).ok;
|
|
7558
|
-
}))
|
|
7559
|
-
await dropStage(io, home, row.id, row.stagingRef);
|
|
7560
|
-
await recordPair(io, home, {
|
|
7561
|
-
pairKey: row.pairKey,
|
|
7562
|
-
runId: row.runId ?? "merge",
|
|
7563
|
-
result: "failed",
|
|
7564
|
-
...row.decision?.target === void 0 ? {} : { target: row.decision.target }
|
|
7565
|
-
});
|
|
7566
|
-
}
|
|
6865
|
+
})) await dropStage(io, home, row.id, row.stagingRef);
|
|
7567
6866
|
}
|
|
7568
6867
|
if (failure.code === "source-gone") {
|
|
7569
6868
|
if (await pairLedger(io, home, fence).transact((tx) => {
|
|
@@ -7572,16 +6871,7 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7572
6871
|
})) await dropStage(io, home, row.id, row.stagingRef);
|
|
7573
6872
|
return {
|
|
7574
6873
|
merged: false,
|
|
7575
|
-
pair: {
|
|
7576
|
-
id: row.id,
|
|
7577
|
-
pairKey: row.pairKey,
|
|
7578
|
-
a: row.a,
|
|
7579
|
-
b: row.b,
|
|
7580
|
-
queue: row.queue,
|
|
7581
|
-
outcome: "failed",
|
|
7582
|
-
archived: [],
|
|
7583
|
-
failure
|
|
7584
|
-
}
|
|
6874
|
+
pair: pair("failed", { failure }, false)
|
|
7585
6875
|
};
|
|
7586
6876
|
}
|
|
7587
6877
|
if (await pairLedger(io, home, fence).transact((tx) => {
|
|
@@ -7594,42 +6884,21 @@ async function recordRound2Outcome(io, home, now, row, outcome, deferProjection
|
|
|
7594
6884
|
return moved.ok && moved.row !== null ? v4ToLegacy(moved.row) : null;
|
|
7595
6885
|
}) === null) return {
|
|
7596
6886
|
merged: false,
|
|
7597
|
-
pair: {
|
|
7598
|
-
id: row.id,
|
|
7599
|
-
pairKey: row.pairKey,
|
|
7600
|
-
a: row.a,
|
|
7601
|
-
b: row.b,
|
|
7602
|
-
queue: row.queue,
|
|
7603
|
-
outcome: "failed",
|
|
7604
|
-
archived: [],
|
|
6887
|
+
pair: pair("failed", {
|
|
7605
6888
|
failure: {
|
|
7606
6889
|
...failure,
|
|
7607
6890
|
code: "row-changed",
|
|
7608
6891
|
message: "row changed before failure record"
|
|
7609
6892
|
},
|
|
7610
6893
|
...reportExtra
|
|
7611
|
-
}
|
|
6894
|
+
}, false)
|
|
7612
6895
|
};
|
|
7613
|
-
await recordPair(io, home, {
|
|
7614
|
-
pairKey: row.pairKey,
|
|
7615
|
-
runId: row.runId ?? "merge",
|
|
7616
|
-
result: "failed",
|
|
7617
|
-
...row.decision?.target === void 0 ? {} : { target: row.decision.target }
|
|
7618
|
-
});
|
|
7619
6896
|
return {
|
|
7620
6897
|
merged: false,
|
|
7621
|
-
pair: {
|
|
7622
|
-
id: row.id,
|
|
7623
|
-
pairKey: row.pairKey,
|
|
7624
|
-
a: row.a,
|
|
7625
|
-
b: row.b,
|
|
7626
|
-
queue: row.queue,
|
|
7627
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
7628
|
-
outcome: "failed",
|
|
7629
|
-
archived: [],
|
|
6898
|
+
pair: pair("failed", {
|
|
7630
6899
|
failure,
|
|
7631
6900
|
...reportExtra
|
|
7632
|
-
}
|
|
6901
|
+
})
|
|
7633
6902
|
};
|
|
7634
6903
|
}
|
|
7635
6904
|
//#endregion
|
|
@@ -8078,14 +7347,6 @@ async function runUndoSteps(options) {
|
|
|
8078
7347
|
};
|
|
8079
7348
|
}
|
|
8080
7349
|
if (await readUndoReceipt(options.io, options.home, options.runId, pairKey) !== null) {
|
|
8081
|
-
await markPhase("pair-index");
|
|
8082
|
-
await options.onPhase?.("pair-index", pairKey);
|
|
8083
|
-
await recordPair(options.io, options.home, {
|
|
8084
|
-
pairKey,
|
|
8085
|
-
runId: options.runId,
|
|
8086
|
-
result: "undone",
|
|
8087
|
-
target: receipt.target
|
|
8088
|
-
});
|
|
8089
7350
|
await markPhase("run-meta");
|
|
8090
7351
|
await options.onPhase?.("run-meta", pairKey);
|
|
8091
7352
|
await settleRun(options.io, options.home, options.runId, pairKey, allPairKeys, options.now());
|
|
@@ -8112,14 +7373,6 @@ async function runUndoSteps(options) {
|
|
|
8112
7373
|
restoredSourceHashes: Object.fromEntries(checked.evidence.sources.map((source) => [source.name, contentHash(source.before)])),
|
|
8113
7374
|
at: options.now()
|
|
8114
7375
|
});
|
|
8115
|
-
await markPhase("pair-index");
|
|
8116
|
-
await options.onPhase?.("pair-index", pairKey);
|
|
8117
|
-
await recordPair(options.io, options.home, {
|
|
8118
|
-
pairKey,
|
|
8119
|
-
runId: options.runId,
|
|
8120
|
-
result: "undone",
|
|
8121
|
-
target: receipt.target
|
|
8122
|
-
});
|
|
8123
7376
|
await markPhase("run-meta");
|
|
8124
7377
|
await options.onPhase?.("run-meta", pairKey);
|
|
8125
7378
|
await settleRun(options.io, options.home, options.runId, pairKey, allPairKeys, options.now());
|
|
@@ -8179,13 +7432,6 @@ async function runUndoSteps(options) {
|
|
|
8179
7432
|
restoredSourceHashes: Object.fromEntries(checked.evidence.sources.map((source) => [source.name, contentHash(source.before)])),
|
|
8180
7433
|
at: options.now()
|
|
8181
7434
|
});
|
|
8182
|
-
await options.onPhase?.("pair-index", pairKey);
|
|
8183
|
-
await recordPair(options.io, options.home, {
|
|
8184
|
-
pairKey,
|
|
8185
|
-
runId: options.runId,
|
|
8186
|
-
result: "undone",
|
|
8187
|
-
target: receipt.target
|
|
8188
|
-
});
|
|
8189
7435
|
await options.onPhase?.("run-meta", pairKey);
|
|
8190
7436
|
await settleRun(options.io, options.home, options.runId, pairKey, allPairKeys, options.now());
|
|
8191
7437
|
undone.push(pairKey);
|
|
@@ -8416,9 +7662,6 @@ function buildRound2Prompt(row, decision, mode = "continue") {
|
|
|
8416
7662
|
...body
|
|
8417
7663
|
] : [...head, ...body]).join("\n");
|
|
8418
7664
|
}
|
|
8419
|
-
function buildStandbyPrompt() {
|
|
8420
|
-
return STANDBY_PROMPT;
|
|
8421
|
-
}
|
|
8422
7665
|
//#endregion
|
|
8423
7666
|
//#region lib/types/channel-port.js
|
|
8424
7667
|
async function runRound1OverChannel(options, candidate, signal) {
|
|
@@ -8926,14 +8169,6 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8926
8169
|
message: "target is blocked by curator: " + assembled.plan.target,
|
|
8927
8170
|
plan: assembled.plan
|
|
8928
8171
|
};
|
|
8929
|
-
const journal = {
|
|
8930
|
-
runId,
|
|
8931
|
-
target: assembled.plan.target,
|
|
8932
|
-
create: !assembled.plan.targetExists,
|
|
8933
|
-
sources: assembled.plan.sources,
|
|
8934
|
-
phase: "prepared",
|
|
8935
|
-
updatedAt: new Date(options.now()).toISOString()
|
|
8936
|
-
};
|
|
8937
8172
|
let result;
|
|
8938
8173
|
let evidenceSha256$1;
|
|
8939
8174
|
let warning;
|
|
@@ -8963,9 +8198,6 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8963
8198
|
...options.sourceRevisions === void 0 ? {} : { sourceRevisions: options.sourceRevisions },
|
|
8964
8199
|
...options.supportDigest === void 0 ? {} : { supportDigest: options.supportDigest }
|
|
8965
8200
|
};
|
|
8966
|
-
try {
|
|
8967
|
-
await writeJournal(io, home, journal);
|
|
8968
|
-
} catch {}
|
|
8969
8201
|
const prepared = await transaction.prepare(unitPlan);
|
|
8970
8202
|
if (!prepared.ok) return {
|
|
8971
8203
|
ok: false,
|
|
@@ -8973,21 +8205,12 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
8973
8205
|
plan: assembled.plan
|
|
8974
8206
|
};
|
|
8975
8207
|
const committed = await transaction.commit(prepared.prepared, options.signal === void 0 ? void 0 : { signal: options.signal });
|
|
8976
|
-
if (!committed.ok) {
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
});
|
|
8983
|
-
} catch {}
|
|
8984
|
-
return {
|
|
8985
|
-
ok: false,
|
|
8986
|
-
message: committed.message,
|
|
8987
|
-
plan: assembled.plan,
|
|
8988
|
-
...committed.code === "target-changed" || committed.code === "source-changed" || committed.code === "support-changed" ? { code: committed.code } : {}
|
|
8989
|
-
};
|
|
8990
|
-
}
|
|
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
|
+
};
|
|
8991
8214
|
const unitId = committed.evidence.unitId;
|
|
8992
8215
|
if (committed.evidence.unitId !== prepared.prepared.unitId && !prepared.prepared.unitId.startsWith("legacy:")) return {
|
|
8993
8216
|
ok: false,
|
|
@@ -9008,29 +8231,11 @@ async function commitStagedRun(io, home, runId, port, options) {
|
|
|
9008
8231
|
mutations: committed.evidence.mutations
|
|
9009
8232
|
};
|
|
9010
8233
|
}
|
|
9011
|
-
if (!result.ok) {
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
phase: "failed",
|
|
9016
|
-
updatedAt: new Date(options.now()).toISOString()
|
|
9017
|
-
});
|
|
9018
|
-
} catch {}
|
|
9019
|
-
return {
|
|
9020
|
-
ok: false,
|
|
9021
|
-
message: result.message,
|
|
9022
|
-
plan: assembled.plan
|
|
9023
|
-
};
|
|
9024
|
-
}
|
|
9025
|
-
const committed = {
|
|
9026
|
-
...journal,
|
|
9027
|
-
phase: "committed",
|
|
9028
|
-
updatedAt: new Date(options.now()).toISOString(),
|
|
9029
|
-
...result.unitId === void 0 ? {} : { unitId: result.unitId }
|
|
8234
|
+
if (!result.ok) return {
|
|
8235
|
+
ok: false,
|
|
8236
|
+
message: result.message,
|
|
8237
|
+
plan: assembled.plan
|
|
9030
8238
|
};
|
|
9031
|
-
try {
|
|
9032
|
-
await writeJournal(io, home, committed);
|
|
9033
|
-
} catch {}
|
|
9034
8239
|
if (result.unitId === void 0) return {
|
|
9035
8240
|
ok: true,
|
|
9036
8241
|
plan: assembled.plan,
|
|
@@ -9312,32 +8517,38 @@ function missingManifestFile(files, stagedPaths) {
|
|
|
9312
8517
|
}
|
|
9313
8518
|
//#endregion
|
|
9314
8519
|
//#region lib/types/authoring-flow.js
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
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 {
|
|
9318
8523
|
code: "target-invalid",
|
|
9319
|
-
message: "target must be a bare skill name: " +
|
|
8524
|
+
message: "target must be a bare skill name: " + target
|
|
9320
8525
|
};
|
|
9321
|
-
const targetCard = options.cards.find((card) => card.name === options.target);
|
|
9322
|
-
const requestedMode = options.mode ?? (targetCard === void 0 ? "create-umbrella" : "merge-into-existing");
|
|
9323
|
-
const mode = requestedMode === "merge-into-existing" && targetCard === void 0 ? "create-umbrella" : requestedMode;
|
|
9324
|
-
const createMode = mode === "create-umbrella";
|
|
9325
8526
|
if (!createMode && targetCard !== void 0) {
|
|
9326
8527
|
if (targetCard.managed !== true) return {
|
|
9327
|
-
ok: false,
|
|
9328
8528
|
code: "target-not-managed",
|
|
9329
|
-
message: "target is not family-managed: " +
|
|
8529
|
+
message: "target is not family-managed: " + target
|
|
9330
8530
|
};
|
|
9331
8531
|
if (targetCard.protectionUnknown === true || targetCard.protectedBy != null) return {
|
|
9332
|
-
ok: false,
|
|
9333
8532
|
code: "target-protected",
|
|
9334
|
-
message: "target is protected (" + (targetCard.protectedBy ?? "unknown") + "): " +
|
|
8533
|
+
message: "target is protected (" + (targetCard.protectedBy ?? "unknown") + "): " + target
|
|
9335
8534
|
};
|
|
9336
8535
|
}
|
|
9337
|
-
if (!createMode && await
|
|
9338
|
-
ok: false,
|
|
8536
|
+
if (!createMode && await isBlocked?.(target) === true) return {
|
|
9339
8537
|
code: "target-blocked",
|
|
9340
|
-
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
|
|
9341
8552
|
};
|
|
9342
8553
|
const stageKey = options.stageKey ?? options.runId;
|
|
9343
8554
|
if (options.reuseStaging === true) {
|
|
@@ -9659,46 +8870,15 @@ const STALE_CAUSES = new Set([
|
|
|
9659
8870
|
"target-gone"
|
|
9660
8871
|
]);
|
|
9661
8872
|
async function runNewChildAuthoring(options, row, decision, signal) {
|
|
9662
|
-
if (decision.target.includes("/") || decision.target.includes(":")) return {
|
|
9663
|
-
kind: "failed",
|
|
9664
|
-
failure: {
|
|
9665
|
-
stage: "author",
|
|
9666
|
-
code: "target-invalid",
|
|
9667
|
-
message: "target must be a bare skill name: " + decision.target,
|
|
9668
|
-
retryable: false,
|
|
9669
|
-
retryFrom: "none"
|
|
9670
|
-
}
|
|
9671
|
-
};
|
|
9672
8873
|
const targetCard = options.cards.find((card) => card.name === decision.target);
|
|
9673
8874
|
const createMode = decision.mode === "create-umbrella";
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
kind: "failed",
|
|
9677
|
-
failure: {
|
|
9678
|
-
stage: "author",
|
|
9679
|
-
code: "target-not-managed",
|
|
9680
|
-
message: "target is not family-managed: " + decision.target,
|
|
9681
|
-
retryable: false,
|
|
9682
|
-
retryFrom: "none"
|
|
9683
|
-
}
|
|
9684
|
-
};
|
|
9685
|
-
if (targetCard.protectionUnknown === true || targetCard.protectedBy != null) return {
|
|
9686
|
-
kind: "failed",
|
|
9687
|
-
failure: {
|
|
9688
|
-
stage: "author",
|
|
9689
|
-
code: "target-protected",
|
|
9690
|
-
message: "target is protected: " + decision.target,
|
|
9691
|
-
retryable: false,
|
|
9692
|
-
retryFrom: "none"
|
|
9693
|
-
}
|
|
9694
|
-
};
|
|
9695
|
-
}
|
|
9696
|
-
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 {
|
|
9697
8877
|
kind: "failed",
|
|
9698
8878
|
failure: {
|
|
9699
8879
|
stage: "author",
|
|
9700
|
-
code:
|
|
9701
|
-
message:
|
|
8880
|
+
code: targetRefusal.code,
|
|
8881
|
+
message: targetRefusal.message,
|
|
9702
8882
|
retryable: false,
|
|
9703
8883
|
retryFrom: "none"
|
|
9704
8884
|
}
|
|
@@ -11161,143 +10341,6 @@ async function supersedeMergeRuns(registry) {
|
|
|
11161
10341
|
return ids.length;
|
|
11162
10342
|
}
|
|
11163
10343
|
//#endregion
|
|
11164
|
-
//#region lib/types/coordinator.js
|
|
11165
|
-
/**
|
|
11166
|
-
* Pure merge transition table. No io, no run shell, no subagents.
|
|
11167
|
-
*
|
|
11168
|
-
* Every transition returns the whole next row (or a drop), so the caller can persist it
|
|
11169
|
-
* through one state transaction. Invalid transitions are refused by name;
|
|
11170
|
-
* a caller never "repairs" a row by guessing which state the operator meant.
|
|
11171
|
-
*/
|
|
11172
|
-
function invalid(event, state) {
|
|
11173
|
-
return {
|
|
11174
|
-
ok: false,
|
|
11175
|
-
code: "invalid-transition",
|
|
11176
|
-
message: "cannot apply " + event.type + " to " + (state ?? "no row")
|
|
11177
|
-
};
|
|
11178
|
-
}
|
|
11179
|
-
/** Drop fields that must not survive a transition; optional fields stay absent. */
|
|
11180
|
-
function base(row, at) {
|
|
11181
|
-
return {
|
|
11182
|
-
id: row.id,
|
|
11183
|
-
pairKey: row.pairKey,
|
|
11184
|
-
a: row.a,
|
|
11185
|
-
b: row.b,
|
|
11186
|
-
state: row.state,
|
|
11187
|
-
queue: row.queue,
|
|
11188
|
-
createdAt: row.createdAt,
|
|
11189
|
-
updatedAt: at,
|
|
11190
|
-
...row.runId === void 0 ? {} : { runId: row.runId },
|
|
11191
|
-
...row.unitId === void 0 ? {} : { unitId: row.unitId },
|
|
11192
|
-
...row.origin === void 0 ? {} : { origin: row.origin },
|
|
11193
|
-
...row.decision === void 0 ? {} : { decision: row.decision },
|
|
11194
|
-
...row.sourceRevision === void 0 ? {} : { sourceRevision: row.sourceRevision },
|
|
11195
|
-
...row.targetRevision === void 0 ? {} : { targetRevision: row.targetRevision },
|
|
11196
|
-
...row.attempts === void 0 ? {} : { attempts: row.attempts },
|
|
11197
|
-
...row.stagingRef === void 0 ? {} : { stagingRef: row.stagingRef },
|
|
11198
|
-
...row.stagingExpiresAt === void 0 ? {} : { stagingExpiresAt: row.stagingExpiresAt },
|
|
11199
|
-
...row.expired === void 0 ? {} : { expired: row.expired },
|
|
11200
|
-
...row.reason === void 0 ? {} : { reason: row.reason },
|
|
11201
|
-
...row.target === void 0 ? {} : { target: row.target }
|
|
11202
|
-
};
|
|
11203
|
-
}
|
|
11204
|
-
function next(row, at, state, patch = {}) {
|
|
11205
|
-
return {
|
|
11206
|
-
ok: true,
|
|
11207
|
-
row: {
|
|
11208
|
-
...base(row, at),
|
|
11209
|
-
state,
|
|
11210
|
-
queue: queueOf(state),
|
|
11211
|
-
...patch
|
|
11212
|
-
}
|
|
11213
|
-
};
|
|
11214
|
-
}
|
|
11215
|
-
/** Legacy v2 projection only; runtime writes must use transitionV3/RowTx. */
|
|
11216
|
-
function transitionLegacyForProjection(current, event) {
|
|
11217
|
-
if (event.type === "candidate") {
|
|
11218
|
-
if (current !== void 0) return {
|
|
11219
|
-
ok: true,
|
|
11220
|
-
row: current
|
|
11221
|
-
};
|
|
11222
|
-
const key = pairKey(event.a, event.b);
|
|
11223
|
-
return {
|
|
11224
|
-
ok: true,
|
|
11225
|
-
row: {
|
|
11226
|
-
id: rowIdOf(key),
|
|
11227
|
-
pairKey: key,
|
|
11228
|
-
a: event.a,
|
|
11229
|
-
b: event.b,
|
|
11230
|
-
state: "verify",
|
|
11231
|
-
queue: "verify",
|
|
11232
|
-
createdAt: event.at,
|
|
11233
|
-
updatedAt: event.at
|
|
11234
|
-
}
|
|
11235
|
-
};
|
|
11236
|
-
}
|
|
11237
|
-
if (event.type === "source-gone") return {
|
|
11238
|
-
ok: true,
|
|
11239
|
-
row: null
|
|
11240
|
-
};
|
|
11241
|
-
if (event.type === "gate-keep") {
|
|
11242
|
-
if (current !== void 0) return {
|
|
11243
|
-
ok: true,
|
|
11244
|
-
row: current
|
|
11245
|
-
};
|
|
11246
|
-
const key = pairKey(event.a, event.b);
|
|
11247
|
-
return {
|
|
11248
|
-
ok: true,
|
|
11249
|
-
row: {
|
|
11250
|
-
id: rowIdOf(key),
|
|
11251
|
-
pairKey: key,
|
|
11252
|
-
a: event.a,
|
|
11253
|
-
b: event.b,
|
|
11254
|
-
state: "skipped",
|
|
11255
|
-
queue: "skipped",
|
|
11256
|
-
origin: "agent",
|
|
11257
|
-
createdAt: event.at,
|
|
11258
|
-
updatedAt: event.at
|
|
11259
|
-
}
|
|
11260
|
-
};
|
|
11261
|
-
}
|
|
11262
|
-
if (current === void 0) return invalid(event, void 0);
|
|
11263
|
-
switch (event.type) {
|
|
11264
|
-
case "round1-keep": return current.state === "verify" ? next(current, event.at, "skipped", { origin: "agent" }) : invalid(event, current.state);
|
|
11265
|
-
case "round1-merge":
|
|
11266
|
-
if (current.state !== "verify") return invalid(event, current.state);
|
|
11267
|
-
return event.approval === "on" ? next(current, event.at, "pending", {
|
|
11268
|
-
...event.decision === void 0 ? {} : { decision: event.decision },
|
|
11269
|
-
...event.stagingRef === void 0 ? {} : { stagingRef: event.stagingRef },
|
|
11270
|
-
...event.stagingExpiresAt === void 0 ? {} : { stagingExpiresAt: event.stagingExpiresAt },
|
|
11271
|
-
...event.sourceRevision === void 0 ? {} : { sourceRevision: event.sourceRevision },
|
|
11272
|
-
...event.targetRevision === void 0 ? {} : { targetRevision: event.targetRevision }
|
|
11273
|
-
}) : next(current, event.at, "approved", {
|
|
11274
|
-
...event.decision === void 0 ? {} : { decision: event.decision },
|
|
11275
|
-
...event.stagingRef === void 0 ? {} : { stagingRef: event.stagingRef },
|
|
11276
|
-
...event.stagingExpiresAt === void 0 ? {} : { stagingExpiresAt: event.stagingExpiresAt },
|
|
11277
|
-
...event.sourceRevision === void 0 ? {} : { sourceRevision: event.sourceRevision },
|
|
11278
|
-
...event.targetRevision === void 0 ? {} : { targetRevision: event.targetRevision }
|
|
11279
|
-
});
|
|
11280
|
-
case "round1-fail": return current.state === "verify" ? next(current, event.at, "verify", {
|
|
11281
|
-
failure: event.failure,
|
|
11282
|
-
attempts: (current.attempts ?? 0) + 1
|
|
11283
|
-
}) : invalid(event, current.state);
|
|
11284
|
-
case "approve": return current.state === "pending" ? next(current, event.at, "approved", event.runId === void 0 ? {} : { runId: event.runId }) : invalid(event, current.state);
|
|
11285
|
-
case "reject": return current.state === "pending" ? next(current, event.at, "skipped", { origin: "human" }) : invalid(event, current.state);
|
|
11286
|
-
case "round2-cancel": return current.state === "fuse" || current.state === "approved" ? next(current, event.at, "approved") : invalid(event, current.state);
|
|
11287
|
-
case "round2-fail": return current.state === "fuse" || current.state === "approved" ? next(current, event.at, "approved", {
|
|
11288
|
-
failure: event.failure,
|
|
11289
|
-
attempts: (current.attempts ?? 0) + 1
|
|
11290
|
-
}) : invalid(event, current.state);
|
|
11291
|
-
case "round2-success": return current.state === "fuse" || current.state === "approved" ? {
|
|
11292
|
-
ok: true,
|
|
11293
|
-
row: null
|
|
11294
|
-
} : invalid(event, current.state);
|
|
11295
|
-
case "target-taken":
|
|
11296
|
-
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);
|
|
11297
|
-
case "restore": return current.state === "skipped" ? next(current, event.at, "verify") : invalid(event, current.state);
|
|
11298
|
-
}
|
|
11299
|
-
}
|
|
11300
|
-
//#endregion
|
|
11301
10344
|
//#region lib/types/pair-command.js
|
|
11302
10345
|
async function runPairCommand(options) {
|
|
11303
10346
|
return await runScanCommand({
|
|
@@ -11674,25 +10717,6 @@ function apply(ctx, rawConfig = {}) {
|
|
|
11674
10717
|
},
|
|
11675
10718
|
async bodyRef(ref) {
|
|
11676
10719
|
return await resolveBody(io, home, ref, async () => ref.side === "archive" ? await skills.readArchived(ref.name) : await skills.read(ref.name));
|
|
11677
|
-
},
|
|
11678
|
-
approval() {
|
|
11679
|
-
return getParams().mergeApproval;
|
|
11680
|
-
},
|
|
11681
|
-
readiness() {
|
|
11682
|
-
return ready;
|
|
11683
|
-
},
|
|
11684
|
-
commands() {
|
|
11685
|
-
return [
|
|
11686
|
-
"merge scan",
|
|
11687
|
-
"merge doctor",
|
|
11688
|
-
"merge status",
|
|
11689
|
-
"merge pending",
|
|
11690
|
-
"merge skipped",
|
|
11691
|
-
"merge report",
|
|
11692
|
-
"merge runs",
|
|
11693
|
-
"merge cancel",
|
|
11694
|
-
"merge reconcile"
|
|
11695
|
-
];
|
|
11696
10720
|
}
|
|
11697
10721
|
};
|
|
11698
10722
|
doctorFact = async () => {
|
|
@@ -11779,4 +10803,4 @@ function apply(ctx, rawConfig = {}) {
|
|
|
11779
10803
|
});
|
|
11780
10804
|
}
|
|
11781
10805
|
//#endregion
|
|
11782
|
-
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 };
|