githolon 0.105.4 → 0.105.5
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/dist/compile_mountability_entry.js +181 -10
- package/dist/dev-server.mjs +177 -8
- package/dist/full-cli.mjs +254 -14
- package/package.json +2 -2
|
@@ -587,6 +587,7 @@ __export(engine_exports, {
|
|
|
587
587
|
cryptoUnwrapKey: () => cryptoUnwrapKey,
|
|
588
588
|
cryptoWrapKey: () => cryptoWrapKey,
|
|
589
589
|
currentLaw: () => currentLaw,
|
|
590
|
+
custodyConfirmedMain: () => custodyConfirmedMain,
|
|
590
591
|
declaredCapabilities: () => declaredCapabilities,
|
|
591
592
|
deepVerifyShard: () => deepVerifyShard,
|
|
592
593
|
delegationCertSign: () => delegationCertSign,
|
|
@@ -613,6 +614,7 @@ __export(engine_exports, {
|
|
|
613
614
|
ingestPackAsCustody: () => ingestPackAsCustody,
|
|
614
615
|
installedLaw: () => installedLaw,
|
|
615
616
|
intentOfferResidencies: () => intentOfferResidencies,
|
|
617
|
+
isDirty: () => isDirty,
|
|
616
618
|
isWarranted: () => isWarranted,
|
|
617
619
|
kernelStamp: () => kernelStamp,
|
|
618
620
|
kgit: () => kgit,
|
|
@@ -1645,6 +1647,40 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1645
1647
|
const s0 = Date.now();
|
|
1646
1648
|
return (end = {}) => timings.spans.push({ id: `intent-offer-${t0}-${seq++}`, track: "cloud", name, kind, depth, t0: s0, t1: Date.now(), ...extra, ...end });
|
|
1647
1649
|
};
|
|
1650
|
+
let footageRef = null;
|
|
1651
|
+
{
|
|
1652
|
+
const parked = [];
|
|
1653
|
+
for (const offer of Array.isArray(offers) ? offers : []) {
|
|
1654
|
+
let blob = offer?.blob instanceof Uint8Array ? offer.blob : null;
|
|
1655
|
+
try {
|
|
1656
|
+
if (!blob && typeof offer?.changeB64 === "string") blob = Uint8Array.from(atob(offer.changeB64), (c) => c.charCodeAt(0));
|
|
1657
|
+
} catch {
|
|
1658
|
+
}
|
|
1659
|
+
if (blob && blob.byteLength) parked.push(blob);
|
|
1660
|
+
}
|
|
1661
|
+
if (parked.length) {
|
|
1662
|
+
footageRef = `refs/heads/parked/offered/${t0.toString(36)}-${Math.floor(Math.random() * 16777215).toString(36)}`;
|
|
1663
|
+
const footageDone = span("park offer footage", "cseal", 1, { offers: parked.length });
|
|
1664
|
+
try {
|
|
1665
|
+
kgit.writeMetaCommit(eng, gitdirOf(ws), {
|
|
1666
|
+
parents: [],
|
|
1667
|
+
files: parked.map((bytes, i) => ({ path: `${i}.change.usda`, bytes })),
|
|
1668
|
+
message: `offered: ${parked.length} intent(s) parked pre-judgment (footage-first)`,
|
|
1669
|
+
timeSecs: 0,
|
|
1670
|
+
ref: footageRef
|
|
1671
|
+
});
|
|
1672
|
+
await custodyPush(eng, ws, ledger, { remoteRef: footageRef });
|
|
1673
|
+
} catch (e) {
|
|
1674
|
+
try {
|
|
1675
|
+
kgit.deleteRef(eng, gitdirOf(ws), footageRef);
|
|
1676
|
+
} catch {
|
|
1677
|
+
}
|
|
1678
|
+
throw new Error(`offer footage not durable \u2014 custody unreachable, nothing was folded; retry the batch: ${String(e).slice(0, 300)}`, { cause: e });
|
|
1679
|
+
} finally {
|
|
1680
|
+
footageDone();
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1648
1684
|
for (const offer of Array.isArray(offers) ? offers : []) {
|
|
1649
1685
|
const cid = typeof offer?.session === "string" && offer.session ? offer.session : "direct";
|
|
1650
1686
|
const rec = sessions.get(cid) || { session: cid, admitted: [], rejected: [], skipped: [] };
|
|
@@ -1720,10 +1756,13 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1720
1756
|
}
|
|
1721
1757
|
timings.sessions = sessions.size;
|
|
1722
1758
|
timings.intents = admittedTotal;
|
|
1759
|
+
let refusalsParked = true;
|
|
1723
1760
|
if (deadLetters.length) {
|
|
1724
1761
|
try {
|
|
1725
|
-
await materializeRefused(eng, ws, ledger, deadLetters);
|
|
1762
|
+
const m = await materializeRefused(eng, ws, ledger, deadLetters);
|
|
1763
|
+
refusalsParked = m.unparkedSessions.size === 0;
|
|
1726
1764
|
} catch (e) {
|
|
1765
|
+
refusalsParked = false;
|
|
1727
1766
|
log("refused-materialize-failed", { ws, error: String(e).slice(0, 200) });
|
|
1728
1767
|
}
|
|
1729
1768
|
}
|
|
@@ -1732,6 +1771,17 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1732
1771
|
await commitAndPush(eng, ws, ledger);
|
|
1733
1772
|
sealDone();
|
|
1734
1773
|
}
|
|
1774
|
+
if (footageRef && refusalsParked) {
|
|
1775
|
+
try {
|
|
1776
|
+
kgit.deleteRef(eng, gitdirOf(ws), footageRef);
|
|
1777
|
+
} catch {
|
|
1778
|
+
}
|
|
1779
|
+
try {
|
|
1780
|
+
await custodyPush(eng, ws, ledger, { remoteRef: footageRef, del: true });
|
|
1781
|
+
} catch (e) {
|
|
1782
|
+
log("footage-delete-push-failed", { ws, ref: footageRef, error: String(e).slice(0, 200) });
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1735
1785
|
const gitdir = gitdirOf(ws);
|
|
1736
1786
|
const head = kgit.resolveRef(eng, gitdir, BRANCH) ?? main.head;
|
|
1737
1787
|
const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore ?? "", head ?? "") : null;
|
|
@@ -1745,7 +1795,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1745
1795
|
}
|
|
1746
1796
|
log("admit-intent-offers", { ws, sessions: sessions.size, admitted: admittedTotal, rejected: [...sessions.values()].reduce((n, s) => n + s.rejected.length, 0), resultPack: resultPackB64 ? "inline" : "none" });
|
|
1747
1797
|
const bornPacked = born.length ? packBornChildren(eng, born) : born;
|
|
1748
|
-
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
1798
|
+
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, sealed: true, sealedMain: custodyConfirmedMain(eng, ws), deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
1749
1799
|
}
|
|
1750
1800
|
function intentOfferResidencies(eng, offers) {
|
|
1751
1801
|
const unique = /* @__PURE__ */ new Map();
|
|
@@ -1877,6 +1927,7 @@ async function mountWorkspace(eng, ws, ledger) {
|
|
|
1877
1927
|
throw new Error(`kernel refused restored main ${remoteMain}: ${JSON.stringify(mounted)}`);
|
|
1878
1928
|
}
|
|
1879
1929
|
restored = true;
|
|
1930
|
+
custodyMainOf(eng).set(ws, remoteMain);
|
|
1880
1931
|
verificationVerdict = jsStruct(mounted.verdict);
|
|
1881
1932
|
}
|
|
1882
1933
|
} catch (e) {
|
|
@@ -2347,7 +2398,7 @@ async function custodyFetch(eng, ws, ledger, { remoteRef = "refs/heads/main", lo
|
|
|
2347
2398
|
if (writeRef) kgit.writeRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef), tip);
|
|
2348
2399
|
return tip;
|
|
2349
2400
|
}
|
|
2350
|
-
async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null }) {
|
|
2401
|
+
async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null, ffOnly = false }) {
|
|
2351
2402
|
const headers = ledger.headers || {};
|
|
2352
2403
|
const remoteRefFull = fullRef(remoteRef);
|
|
2353
2404
|
let remote;
|
|
@@ -2363,22 +2414,46 @@ async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del =
|
|
|
2363
2414
|
}
|
|
2364
2415
|
const tgt = newOid || kgit.resolveRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef));
|
|
2365
2416
|
if (!tgt) throw new Error(`custodyPush: local ref ${localRef || remoteRef} unresolved`);
|
|
2366
|
-
if (tgt === oldOid)
|
|
2417
|
+
if (tgt === oldOid) {
|
|
2418
|
+
if (remoteRefFull === fullRef(BRANCH)) custodyMainOf(eng).set(ws, tgt);
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2367
2421
|
let pack = null;
|
|
2368
2422
|
if (!pointer) {
|
|
2369
2423
|
pack = oldOid !== ZERO_OID ? packDelta(eng, ws, oldOid, tgt) : null;
|
|
2424
|
+
if (!pack && ffOnly && oldOid !== ZERO_OID) {
|
|
2425
|
+
throw new Error(`custody ${remoteRefFull} regression refused: remote ${oldOid.slice(0, 12)} is not an ancestor of local ${tgt.slice(0, 12)} \u2014 this engine's view is stale; re-mount from custody instead of forcing`);
|
|
2426
|
+
}
|
|
2370
2427
|
if (!pack) pack = packDelta(eng, ws, "", tgt);
|
|
2371
2428
|
}
|
|
2372
2429
|
const packBytes = pack?.byteLength ?? 0;
|
|
2373
2430
|
try {
|
|
2374
|
-
|
|
2431
|
+
const r = await pushVia(ledger, () => pushPack(ledger.remote, headers, { updates: [{ ref: remoteRefFull, oldOid, newOid: tgt }], pack }));
|
|
2432
|
+
if (remoteRefFull === fullRef(BRANCH)) custodyMainOf(eng).set(ws, tgt);
|
|
2433
|
+
return r;
|
|
2375
2434
|
} catch (error) {
|
|
2376
2435
|
throw new Error(`custody receive-pack push failed for ${remoteRefFull} (${packBytes} pack bytes): ${String(error)}`, { cause: error });
|
|
2377
2436
|
}
|
|
2378
2437
|
}
|
|
2438
|
+
function custodyMainOf(eng) {
|
|
2439
|
+
eng._custodyMain ??= /* @__PURE__ */ new Map();
|
|
2440
|
+
return eng._custodyMain;
|
|
2441
|
+
}
|
|
2442
|
+
function custodyConfirmedMain(eng, ws) {
|
|
2443
|
+
return custodyMainOf(eng).get(ws) ?? null;
|
|
2444
|
+
}
|
|
2445
|
+
function isDirty(eng, ws) {
|
|
2446
|
+
try {
|
|
2447
|
+
const resident = kgit.resolveRef(eng, gitdirOf(ws), BRANCH);
|
|
2448
|
+
if (!resident) return false;
|
|
2449
|
+
return resident !== custodyMainOf(eng).get(ws);
|
|
2450
|
+
} catch {
|
|
2451
|
+
return false;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2379
2454
|
async function commitAndPush(eng, ws, ledger) {
|
|
2380
2455
|
try {
|
|
2381
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main" });
|
|
2456
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", ffOnly: true });
|
|
2382
2457
|
} catch (e) {
|
|
2383
2458
|
unmount(eng, ws);
|
|
2384
2459
|
const cause = e instanceof Error ? e.cause : void 0;
|
|
@@ -2781,6 +2856,80 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
2781
2856
|
_sessionDone();
|
|
2782
2857
|
}
|
|
2783
2858
|
}
|
|
2859
|
+
const offeredRefPrefix = "refs/heads/parked/offered/";
|
|
2860
|
+
const footageConsumed = [];
|
|
2861
|
+
const footageBorn = [], footageBirthOutcomes = [];
|
|
2862
|
+
try {
|
|
2863
|
+
const offeredRefs = Object.entries(await custodyLsRefs(ledger, offeredRefPrefix));
|
|
2864
|
+
for (const [oref, ooid] of offeredRefs) {
|
|
2865
|
+
if (!oref.startsWith(offeredRefPrefix) || !ooid) continue;
|
|
2866
|
+
const fcid = `offered:${oref.slice(offeredRefPrefix.length)}`;
|
|
2867
|
+
const _fDone = _span(`footage ${fcid.slice(0, 24)}`, "csession", 1, { client: fcid });
|
|
2868
|
+
const admitted = [], rejected = [], skipped = [];
|
|
2869
|
+
try {
|
|
2870
|
+
try {
|
|
2871
|
+
await custodyFetch(eng, ws, ledger, { remoteRef: oref, have: kgit.resolveRef(eng, gitdir, BRANCH) });
|
|
2872
|
+
} catch {
|
|
2873
|
+
await custodyFetch(eng, ws, ledger, { remoteRef: oref, have: null });
|
|
2874
|
+
}
|
|
2875
|
+
const main = await mainIntentIds(eng, ws);
|
|
2876
|
+
for (let i = 0; ; i++) {
|
|
2877
|
+
let blob = null;
|
|
2878
|
+
try {
|
|
2879
|
+
blob = kgit.readBlob(eng, gitdir, ooid, `${i}.change.usda`);
|
|
2880
|
+
} catch {
|
|
2881
|
+
blob = null;
|
|
2882
|
+
}
|
|
2883
|
+
if (!blob || !blob.byteLength) break;
|
|
2884
|
+
try {
|
|
2885
|
+
const inspected = kgit.inspectChange(eng, blob);
|
|
2886
|
+
const intentId = inspected.intentId || null;
|
|
2887
|
+
const oid = String(intentId || `${fcid}#${i}`).slice(0, 10);
|
|
2888
|
+
if (!inspected.authored || !inspected.call) {
|
|
2889
|
+
rejected.push({ oid, error: "parked offer is not an authored nominal call" });
|
|
2890
|
+
continue;
|
|
2891
|
+
}
|
|
2892
|
+
const { domainPath: dom, directivePath: dirId } = inspected.call;
|
|
2893
|
+
if (receiptFence && dirId && Array.isArray(receiptFence[dom]) && receiptFence[dom].includes(dirId)) {
|
|
2894
|
+
const error = `'${dom}/${dirId}' is a capability RECEIPT \u2014 receipts are executor/owner writes, never open-session writes`;
|
|
2895
|
+
rejected.push({ oid, error, deadLettered: true });
|
|
2896
|
+
deadLetters.push({ intentId, oid, session: fcid, error, blob, domain: dom, directiveId: dirId });
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
if (intentId && main.ids.has(intentId)) {
|
|
2900
|
+
skipped.push({ oid, intent: intentId, alreadyOnMain: true });
|
|
2901
|
+
continue;
|
|
2902
|
+
}
|
|
2903
|
+
const res = offerAdmit(eng, ws, blob, { defer: canDeferProjection });
|
|
2904
|
+
if (res.ok) {
|
|
2905
|
+
if (intentId) main.ids.add(intentId);
|
|
2906
|
+
main.oids.add(res.head);
|
|
2907
|
+
main.head = res.head;
|
|
2908
|
+
admitted.push({ oid, intent: intentId, head: res.head });
|
|
2909
|
+
totalAdmitted += 1;
|
|
2910
|
+
_intents += 1;
|
|
2911
|
+
if (Array.isArray(res.born) && res.born.length) footageBorn.push(...res.born);
|
|
2912
|
+
if (Array.isArray(res.birthOutcomes) && res.birthOutcomes.length) footageBirthOutcomes.push(...res.birthOutcomes);
|
|
2913
|
+
} else {
|
|
2914
|
+
const error = `${String(res.error || "").slice(0, 300)} \u2014 dead-lettered; fix the law (or the payload), then POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
2915
|
+
rejected.push({ oid, error, deadLettered: true });
|
|
2916
|
+
deadLetters.push({ intentId, oid, session: fcid, error, blob, domain: dom, directiveId: dirId });
|
|
2917
|
+
}
|
|
2918
|
+
} catch (e) {
|
|
2919
|
+
rejected.push({ oid: `${fcid}#${i}`.slice(0, 10), error: String(e).slice(0, 200) });
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
footageConsumed.push(oref);
|
|
2923
|
+
results.push({ session: fcid, admitted, rejected, ...skipped.length ? { skipped } : {} });
|
|
2924
|
+
} catch (e) {
|
|
2925
|
+
results.push({ session: fcid, error: String(e).slice(0, 200) });
|
|
2926
|
+
} finally {
|
|
2927
|
+
_fDone({ admitted: admitted.length, rejected: rejected.length });
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
} catch (e) {
|
|
2931
|
+
log("footage-scan-failed", { ws, error: String(e).slice(0, 200) });
|
|
2932
|
+
}
|
|
2784
2933
|
if (canDeferProjection && totalAdmitted) {
|
|
2785
2934
|
const _projDone = _span("projection flush (batch)", "cproject", 1, { admitted: totalAdmitted });
|
|
2786
2935
|
try {
|
|
@@ -2804,7 +2953,8 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
2804
2953
|
const hasCoordination = !!(summaryCtx || placements.length || splits.length || globalsOut.length);
|
|
2805
2954
|
const deferDurability = defer && !hasCoordination;
|
|
2806
2955
|
let _sealed = true;
|
|
2807
|
-
|
|
2956
|
+
const sealNeeded = totalAdmitted > 0 || isDirty(eng, ws);
|
|
2957
|
+
if (sealNeeded && !deferDurability) {
|
|
2808
2958
|
const _sealDone = _span(`seal (batch)`, "cseal", 1, { sessions: consumed.length, admitted: totalAdmitted });
|
|
2809
2959
|
const _s = Date.now();
|
|
2810
2960
|
try {
|
|
@@ -2824,17 +2974,38 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
2824
2974
|
} catch {
|
|
2825
2975
|
}
|
|
2826
2976
|
}
|
|
2977
|
+
for (const oref of footageConsumed) {
|
|
2978
|
+
const fcid = `offered:${oref.slice(offeredRefPrefix.length)}`;
|
|
2979
|
+
if (unparkedSessions.has(fcid)) continue;
|
|
2980
|
+
try {
|
|
2981
|
+
kgit.deleteRef(eng, gitdir, oref);
|
|
2982
|
+
} catch {
|
|
2983
|
+
}
|
|
2984
|
+
try {
|
|
2985
|
+
await custodyPush(eng, ws, ledger, { remoteRef: oref, del: true });
|
|
2986
|
+
} catch {
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2827
2989
|
}
|
|
2828
2990
|
const newMain = kgit.resolveRef(eng, gitdir, BRANCH);
|
|
2829
|
-
log("admit", { ws, sessions: results.length, main: newMain });
|
|
2991
|
+
log("admit", { ws, sessions: results.length, main: newMain, sealed: _sealed, sealedMain: custodyConfirmedMain(eng, ws) });
|
|
2830
2992
|
const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore ?? "", newMain) : null;
|
|
2831
2993
|
const _total = Date.now() - _t0;
|
|
2832
2994
|
const timings = { totalMs: _total, scanMs: _scanMs, fetchMs: _fetchMs, sealMs: _sealMs, gateFoldMs: Math.max(0, _total - _scanMs - _fetchMs - _sealMs), intents: _intents, sessions: results.length, spans: _spans };
|
|
2833
2995
|
return {
|
|
2996
|
+
// SCOREBOARD TRUTH: `main` is the resident fold head (the ack the client converges to);
|
|
2997
|
+
// `sealedMain` is the custody-confirmed head — THE ONLY head the host may advertise/cache
|
|
2998
|
+
// (seated_barrier_and_seal_obligation.md Part 2). `sealed:false` ⇒ the seal obligation is
|
|
2999
|
+
// outstanding and the caller must re-arm the admit alarm (retry) rather than move on.
|
|
2834
3000
|
sessions: results,
|
|
2835
3001
|
main: newMain,
|
|
3002
|
+
sealed: _sealed,
|
|
3003
|
+
sealedMain: custodyConfirmedMain(eng, ws),
|
|
2836
3004
|
deadLetters,
|
|
2837
3005
|
timings,
|
|
3006
|
+
// Footage-replayed `.births()` offers: the born child custody + typed verdicts, for the caller
|
|
3007
|
+
// to persist exactly as the live POST lane does (packed here — the caller holds no engine FS).
|
|
3008
|
+
...footageBorn.length ? { born: packBornChildren(eng, footageBorn), birthOutcomes: footageBirthOutcomes } : {},
|
|
2838
3009
|
...summary ? { summary } : {},
|
|
2839
3010
|
...placements.length ? { placements } : {},
|
|
2840
3011
|
...splits.length ? { splits } : {},
|
|
@@ -2848,7 +3019,7 @@ async function backupHead(eng, ws, ledger, head) {
|
|
|
2848
3019
|
if (!eng.mounted.has(ws)) return { ok: false, error: "not mounted" };
|
|
2849
3020
|
if (!head) return { ok: false, error: "no head" };
|
|
2850
3021
|
try {
|
|
2851
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", newOid: head });
|
|
3022
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", newOid: head, ffOnly: true });
|
|
2852
3023
|
return { ok: true, head };
|
|
2853
3024
|
} catch (e) {
|
|
2854
3025
|
return { ok: false, error: String(e?.message || e).slice(0, 200), head };
|
|
@@ -2861,7 +3032,7 @@ async function backupToCustody(eng, ws, ledger, { consumed = [] } = {}) {
|
|
|
2861
3032
|
head = kgit.resolveRef(eng, gitdir, BRANCH);
|
|
2862
3033
|
if (!head) return { ok: false, error: "no local main" };
|
|
2863
3034
|
try {
|
|
2864
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main" });
|
|
3035
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", ffOnly: true });
|
|
2865
3036
|
} catch (e) {
|
|
2866
3037
|
return { ok: false, error: String(e).slice(0, 200), head };
|
|
2867
3038
|
}
|
package/dist/dev-server.mjs
CHANGED
|
@@ -936,6 +936,40 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
936
936
|
const s0 = Date.now();
|
|
937
937
|
return (end = {}) => timings.spans.push({ id: `intent-offer-${t0}-${seq++}`, track: "cloud", name, kind, depth, t0: s0, t1: Date.now(), ...extra, ...end });
|
|
938
938
|
};
|
|
939
|
+
let footageRef = null;
|
|
940
|
+
{
|
|
941
|
+
const parked = [];
|
|
942
|
+
for (const offer of Array.isArray(offers) ? offers : []) {
|
|
943
|
+
let blob = offer?.blob instanceof Uint8Array ? offer.blob : null;
|
|
944
|
+
try {
|
|
945
|
+
if (!blob && typeof offer?.changeB64 === "string") blob = Uint8Array.from(atob(offer.changeB64), (c) => c.charCodeAt(0));
|
|
946
|
+
} catch {
|
|
947
|
+
}
|
|
948
|
+
if (blob && blob.byteLength) parked.push(blob);
|
|
949
|
+
}
|
|
950
|
+
if (parked.length) {
|
|
951
|
+
footageRef = `refs/heads/parked/offered/${t0.toString(36)}-${Math.floor(Math.random() * 16777215).toString(36)}`;
|
|
952
|
+
const footageDone = span("park offer footage", "cseal", 1, { offers: parked.length });
|
|
953
|
+
try {
|
|
954
|
+
kgit.writeMetaCommit(eng, gitdirOf(ws), {
|
|
955
|
+
parents: [],
|
|
956
|
+
files: parked.map((bytes, i) => ({ path: `${i}.change.usda`, bytes })),
|
|
957
|
+
message: `offered: ${parked.length} intent(s) parked pre-judgment (footage-first)`,
|
|
958
|
+
timeSecs: 0,
|
|
959
|
+
ref: footageRef
|
|
960
|
+
});
|
|
961
|
+
await custodyPush(eng, ws, ledger, { remoteRef: footageRef });
|
|
962
|
+
} catch (e) {
|
|
963
|
+
try {
|
|
964
|
+
kgit.deleteRef(eng, gitdirOf(ws), footageRef);
|
|
965
|
+
} catch {
|
|
966
|
+
}
|
|
967
|
+
throw new Error(`offer footage not durable \u2014 custody unreachable, nothing was folded; retry the batch: ${String(e).slice(0, 300)}`, { cause: e });
|
|
968
|
+
} finally {
|
|
969
|
+
footageDone();
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
939
973
|
for (const offer of Array.isArray(offers) ? offers : []) {
|
|
940
974
|
const cid = typeof offer?.session === "string" && offer.session ? offer.session : "direct";
|
|
941
975
|
const rec = sessions.get(cid) || { session: cid, admitted: [], rejected: [], skipped: [] };
|
|
@@ -1011,10 +1045,13 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1011
1045
|
}
|
|
1012
1046
|
timings.sessions = sessions.size;
|
|
1013
1047
|
timings.intents = admittedTotal;
|
|
1048
|
+
let refusalsParked = true;
|
|
1014
1049
|
if (deadLetters.length) {
|
|
1015
1050
|
try {
|
|
1016
|
-
await materializeRefused(eng, ws, ledger, deadLetters);
|
|
1051
|
+
const m = await materializeRefused(eng, ws, ledger, deadLetters);
|
|
1052
|
+
refusalsParked = m.unparkedSessions.size === 0;
|
|
1017
1053
|
} catch (e) {
|
|
1054
|
+
refusalsParked = false;
|
|
1018
1055
|
log("refused-materialize-failed", { ws, error: String(e).slice(0, 200) });
|
|
1019
1056
|
}
|
|
1020
1057
|
}
|
|
@@ -1023,6 +1060,17 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1023
1060
|
await commitAndPush(eng, ws, ledger);
|
|
1024
1061
|
sealDone();
|
|
1025
1062
|
}
|
|
1063
|
+
if (footageRef && refusalsParked) {
|
|
1064
|
+
try {
|
|
1065
|
+
kgit.deleteRef(eng, gitdirOf(ws), footageRef);
|
|
1066
|
+
} catch {
|
|
1067
|
+
}
|
|
1068
|
+
try {
|
|
1069
|
+
await custodyPush(eng, ws, ledger, { remoteRef: footageRef, del: true });
|
|
1070
|
+
} catch (e) {
|
|
1071
|
+
log("footage-delete-push-failed", { ws, ref: footageRef, error: String(e).slice(0, 200) });
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1026
1074
|
const gitdir = gitdirOf(ws);
|
|
1027
1075
|
const head = kgit.resolveRef(eng, gitdir, BRANCH) ?? main.head;
|
|
1028
1076
|
const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore ?? "", head ?? "") : null;
|
|
@@ -1036,7 +1084,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
1036
1084
|
}
|
|
1037
1085
|
log("admit-intent-offers", { ws, sessions: sessions.size, admitted: admittedTotal, rejected: [...sessions.values()].reduce((n, s) => n + s.rejected.length, 0), resultPack: resultPackB64 ? "inline" : "none" });
|
|
1038
1086
|
const bornPacked = born.length ? packBornChildren(eng, born) : born;
|
|
1039
|
-
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
1087
|
+
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, sealed: true, sealedMain: custodyConfirmedMain(eng, ws), deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
1040
1088
|
}
|
|
1041
1089
|
function intentOfferResidencies(eng, offers) {
|
|
1042
1090
|
const unique = /* @__PURE__ */ new Map();
|
|
@@ -1093,6 +1141,7 @@ async function mountWorkspace(eng, ws, ledger) {
|
|
|
1093
1141
|
throw new Error(`kernel refused restored main ${remoteMain}: ${JSON.stringify(mounted)}`);
|
|
1094
1142
|
}
|
|
1095
1143
|
restored = true;
|
|
1144
|
+
custodyMainOf(eng).set(ws, remoteMain);
|
|
1096
1145
|
verificationVerdict = jsStruct(mounted.verdict);
|
|
1097
1146
|
}
|
|
1098
1147
|
} catch (e) {
|
|
@@ -1245,7 +1294,7 @@ async function custodyFetch(eng, ws, ledger, { remoteRef = "refs/heads/main", lo
|
|
|
1245
1294
|
if (writeRef) kgit.writeRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef), tip);
|
|
1246
1295
|
return tip;
|
|
1247
1296
|
}
|
|
1248
|
-
async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null }) {
|
|
1297
|
+
async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null, ffOnly = false }) {
|
|
1249
1298
|
const headers = ledger.headers || {};
|
|
1250
1299
|
const remoteRefFull = fullRef(remoteRef);
|
|
1251
1300
|
let remote;
|
|
@@ -1261,22 +1310,46 @@ async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del =
|
|
|
1261
1310
|
}
|
|
1262
1311
|
const tgt = newOid || kgit.resolveRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef));
|
|
1263
1312
|
if (!tgt) throw new Error(`custodyPush: local ref ${localRef || remoteRef} unresolved`);
|
|
1264
|
-
if (tgt === oldOid)
|
|
1313
|
+
if (tgt === oldOid) {
|
|
1314
|
+
if (remoteRefFull === fullRef(BRANCH)) custodyMainOf(eng).set(ws, tgt);
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1265
1317
|
let pack = null;
|
|
1266
1318
|
if (!pointer) {
|
|
1267
1319
|
pack = oldOid !== ZERO_OID ? packDelta(eng, ws, oldOid, tgt) : null;
|
|
1320
|
+
if (!pack && ffOnly && oldOid !== ZERO_OID) {
|
|
1321
|
+
throw new Error(`custody ${remoteRefFull} regression refused: remote ${oldOid.slice(0, 12)} is not an ancestor of local ${tgt.slice(0, 12)} \u2014 this engine's view is stale; re-mount from custody instead of forcing`);
|
|
1322
|
+
}
|
|
1268
1323
|
if (!pack) pack = packDelta(eng, ws, "", tgt);
|
|
1269
1324
|
}
|
|
1270
1325
|
const packBytes = pack?.byteLength ?? 0;
|
|
1271
1326
|
try {
|
|
1272
|
-
|
|
1327
|
+
const r = await pushVia(ledger, () => pushPack(ledger.remote, headers, { updates: [{ ref: remoteRefFull, oldOid, newOid: tgt }], pack }));
|
|
1328
|
+
if (remoteRefFull === fullRef(BRANCH)) custodyMainOf(eng).set(ws, tgt);
|
|
1329
|
+
return r;
|
|
1273
1330
|
} catch (error) {
|
|
1274
1331
|
throw new Error(`custody receive-pack push failed for ${remoteRefFull} (${packBytes} pack bytes): ${String(error)}`, { cause: error });
|
|
1275
1332
|
}
|
|
1276
1333
|
}
|
|
1334
|
+
function custodyMainOf(eng) {
|
|
1335
|
+
eng._custodyMain ??= /* @__PURE__ */ new Map();
|
|
1336
|
+
return eng._custodyMain;
|
|
1337
|
+
}
|
|
1338
|
+
function custodyConfirmedMain(eng, ws) {
|
|
1339
|
+
return custodyMainOf(eng).get(ws) ?? null;
|
|
1340
|
+
}
|
|
1341
|
+
function isDirty(eng, ws) {
|
|
1342
|
+
try {
|
|
1343
|
+
const resident = kgit.resolveRef(eng, gitdirOf(ws), BRANCH);
|
|
1344
|
+
if (!resident) return false;
|
|
1345
|
+
return resident !== custodyMainOf(eng).get(ws);
|
|
1346
|
+
} catch {
|
|
1347
|
+
return false;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1277
1350
|
async function commitAndPush(eng, ws, ledger) {
|
|
1278
1351
|
try {
|
|
1279
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main" });
|
|
1352
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", ffOnly: true });
|
|
1280
1353
|
} catch (e) {
|
|
1281
1354
|
unmount(eng, ws);
|
|
1282
1355
|
const cause = e instanceof Error ? e.cause : void 0;
|
|
@@ -1602,6 +1675,80 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
1602
1675
|
_sessionDone();
|
|
1603
1676
|
}
|
|
1604
1677
|
}
|
|
1678
|
+
const offeredRefPrefix = "refs/heads/parked/offered/";
|
|
1679
|
+
const footageConsumed = [];
|
|
1680
|
+
const footageBorn = [], footageBirthOutcomes = [];
|
|
1681
|
+
try {
|
|
1682
|
+
const offeredRefs = Object.entries(await custodyLsRefs(ledger, offeredRefPrefix));
|
|
1683
|
+
for (const [oref, ooid] of offeredRefs) {
|
|
1684
|
+
if (!oref.startsWith(offeredRefPrefix) || !ooid) continue;
|
|
1685
|
+
const fcid = `offered:${oref.slice(offeredRefPrefix.length)}`;
|
|
1686
|
+
const _fDone = _span(`footage ${fcid.slice(0, 24)}`, "csession", 1, { client: fcid });
|
|
1687
|
+
const admitted = [], rejected = [], skipped = [];
|
|
1688
|
+
try {
|
|
1689
|
+
try {
|
|
1690
|
+
await custodyFetch(eng, ws, ledger, { remoteRef: oref, have: kgit.resolveRef(eng, gitdir, BRANCH) });
|
|
1691
|
+
} catch {
|
|
1692
|
+
await custodyFetch(eng, ws, ledger, { remoteRef: oref, have: null });
|
|
1693
|
+
}
|
|
1694
|
+
const main = await mainIntentIds(eng, ws);
|
|
1695
|
+
for (let i = 0; ; i++) {
|
|
1696
|
+
let blob = null;
|
|
1697
|
+
try {
|
|
1698
|
+
blob = kgit.readBlob(eng, gitdir, ooid, `${i}.change.usda`);
|
|
1699
|
+
} catch {
|
|
1700
|
+
blob = null;
|
|
1701
|
+
}
|
|
1702
|
+
if (!blob || !blob.byteLength) break;
|
|
1703
|
+
try {
|
|
1704
|
+
const inspected = kgit.inspectChange(eng, blob);
|
|
1705
|
+
const intentId = inspected.intentId || null;
|
|
1706
|
+
const oid = String(intentId || `${fcid}#${i}`).slice(0, 10);
|
|
1707
|
+
if (!inspected.authored || !inspected.call) {
|
|
1708
|
+
rejected.push({ oid, error: "parked offer is not an authored nominal call" });
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
const { domainPath: dom, directivePath: dirId } = inspected.call;
|
|
1712
|
+
if (receiptFence && dirId && Array.isArray(receiptFence[dom]) && receiptFence[dom].includes(dirId)) {
|
|
1713
|
+
const error = `'${dom}/${dirId}' is a capability RECEIPT \u2014 receipts are executor/owner writes, never open-session writes`;
|
|
1714
|
+
rejected.push({ oid, error, deadLettered: true });
|
|
1715
|
+
deadLetters.push({ intentId, oid, session: fcid, error, blob, domain: dom, directiveId: dirId });
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1718
|
+
if (intentId && main.ids.has(intentId)) {
|
|
1719
|
+
skipped.push({ oid, intent: intentId, alreadyOnMain: true });
|
|
1720
|
+
continue;
|
|
1721
|
+
}
|
|
1722
|
+
const res = offerAdmit(eng, ws, blob, { defer: canDeferProjection });
|
|
1723
|
+
if (res.ok) {
|
|
1724
|
+
if (intentId) main.ids.add(intentId);
|
|
1725
|
+
main.oids.add(res.head);
|
|
1726
|
+
main.head = res.head;
|
|
1727
|
+
admitted.push({ oid, intent: intentId, head: res.head });
|
|
1728
|
+
totalAdmitted += 1;
|
|
1729
|
+
_intents += 1;
|
|
1730
|
+
if (Array.isArray(res.born) && res.born.length) footageBorn.push(...res.born);
|
|
1731
|
+
if (Array.isArray(res.birthOutcomes) && res.birthOutcomes.length) footageBirthOutcomes.push(...res.birthOutcomes);
|
|
1732
|
+
} else {
|
|
1733
|
+
const error = `${String(res.error || "").slice(0, 300)} \u2014 dead-lettered; fix the law (or the payload), then POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
1734
|
+
rejected.push({ oid, error, deadLettered: true });
|
|
1735
|
+
deadLetters.push({ intentId, oid, session: fcid, error, blob, domain: dom, directiveId: dirId });
|
|
1736
|
+
}
|
|
1737
|
+
} catch (e) {
|
|
1738
|
+
rejected.push({ oid: `${fcid}#${i}`.slice(0, 10), error: String(e).slice(0, 200) });
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
footageConsumed.push(oref);
|
|
1742
|
+
results.push({ session: fcid, admitted, rejected, ...skipped.length ? { skipped } : {} });
|
|
1743
|
+
} catch (e) {
|
|
1744
|
+
results.push({ session: fcid, error: String(e).slice(0, 200) });
|
|
1745
|
+
} finally {
|
|
1746
|
+
_fDone({ admitted: admitted.length, rejected: rejected.length });
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
} catch (e) {
|
|
1750
|
+
log("footage-scan-failed", { ws, error: String(e).slice(0, 200) });
|
|
1751
|
+
}
|
|
1605
1752
|
if (canDeferProjection && totalAdmitted) {
|
|
1606
1753
|
const _projDone = _span("projection flush (batch)", "cproject", 1, { admitted: totalAdmitted });
|
|
1607
1754
|
try {
|
|
@@ -1625,7 +1772,8 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
1625
1772
|
const hasCoordination = !!(summaryCtx || placements.length || splits.length || globalsOut.length);
|
|
1626
1773
|
const deferDurability = defer && !hasCoordination;
|
|
1627
1774
|
let _sealed = true;
|
|
1628
|
-
|
|
1775
|
+
const sealNeeded = totalAdmitted > 0 || isDirty(eng, ws);
|
|
1776
|
+
if (sealNeeded && !deferDurability) {
|
|
1629
1777
|
const _sealDone = _span(`seal (batch)`, "cseal", 1, { sessions: consumed.length, admitted: totalAdmitted });
|
|
1630
1778
|
const _s = Date.now();
|
|
1631
1779
|
try {
|
|
@@ -1645,17 +1793,38 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
1645
1793
|
} catch {
|
|
1646
1794
|
}
|
|
1647
1795
|
}
|
|
1796
|
+
for (const oref of footageConsumed) {
|
|
1797
|
+
const fcid = `offered:${oref.slice(offeredRefPrefix.length)}`;
|
|
1798
|
+
if (unparkedSessions.has(fcid)) continue;
|
|
1799
|
+
try {
|
|
1800
|
+
kgit.deleteRef(eng, gitdir, oref);
|
|
1801
|
+
} catch {
|
|
1802
|
+
}
|
|
1803
|
+
try {
|
|
1804
|
+
await custodyPush(eng, ws, ledger, { remoteRef: oref, del: true });
|
|
1805
|
+
} catch {
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1648
1808
|
}
|
|
1649
1809
|
const newMain = kgit.resolveRef(eng, gitdir, BRANCH);
|
|
1650
|
-
log("admit", { ws, sessions: results.length, main: newMain });
|
|
1810
|
+
log("admit", { ws, sessions: results.length, main: newMain, sealed: _sealed, sealedMain: custodyConfirmedMain(eng, ws) });
|
|
1651
1811
|
const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore ?? "", newMain) : null;
|
|
1652
1812
|
const _total = Date.now() - _t0;
|
|
1653
1813
|
const timings = { totalMs: _total, scanMs: _scanMs, fetchMs: _fetchMs, sealMs: _sealMs, gateFoldMs: Math.max(0, _total - _scanMs - _fetchMs - _sealMs), intents: _intents, sessions: results.length, spans: _spans };
|
|
1654
1814
|
return {
|
|
1815
|
+
// SCOREBOARD TRUTH: `main` is the resident fold head (the ack the client converges to);
|
|
1816
|
+
// `sealedMain` is the custody-confirmed head — THE ONLY head the host may advertise/cache
|
|
1817
|
+
// (seated_barrier_and_seal_obligation.md Part 2). `sealed:false` ⇒ the seal obligation is
|
|
1818
|
+
// outstanding and the caller must re-arm the admit alarm (retry) rather than move on.
|
|
1655
1819
|
sessions: results,
|
|
1656
1820
|
main: newMain,
|
|
1821
|
+
sealed: _sealed,
|
|
1822
|
+
sealedMain: custodyConfirmedMain(eng, ws),
|
|
1657
1823
|
deadLetters,
|
|
1658
1824
|
timings,
|
|
1825
|
+
// Footage-replayed `.births()` offers: the born child custody + typed verdicts, for the caller
|
|
1826
|
+
// to persist exactly as the live POST lane does (packed here — the caller holds no engine FS).
|
|
1827
|
+
...footageBorn.length ? { born: packBornChildren(eng, footageBorn), birthOutcomes: footageBirthOutcomes } : {},
|
|
1659
1828
|
...summary ? { summary } : {},
|
|
1660
1829
|
...placements.length ? { placements } : {},
|
|
1661
1830
|
...splits.length ? { splits } : {},
|
package/dist/full-cli.mjs
CHANGED
|
@@ -4979,7 +4979,7 @@ function createGovernanceOffers(ctx) {
|
|
|
4979
4979
|
* `revoked: true` means the subject's leaf was flipped `status:revoked` (remove-wins — a lawful
|
|
4980
4980
|
* re-enroll of the SAME key is refused; mint + enroll a new device key instead).
|
|
4981
4981
|
*/
|
|
4982
|
-
parentSignerEnrollment: async ({ parent, principal, keyHash, publicKey, authToken } = {}) => {
|
|
4982
|
+
parentSignerEnrollment: async ({ parent, principal, keyHash, publicKey, authToken, remote } = {}) => {
|
|
4983
4983
|
if (!parent || typeof parent !== "string") throw new Error("parentSignerEnrollment requires `parent` (the workspace whose chain holds the signer tuple)");
|
|
4984
4984
|
if (!principal || typeof principal !== "string") throw new Error("parentSignerEnrollment requires `principal` (the auth-provider uid)");
|
|
4985
4985
|
const p = canonicalPrincipal(principal);
|
|
@@ -4989,7 +4989,7 @@ function createGovernanceOffers(ctx) {
|
|
|
4989
4989
|
}
|
|
4990
4990
|
const object = signerObjectOf(p);
|
|
4991
4991
|
let rows;
|
|
4992
|
-
if (parent === workspace) {
|
|
4992
|
+
if (parent === workspace && !remote) {
|
|
4993
4993
|
rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
|
|
4994
4994
|
} else {
|
|
4995
4995
|
const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
|
|
@@ -5560,7 +5560,7 @@ async function checkCompat(holon, nomosCompat) {
|
|
|
5560
5560
|
}
|
|
5561
5561
|
return verdict;
|
|
5562
5562
|
}
|
|
5563
|
-
async function connectSingle({ cloud, workspace, clientId, authToken, restoreFrom, onSpan, authorSecret, principal, allowUnborn = false, salvageOnly = false, recover = false, mountInPlace = false, __injectCheckpoint, kernelProvider, fetchImpl, historicSnapshots, onCustodyBreak, watchRebind, openWorkspaceInPlane, __knownKernelCapabilities, __testKRootPublic, __testRootSecret }) {
|
|
5563
|
+
async function connectSingle({ cloud, workspace, clientId, authToken, restoreFrom, onSpan, authorSecret, principal, allowUnborn = false, salvageOnly = false, recover = false, mountInPlace = false, __injectCheckpoint, kernelProvider, fetchImpl, historicSnapshots, onCustodyBreak, onLocalWorkRejected, watchRebind, openWorkspaceInPlane, __knownKernelCapabilities, __testKRootPublic, __testRootSecret }) {
|
|
5564
5564
|
if (salvageOnly) allowUnborn = true;
|
|
5565
5565
|
if (!cloud || !workspace) throw new Error("connect({ cloud, workspace }) required");
|
|
5566
5566
|
const _fetch = typeof fetchImpl === "function" ? fetchImpl : globalThis.fetch;
|
|
@@ -5722,6 +5722,47 @@ ${String(commit).toLowerCase()}`;
|
|
|
5722
5722
|
}
|
|
5723
5723
|
};
|
|
5724
5724
|
const onCustodyBreakOpt = typeof onCustodyBreak === "function" ? onCustodyBreak : null;
|
|
5725
|
+
let localWorkRejectedHook = typeof onLocalWorkRejected === "function" ? onLocalWorkRejected : null;
|
|
5726
|
+
const localWorkRejectedListeners = /* @__PURE__ */ new Set();
|
|
5727
|
+
const refusalIsRetryable = (error) => {
|
|
5728
|
+
try {
|
|
5729
|
+
const d = authzDiagnosisFromRefusal(String(error ?? ""));
|
|
5730
|
+
return d?.code === "nomos.authz.signer_enrollment_missing";
|
|
5731
|
+
} catch {
|
|
5732
|
+
return false;
|
|
5733
|
+
}
|
|
5734
|
+
};
|
|
5735
|
+
const emitLocalWorkRejected = (source, refused, resetTo) => {
|
|
5736
|
+
if (!refused.length) return;
|
|
5737
|
+
const items = refused.map((r) => ({
|
|
5738
|
+
intentId: typeof r.intentId === "string" ? r.intentId : null,
|
|
5739
|
+
oid: typeof r.oid === "string" ? r.oid : null,
|
|
5740
|
+
domain: typeof r.domain === "string" ? r.domain : null,
|
|
5741
|
+
directiveId: typeof r.directiveId === "string" ? r.directiveId : null,
|
|
5742
|
+
error: String(r.error ?? "the law refused this offer").slice(0, 600),
|
|
5743
|
+
retryable: refusalIsRetryable(r.error)
|
|
5744
|
+
}));
|
|
5745
|
+
const event = {
|
|
5746
|
+
workspace,
|
|
5747
|
+
refused: items,
|
|
5748
|
+
parked: true,
|
|
5749
|
+
resetTo,
|
|
5750
|
+
retryable: items.every((i) => i.retryable),
|
|
5751
|
+
source
|
|
5752
|
+
};
|
|
5753
|
+
if (localWorkRejectedHook) {
|
|
5754
|
+
try {
|
|
5755
|
+
localWorkRejectedHook(event);
|
|
5756
|
+
} catch {
|
|
5757
|
+
}
|
|
5758
|
+
}
|
|
5759
|
+
for (const l of [...localWorkRejectedListeners]) {
|
|
5760
|
+
try {
|
|
5761
|
+
l(event);
|
|
5762
|
+
} catch {
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
};
|
|
5725
5766
|
function captureIncarnation(j) {
|
|
5726
5767
|
const inc = j && typeof j.incarnation === "string" && OID40_RE.test(j.incarnation) ? j.incarnation : null;
|
|
5727
5768
|
if (inc !== null) remoteIncarnation = inc;
|
|
@@ -6308,6 +6349,7 @@ ${String(commit).toLowerCase()}`;
|
|
|
6308
6349
|
}
|
|
6309
6350
|
}
|
|
6310
6351
|
}
|
|
6352
|
+
if (deadLettered.length) emitLocalWorkRejected("sync", deadLettered.map((d) => ({ intentId: d.id, error: d.error })), remoteHead);
|
|
6311
6353
|
invalidateInstalledLawMetadata();
|
|
6312
6354
|
nudgeWatches();
|
|
6313
6355
|
return {
|
|
@@ -8620,6 +8662,22 @@ ${String(commit).toLowerCase()}`;
|
|
|
8620
8662
|
if (typeof cb === "function") custodyListeners.add(cb);
|
|
8621
8663
|
return () => custodyListeners.delete(cb);
|
|
8622
8664
|
},
|
|
8665
|
+
/** THE LOCAL-WORK-REJECTED HOOK (settable; connect({onLocalWorkRejected}) is the default) — the
|
|
8666
|
+
* typed "the cloud refused work your device had accepted" lifecycle event. See
|
|
8667
|
+
* `LocalWorkRejectedEvent`: refused intents are already parked + survivors replayed when it
|
|
8668
|
+
* fires; the app's only job is honest UX (retryable ⇒ "queued, will retry"; terminal ⇒
|
|
8669
|
+
* "preserved for review — contact support"). */
|
|
8670
|
+
get onLocalWorkRejected() {
|
|
8671
|
+
return localWorkRejectedHook;
|
|
8672
|
+
},
|
|
8673
|
+
set onLocalWorkRejected(fn) {
|
|
8674
|
+
localWorkRejectedHook = typeof fn === "function" ? fn : null;
|
|
8675
|
+
},
|
|
8676
|
+
/** Subscribe (multi-listener) to LocalWorkRejectedEvents. Returns an unsubscribe fn. */
|
|
8677
|
+
onLocalWorkRejectedEvent: (cb) => {
|
|
8678
|
+
if (typeof cb === "function") localWorkRejectedListeners.add(cb);
|
|
8679
|
+
return () => localWorkRejectedListeners.delete(cb);
|
|
8680
|
+
},
|
|
8623
8681
|
/**
|
|
8624
8682
|
* INTROSPECTION — where this holon sits on the custody spectrum:
|
|
8625
8683
|
* `{ incarnation, localGenesis, remoteIncarnation, syncPosture, pendingLocalIntents, salvagedIntents,
|
|
@@ -10089,6 +10147,10 @@ ${String(commit).toLowerCase()}`;
|
|
|
10089
10147
|
});
|
|
10090
10148
|
_convSpan.end();
|
|
10091
10149
|
if (result && result.custodyBreak) return await resolveCustodyBreakFlow(result.custodyBreak, { operation: "sync" });
|
|
10150
|
+
if (admissionRefusals && admissionRefusals.size) {
|
|
10151
|
+
const refusedEntries = (admission?.sessions || []).flatMap((s) => (s.rejected || []).map((r) => ({ intentId: r.intent, oid: r.oid, error: r.error })));
|
|
10152
|
+
emitLocalWorkRejected("admission", refusedEntries, result && typeof result.remoteMain === "string" ? result.remoteMain : null);
|
|
10153
|
+
}
|
|
10092
10154
|
try {
|
|
10093
10155
|
result.stillAhead = await resolveBranchHead() !== syncedBase;
|
|
10094
10156
|
} catch {
|
|
@@ -10872,7 +10934,14 @@ function routedHolon(coordinator, { cloud, workspace, clientId, authToken, fetch
|
|
|
10872
10934
|
},
|
|
10873
10935
|
set onCustodyBreak(fn) {
|
|
10874
10936
|
coordinator.onCustodyBreak = fn;
|
|
10875
|
-
}
|
|
10937
|
+
},
|
|
10938
|
+
get onLocalWorkRejected() {
|
|
10939
|
+
return coordinator.onLocalWorkRejected;
|
|
10940
|
+
},
|
|
10941
|
+
set onLocalWorkRejected(fn) {
|
|
10942
|
+
coordinator.onLocalWorkRejected = fn;
|
|
10943
|
+
},
|
|
10944
|
+
onLocalWorkRejectedEvent: (cb) => coordinator.onLocalWorkRejectedEvent(cb)
|
|
10876
10945
|
};
|
|
10877
10946
|
}
|
|
10878
10947
|
async function inspectSnapshot(opts) {
|
|
@@ -11804,6 +11873,7 @@ __export(engine_exports, {
|
|
|
11804
11873
|
cryptoUnwrapKey: () => cryptoUnwrapKey,
|
|
11805
11874
|
cryptoWrapKey: () => cryptoWrapKey,
|
|
11806
11875
|
currentLaw: () => currentLaw,
|
|
11876
|
+
custodyConfirmedMain: () => custodyConfirmedMain,
|
|
11807
11877
|
declaredCapabilities: () => declaredCapabilities,
|
|
11808
11878
|
deepVerifyShard: () => deepVerifyShard,
|
|
11809
11879
|
delegationCertSign: () => delegationCertSign,
|
|
@@ -11830,6 +11900,7 @@ __export(engine_exports, {
|
|
|
11830
11900
|
ingestPackAsCustody: () => ingestPackAsCustody,
|
|
11831
11901
|
installedLaw: () => installedLaw,
|
|
11832
11902
|
intentOfferResidencies: () => intentOfferResidencies,
|
|
11903
|
+
isDirty: () => isDirty,
|
|
11833
11904
|
isWarranted: () => isWarranted,
|
|
11834
11905
|
kernelStamp: () => kernelStamp,
|
|
11835
11906
|
kgit: () => kgit,
|
|
@@ -12862,6 +12933,40 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
12862
12933
|
const s0 = Date.now();
|
|
12863
12934
|
return (end = {}) => timings.spans.push({ id: `intent-offer-${t0}-${seq++}`, track: "cloud", name, kind, depth, t0: s0, t1: Date.now(), ...extra, ...end });
|
|
12864
12935
|
};
|
|
12936
|
+
let footageRef = null;
|
|
12937
|
+
{
|
|
12938
|
+
const parked = [];
|
|
12939
|
+
for (const offer of Array.isArray(offers) ? offers : []) {
|
|
12940
|
+
let blob = offer?.blob instanceof Uint8Array ? offer.blob : null;
|
|
12941
|
+
try {
|
|
12942
|
+
if (!blob && typeof offer?.changeB64 === "string") blob = Uint8Array.from(atob(offer.changeB64), (c) => c.charCodeAt(0));
|
|
12943
|
+
} catch {
|
|
12944
|
+
}
|
|
12945
|
+
if (blob && blob.byteLength) parked.push(blob);
|
|
12946
|
+
}
|
|
12947
|
+
if (parked.length) {
|
|
12948
|
+
footageRef = `refs/heads/parked/offered/${t0.toString(36)}-${Math.floor(Math.random() * 16777215).toString(36)}`;
|
|
12949
|
+
const footageDone = span("park offer footage", "cseal", 1, { offers: parked.length });
|
|
12950
|
+
try {
|
|
12951
|
+
kgit.writeMetaCommit(eng, gitdirOf(ws), {
|
|
12952
|
+
parents: [],
|
|
12953
|
+
files: parked.map((bytes, i) => ({ path: `${i}.change.usda`, bytes })),
|
|
12954
|
+
message: `offered: ${parked.length} intent(s) parked pre-judgment (footage-first)`,
|
|
12955
|
+
timeSecs: 0,
|
|
12956
|
+
ref: footageRef
|
|
12957
|
+
});
|
|
12958
|
+
await custodyPush(eng, ws, ledger, { remoteRef: footageRef });
|
|
12959
|
+
} catch (e) {
|
|
12960
|
+
try {
|
|
12961
|
+
kgit.deleteRef(eng, gitdirOf(ws), footageRef);
|
|
12962
|
+
} catch {
|
|
12963
|
+
}
|
|
12964
|
+
throw new Error(`offer footage not durable \u2014 custody unreachable, nothing was folded; retry the batch: ${String(e).slice(0, 300)}`, { cause: e });
|
|
12965
|
+
} finally {
|
|
12966
|
+
footageDone();
|
|
12967
|
+
}
|
|
12968
|
+
}
|
|
12969
|
+
}
|
|
12865
12970
|
for (const offer of Array.isArray(offers) ? offers : []) {
|
|
12866
12971
|
const cid = typeof offer?.session === "string" && offer.session ? offer.session : "direct";
|
|
12867
12972
|
const rec = sessions.get(cid) || { session: cid, admitted: [], rejected: [], skipped: [] };
|
|
@@ -12937,10 +13042,13 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
12937
13042
|
}
|
|
12938
13043
|
timings.sessions = sessions.size;
|
|
12939
13044
|
timings.intents = admittedTotal;
|
|
13045
|
+
let refusalsParked = true;
|
|
12940
13046
|
if (deadLetters.length) {
|
|
12941
13047
|
try {
|
|
12942
|
-
await materializeRefused(eng, ws, ledger, deadLetters);
|
|
13048
|
+
const m = await materializeRefused(eng, ws, ledger, deadLetters);
|
|
13049
|
+
refusalsParked = m.unparkedSessions.size === 0;
|
|
12943
13050
|
} catch (e) {
|
|
13051
|
+
refusalsParked = false;
|
|
12944
13052
|
log("refused-materialize-failed", { ws, error: String(e).slice(0, 200) });
|
|
12945
13053
|
}
|
|
12946
13054
|
}
|
|
@@ -12949,6 +13057,17 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
12949
13057
|
await commitAndPush(eng, ws, ledger);
|
|
12950
13058
|
sealDone();
|
|
12951
13059
|
}
|
|
13060
|
+
if (footageRef && refusalsParked) {
|
|
13061
|
+
try {
|
|
13062
|
+
kgit.deleteRef(eng, gitdirOf(ws), footageRef);
|
|
13063
|
+
} catch {
|
|
13064
|
+
}
|
|
13065
|
+
try {
|
|
13066
|
+
await custodyPush(eng, ws, ledger, { remoteRef: footageRef, del: true });
|
|
13067
|
+
} catch (e) {
|
|
13068
|
+
log("footage-delete-push-failed", { ws, ref: footageRef, error: String(e).slice(0, 200) });
|
|
13069
|
+
}
|
|
13070
|
+
}
|
|
12952
13071
|
const gitdir = gitdirOf(ws);
|
|
12953
13072
|
const head = kgit.resolveRef(eng, gitdir, BRANCH2) ?? main2.head;
|
|
12954
13073
|
const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore ?? "", head ?? "") : null;
|
|
@@ -12962,7 +13081,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
12962
13081
|
}
|
|
12963
13082
|
log("admit-intent-offers", { ws, sessions: sessions.size, admitted: admittedTotal, rejected: [...sessions.values()].reduce((n, s) => n + s.rejected.length, 0), resultPack: resultPackB64 ? "inline" : "none" });
|
|
12964
13083
|
const bornPacked = born.length ? packBornChildren(eng, born) : born;
|
|
12965
|
-
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
13084
|
+
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, sealed: true, sealedMain: custodyConfirmedMain(eng, ws), deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
12966
13085
|
}
|
|
12967
13086
|
function intentOfferResidencies(eng, offers) {
|
|
12968
13087
|
const unique = /* @__PURE__ */ new Map();
|
|
@@ -13094,6 +13213,7 @@ async function mountWorkspace(eng, ws, ledger) {
|
|
|
13094
13213
|
throw new Error(`kernel refused restored main ${remoteMain}: ${JSON.stringify(mounted)}`);
|
|
13095
13214
|
}
|
|
13096
13215
|
restored = true;
|
|
13216
|
+
custodyMainOf(eng).set(ws, remoteMain);
|
|
13097
13217
|
verificationVerdict = jsStruct2(mounted.verdict);
|
|
13098
13218
|
}
|
|
13099
13219
|
} catch (e) {
|
|
@@ -13564,7 +13684,7 @@ async function custodyFetch(eng, ws, ledger, { remoteRef = "refs/heads/main", lo
|
|
|
13564
13684
|
if (writeRef) kgit.writeRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef), tip);
|
|
13565
13685
|
return tip;
|
|
13566
13686
|
}
|
|
13567
|
-
async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null }) {
|
|
13687
|
+
async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del = false, pointer = false, newOid = null, ffOnly = false }) {
|
|
13568
13688
|
const headers = ledger.headers || {};
|
|
13569
13689
|
const remoteRefFull = fullRef(remoteRef);
|
|
13570
13690
|
let remote;
|
|
@@ -13580,22 +13700,46 @@ async function custodyPush(eng, ws, ledger, { localRef = null, remoteRef, del =
|
|
|
13580
13700
|
}
|
|
13581
13701
|
const tgt = newOid || kgit.resolveRef(eng, gitdirOf(ws), fullRef(localRef || remoteRef));
|
|
13582
13702
|
if (!tgt) throw new Error(`custodyPush: local ref ${localRef || remoteRef} unresolved`);
|
|
13583
|
-
if (tgt === oldOid)
|
|
13703
|
+
if (tgt === oldOid) {
|
|
13704
|
+
if (remoteRefFull === fullRef(BRANCH2)) custodyMainOf(eng).set(ws, tgt);
|
|
13705
|
+
return;
|
|
13706
|
+
}
|
|
13584
13707
|
let pack = null;
|
|
13585
13708
|
if (!pointer) {
|
|
13586
13709
|
pack = oldOid !== ZERO_OID2 ? packDelta(eng, ws, oldOid, tgt) : null;
|
|
13710
|
+
if (!pack && ffOnly && oldOid !== ZERO_OID2) {
|
|
13711
|
+
throw new Error(`custody ${remoteRefFull} regression refused: remote ${oldOid.slice(0, 12)} is not an ancestor of local ${tgt.slice(0, 12)} \u2014 this engine's view is stale; re-mount from custody instead of forcing`);
|
|
13712
|
+
}
|
|
13587
13713
|
if (!pack) pack = packDelta(eng, ws, "", tgt);
|
|
13588
13714
|
}
|
|
13589
13715
|
const packBytes = pack?.byteLength ?? 0;
|
|
13590
13716
|
try {
|
|
13591
|
-
|
|
13717
|
+
const r = await pushVia(ledger, () => pushPack2(ledger.remote, headers, { updates: [{ ref: remoteRefFull, oldOid, newOid: tgt }], pack }));
|
|
13718
|
+
if (remoteRefFull === fullRef(BRANCH2)) custodyMainOf(eng).set(ws, tgt);
|
|
13719
|
+
return r;
|
|
13592
13720
|
} catch (error) {
|
|
13593
13721
|
throw new Error(`custody receive-pack push failed for ${remoteRefFull} (${packBytes} pack bytes): ${String(error)}`, { cause: error });
|
|
13594
13722
|
}
|
|
13595
13723
|
}
|
|
13724
|
+
function custodyMainOf(eng) {
|
|
13725
|
+
eng._custodyMain ??= /* @__PURE__ */ new Map();
|
|
13726
|
+
return eng._custodyMain;
|
|
13727
|
+
}
|
|
13728
|
+
function custodyConfirmedMain(eng, ws) {
|
|
13729
|
+
return custodyMainOf(eng).get(ws) ?? null;
|
|
13730
|
+
}
|
|
13731
|
+
function isDirty(eng, ws) {
|
|
13732
|
+
try {
|
|
13733
|
+
const resident = kgit.resolveRef(eng, gitdirOf(ws), BRANCH2);
|
|
13734
|
+
if (!resident) return false;
|
|
13735
|
+
return resident !== custodyMainOf(eng).get(ws);
|
|
13736
|
+
} catch {
|
|
13737
|
+
return false;
|
|
13738
|
+
}
|
|
13739
|
+
}
|
|
13596
13740
|
async function commitAndPush(eng, ws, ledger) {
|
|
13597
13741
|
try {
|
|
13598
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main" });
|
|
13742
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", ffOnly: true });
|
|
13599
13743
|
} catch (e) {
|
|
13600
13744
|
unmount(eng, ws);
|
|
13601
13745
|
const cause = e instanceof Error ? e.cause : void 0;
|
|
@@ -13998,6 +14142,80 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
13998
14142
|
_sessionDone();
|
|
13999
14143
|
}
|
|
14000
14144
|
}
|
|
14145
|
+
const offeredRefPrefix = "refs/heads/parked/offered/";
|
|
14146
|
+
const footageConsumed = [];
|
|
14147
|
+
const footageBorn = [], footageBirthOutcomes = [];
|
|
14148
|
+
try {
|
|
14149
|
+
const offeredRefs = Object.entries(await custodyLsRefs(ledger, offeredRefPrefix));
|
|
14150
|
+
for (const [oref, ooid] of offeredRefs) {
|
|
14151
|
+
if (!oref.startsWith(offeredRefPrefix) || !ooid) continue;
|
|
14152
|
+
const fcid = `offered:${oref.slice(offeredRefPrefix.length)}`;
|
|
14153
|
+
const _fDone = _span(`footage ${fcid.slice(0, 24)}`, "csession", 1, { client: fcid });
|
|
14154
|
+
const admitted = [], rejected = [], skipped = [];
|
|
14155
|
+
try {
|
|
14156
|
+
try {
|
|
14157
|
+
await custodyFetch(eng, ws, ledger, { remoteRef: oref, have: kgit.resolveRef(eng, gitdir, BRANCH2) });
|
|
14158
|
+
} catch {
|
|
14159
|
+
await custodyFetch(eng, ws, ledger, { remoteRef: oref, have: null });
|
|
14160
|
+
}
|
|
14161
|
+
const main2 = await mainIntentIds(eng, ws);
|
|
14162
|
+
for (let i = 0; ; i++) {
|
|
14163
|
+
let blob = null;
|
|
14164
|
+
try {
|
|
14165
|
+
blob = kgit.readBlob(eng, gitdir, ooid, `${i}.change.usda`);
|
|
14166
|
+
} catch {
|
|
14167
|
+
blob = null;
|
|
14168
|
+
}
|
|
14169
|
+
if (!blob || !blob.byteLength) break;
|
|
14170
|
+
try {
|
|
14171
|
+
const inspected = kgit.inspectChange(eng, blob);
|
|
14172
|
+
const intentId = inspected.intentId || null;
|
|
14173
|
+
const oid = String(intentId || `${fcid}#${i}`).slice(0, 10);
|
|
14174
|
+
if (!inspected.authored || !inspected.call) {
|
|
14175
|
+
rejected.push({ oid, error: "parked offer is not an authored nominal call" });
|
|
14176
|
+
continue;
|
|
14177
|
+
}
|
|
14178
|
+
const { domainPath: dom, directivePath: dirId } = inspected.call;
|
|
14179
|
+
if (receiptFence && dirId && Array.isArray(receiptFence[dom]) && receiptFence[dom].includes(dirId)) {
|
|
14180
|
+
const error = `'${dom}/${dirId}' is a capability RECEIPT \u2014 receipts are executor/owner writes, never open-session writes`;
|
|
14181
|
+
rejected.push({ oid, error, deadLettered: true });
|
|
14182
|
+
deadLetters.push({ intentId, oid, session: fcid, error, blob, domain: dom, directiveId: dirId });
|
|
14183
|
+
continue;
|
|
14184
|
+
}
|
|
14185
|
+
if (intentId && main2.ids.has(intentId)) {
|
|
14186
|
+
skipped.push({ oid, intent: intentId, alreadyOnMain: true });
|
|
14187
|
+
continue;
|
|
14188
|
+
}
|
|
14189
|
+
const res = offerAdmit(eng, ws, blob, { defer: canDeferProjection });
|
|
14190
|
+
if (res.ok) {
|
|
14191
|
+
if (intentId) main2.ids.add(intentId);
|
|
14192
|
+
main2.oids.add(res.head);
|
|
14193
|
+
main2.head = res.head;
|
|
14194
|
+
admitted.push({ oid, intent: intentId, head: res.head });
|
|
14195
|
+
totalAdmitted += 1;
|
|
14196
|
+
_intents += 1;
|
|
14197
|
+
if (Array.isArray(res.born) && res.born.length) footageBorn.push(...res.born);
|
|
14198
|
+
if (Array.isArray(res.birthOutcomes) && res.birthOutcomes.length) footageBirthOutcomes.push(...res.birthOutcomes);
|
|
14199
|
+
} else {
|
|
14200
|
+
const error = `${String(res.error || "").slice(0, 300)} \u2014 dead-lettered; fix the law (or the payload), then POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
14201
|
+
rejected.push({ oid, error, deadLettered: true });
|
|
14202
|
+
deadLetters.push({ intentId, oid, session: fcid, error, blob, domain: dom, directiveId: dirId });
|
|
14203
|
+
}
|
|
14204
|
+
} catch (e) {
|
|
14205
|
+
rejected.push({ oid: `${fcid}#${i}`.slice(0, 10), error: String(e).slice(0, 200) });
|
|
14206
|
+
}
|
|
14207
|
+
}
|
|
14208
|
+
footageConsumed.push(oref);
|
|
14209
|
+
results.push({ session: fcid, admitted, rejected, ...skipped.length ? { skipped } : {} });
|
|
14210
|
+
} catch (e) {
|
|
14211
|
+
results.push({ session: fcid, error: String(e).slice(0, 200) });
|
|
14212
|
+
} finally {
|
|
14213
|
+
_fDone({ admitted: admitted.length, rejected: rejected.length });
|
|
14214
|
+
}
|
|
14215
|
+
}
|
|
14216
|
+
} catch (e) {
|
|
14217
|
+
log("footage-scan-failed", { ws, error: String(e).slice(0, 200) });
|
|
14218
|
+
}
|
|
14001
14219
|
if (canDeferProjection && totalAdmitted) {
|
|
14002
14220
|
const _projDone = _span("projection flush (batch)", "cproject", 1, { admitted: totalAdmitted });
|
|
14003
14221
|
try {
|
|
@@ -14021,7 +14239,8 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
14021
14239
|
const hasCoordination = !!(summaryCtx || placements.length || splits.length || globalsOut.length);
|
|
14022
14240
|
const deferDurability = defer && !hasCoordination;
|
|
14023
14241
|
let _sealed = true;
|
|
14024
|
-
|
|
14242
|
+
const sealNeeded = totalAdmitted > 0 || isDirty(eng, ws);
|
|
14243
|
+
if (sealNeeded && !deferDurability) {
|
|
14025
14244
|
const _sealDone = _span(`seal (batch)`, "cseal", 1, { sessions: consumed.length, admitted: totalAdmitted });
|
|
14026
14245
|
const _s = Date.now();
|
|
14027
14246
|
try {
|
|
@@ -14041,17 +14260,38 @@ async function admitAll(eng, ws, ledger, { receiptFence = null, shardRouting = n
|
|
|
14041
14260
|
} catch {
|
|
14042
14261
|
}
|
|
14043
14262
|
}
|
|
14263
|
+
for (const oref of footageConsumed) {
|
|
14264
|
+
const fcid = `offered:${oref.slice(offeredRefPrefix.length)}`;
|
|
14265
|
+
if (unparkedSessions.has(fcid)) continue;
|
|
14266
|
+
try {
|
|
14267
|
+
kgit.deleteRef(eng, gitdir, oref);
|
|
14268
|
+
} catch {
|
|
14269
|
+
}
|
|
14270
|
+
try {
|
|
14271
|
+
await custodyPush(eng, ws, ledger, { remoteRef: oref, del: true });
|
|
14272
|
+
} catch {
|
|
14273
|
+
}
|
|
14274
|
+
}
|
|
14044
14275
|
}
|
|
14045
14276
|
const newMain = kgit.resolveRef(eng, gitdir, BRANCH2);
|
|
14046
|
-
log("admit", { ws, sessions: results.length, main: newMain });
|
|
14277
|
+
log("admit", { ws, sessions: results.length, main: newMain, sealed: _sealed, sealedMain: custodyConfirmedMain(eng, ws) });
|
|
14047
14278
|
const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore ?? "", newMain) : null;
|
|
14048
14279
|
const _total = Date.now() - _t0;
|
|
14049
14280
|
const timings = { totalMs: _total, scanMs: _scanMs, fetchMs: _fetchMs, sealMs: _sealMs, gateFoldMs: Math.max(0, _total - _scanMs - _fetchMs - _sealMs), intents: _intents, sessions: results.length, spans: _spans };
|
|
14050
14281
|
return {
|
|
14282
|
+
// SCOREBOARD TRUTH: `main` is the resident fold head (the ack the client converges to);
|
|
14283
|
+
// `sealedMain` is the custody-confirmed head — THE ONLY head the host may advertise/cache
|
|
14284
|
+
// (seated_barrier_and_seal_obligation.md Part 2). `sealed:false` ⇒ the seal obligation is
|
|
14285
|
+
// outstanding and the caller must re-arm the admit alarm (retry) rather than move on.
|
|
14051
14286
|
sessions: results,
|
|
14052
14287
|
main: newMain,
|
|
14288
|
+
sealed: _sealed,
|
|
14289
|
+
sealedMain: custodyConfirmedMain(eng, ws),
|
|
14053
14290
|
deadLetters,
|
|
14054
14291
|
timings,
|
|
14292
|
+
// Footage-replayed `.births()` offers: the born child custody + typed verdicts, for the caller
|
|
14293
|
+
// to persist exactly as the live POST lane does (packed here — the caller holds no engine FS).
|
|
14294
|
+
...footageBorn.length ? { born: packBornChildren(eng, footageBorn), birthOutcomes: footageBirthOutcomes } : {},
|
|
14055
14295
|
...summary ? { summary } : {},
|
|
14056
14296
|
...placements.length ? { placements } : {},
|
|
14057
14297
|
...splits.length ? { splits } : {},
|
|
@@ -14065,7 +14305,7 @@ async function backupHead(eng, ws, ledger, head) {
|
|
|
14065
14305
|
if (!eng.mounted.has(ws)) return { ok: false, error: "not mounted" };
|
|
14066
14306
|
if (!head) return { ok: false, error: "no head" };
|
|
14067
14307
|
try {
|
|
14068
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", newOid: head });
|
|
14308
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", newOid: head, ffOnly: true });
|
|
14069
14309
|
return { ok: true, head };
|
|
14070
14310
|
} catch (e) {
|
|
14071
14311
|
return { ok: false, error: String(e?.message || e).slice(0, 200), head };
|
|
@@ -14078,7 +14318,7 @@ async function backupToCustody(eng, ws, ledger, { consumed = [] } = {}) {
|
|
|
14078
14318
|
head = kgit.resolveRef(eng, gitdir, BRANCH2);
|
|
14079
14319
|
if (!head) return { ok: false, error: "no local main" };
|
|
14080
14320
|
try {
|
|
14081
|
-
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main" });
|
|
14321
|
+
await custodyPush(eng, ws, ledger, { remoteRef: "refs/heads/main", ffOnly: true });
|
|
14082
14322
|
} catch (e) {
|
|
14083
14323
|
return { ok: false, error: String(e).slice(0, 200), head };
|
|
14084
14324
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "githolon",
|
|
3
|
-
"version": "0.105.
|
|
3
|
+
"version": "0.105.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "githolon — the Nomos developer CLI: Rails-style generators for @githolon/dsl domains + the package compiler. Kernel-independent.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@bjorn3/browser_wasi_shim": "0.4.2",
|
|
32
32
|
"@bufbuild/protobuf": "^2.13.0",
|
|
33
|
-
"@githolon/dsl": "^0.105.
|
|
33
|
+
"@githolon/dsl": "^0.105.5",
|
|
34
34
|
"isomorphic-git": "^1.38.4",
|
|
35
35
|
"tsx": "^4.19.2"
|
|
36
36
|
},
|