@githolon/runtime 0.112.8 → 0.112.12
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/RUNTIME-SOURCES.sha256 +22 -21
- package/dist/nomos-native-runtime.js +330 -106
- package/dist/nomos-runner-web.js +11 -1
- package/dist/nomos-runner-worker.js +551 -230
- package/dist/nomos-runner.js +547 -230
- package/package.json +1 -1
- package/runner/build.ts +1 -0
- package/runner/node-entry.mjs +437 -187
|
@@ -6587,7 +6587,8 @@ var NomosRuntimeComponent = (() => {
|
|
|
6587
6587
|
}
|
|
6588
6588
|
}));
|
|
6589
6589
|
if (response.outcome.case === "failure") {
|
|
6590
|
-
|
|
6590
|
+
throwUnnamedHistoryRequirement(response.outcome.value, mount.workspace);
|
|
6591
|
+
throwKernelFailure(response.outcome.value);
|
|
6591
6592
|
}
|
|
6592
6593
|
if (response.outcome.case !== "outbox") {
|
|
6593
6594
|
throw new Error(`kernel returned '${response.outcome.case || "empty"}' while reading correspondence`);
|
|
@@ -6616,7 +6617,8 @@ var NomosRuntimeComponent = (() => {
|
|
|
6616
6617
|
}
|
|
6617
6618
|
}));
|
|
6618
6619
|
if (response.outcome.case === "failure") {
|
|
6619
|
-
|
|
6620
|
+
throwUnnamedHistoryRequirement(response.outcome.value, mount.workspace);
|
|
6621
|
+
throwKernelFailure(response.outcome.value);
|
|
6620
6622
|
}
|
|
6621
6623
|
if (response.outcome.case !== "outbox") {
|
|
6622
6624
|
throw new Error(
|
|
@@ -9574,19 +9576,19 @@ var NomosRuntimeComponent = (() => {
|
|
|
9574
9576
|
|
|
9575
9577
|
// ../src/runtime/workspace_naming.ts
|
|
9576
9578
|
var WORKSPACE_NAME_SEP = "";
|
|
9577
|
-
var keyedBirthNameOf = (
|
|
9579
|
+
var keyedBirthNameOf = (namespace2, key) => `${namespace2}-${sha256Hex(new TextEncoder().encode(namespace2 + WORKSPACE_NAME_SEP + key)).slice(0, 40)}`;
|
|
9578
9580
|
var RECEIVING_GROUP_NAME_PREFIX = "nomos-rg-";
|
|
9579
9581
|
var receivingGroupNameOf = (principal) => `${RECEIVING_GROUP_NAME_PREFIX}${sha256Hex(new TextEncoder().encode(principal)).slice(0, 40)}`;
|
|
9580
|
-
var isKeyedBirthOf = (
|
|
9582
|
+
var isKeyedBirthOf = (namespace2, workspace) => workspace.startsWith(`${namespace2}-`);
|
|
9581
9583
|
var WORKSPACE_NAME_REQUEST_INVALID = "nomos.runtime.workspace_name_request_invalid";
|
|
9582
9584
|
function resolveWorkspaceName(command) {
|
|
9583
9585
|
switch (command.birth.case) {
|
|
9584
9586
|
case "keyed": {
|
|
9585
|
-
const { namespace, key } = command.birth.value;
|
|
9586
|
-
if (
|
|
9587
|
+
const { namespace: namespace2, key } = command.birth.value;
|
|
9588
|
+
if (namespace2.length === 0 || key.length === 0) {
|
|
9587
9589
|
throw new Error(`${WORKSPACE_NAME_REQUEST_INVALID}: a keyed birth name needs both its namespace and its key`);
|
|
9588
9590
|
}
|
|
9589
|
-
return create(ResolvedWorkspaceNameSchema, { workspace: keyedBirthNameOf(
|
|
9591
|
+
return create(ResolvedWorkspaceNameSchema, { workspace: keyedBirthNameOf(namespace2, key) });
|
|
9590
9592
|
}
|
|
9591
9593
|
case "receivingGroup": {
|
|
9592
9594
|
const { principal } = command.birth.value;
|
|
@@ -11629,6 +11631,132 @@ var NomosRuntimeComponent = (() => {
|
|
|
11629
11631
|
}
|
|
11630
11632
|
};
|
|
11631
11633
|
|
|
11634
|
+
// ../src/runtime/peer_desk_store.ts
|
|
11635
|
+
var recordId = (namespace2, key) => `${namespace2.length}:${namespace2}${key}`;
|
|
11636
|
+
var copy2 = (record) => ({
|
|
11637
|
+
...record,
|
|
11638
|
+
value: record.value.slice()
|
|
11639
|
+
});
|
|
11640
|
+
var MemoryPeerDeskStore = class {
|
|
11641
|
+
#records = /* @__PURE__ */ new Map();
|
|
11642
|
+
list(namespace2) {
|
|
11643
|
+
return [...this.#records.values()].filter((record) => record.namespace === namespace2).sort((left, right) => left.key.localeCompare(right.key)).map(copy2);
|
|
11644
|
+
}
|
|
11645
|
+
compareExchange(namespace2, key, expectedRevision, value) {
|
|
11646
|
+
const id = recordId(namespace2, key);
|
|
11647
|
+
const current = this.#records.get(id);
|
|
11648
|
+
if (current?.revision !== expectedRevision) {
|
|
11649
|
+
throw new Error(
|
|
11650
|
+
`peer desk record '${namespace2}/${key}' changed at revision ${current?.revision ?? "absent"}`
|
|
11651
|
+
);
|
|
11652
|
+
}
|
|
11653
|
+
if (value === void 0) {
|
|
11654
|
+
this.#records.delete(id);
|
|
11655
|
+
return void 0;
|
|
11656
|
+
}
|
|
11657
|
+
const next = Object.freeze({
|
|
11658
|
+
namespace: namespace2,
|
|
11659
|
+
key,
|
|
11660
|
+
revision: (current?.revision ?? 0n) + 1n,
|
|
11661
|
+
value: value.slice()
|
|
11662
|
+
});
|
|
11663
|
+
this.#records.set(id, next);
|
|
11664
|
+
return copy2(next);
|
|
11665
|
+
}
|
|
11666
|
+
};
|
|
11667
|
+
|
|
11668
|
+
// ../src/runtime/custody_receipts.ts
|
|
11669
|
+
var namespace = "nomos.peer-desk.custody-receipts/v1";
|
|
11670
|
+
var encoder = new TextEncoder();
|
|
11671
|
+
var decoder = new TextDecoder();
|
|
11672
|
+
var MAX_BASES = 256;
|
|
11673
|
+
var MAX_RECEIPTS = 4096;
|
|
11674
|
+
var CustodyReceipts = class {
|
|
11675
|
+
#store;
|
|
11676
|
+
#records = /* @__PURE__ */ new Map();
|
|
11677
|
+
#journals = /* @__PURE__ */ new Map();
|
|
11678
|
+
#receipts = /* @__PURE__ */ new Map();
|
|
11679
|
+
constructor(store = new MemoryPeerDeskStore()) {
|
|
11680
|
+
this.#store = store;
|
|
11681
|
+
for (const record of store.list(namespace)) {
|
|
11682
|
+
this.#records.set(record.key, record);
|
|
11683
|
+
try {
|
|
11684
|
+
if (record.key.startsWith("receipt:")) {
|
|
11685
|
+
const newline = record.value.indexOf(10);
|
|
11686
|
+
if (newline < 0) continue;
|
|
11687
|
+
const receipt = fromBinary(CustodyIntentAdmissionSchema, record.value.subarray(newline + 1));
|
|
11688
|
+
const header2 = JSON.parse(decoder.decode(record.value.subarray(0, newline)));
|
|
11689
|
+
if (receipt.outcome.case === "admitted" && typeof header2.generation === "string" && typeof header2.head === "string") this.#receipts.set(record.key, { ...header2, receipt });
|
|
11690
|
+
continue;
|
|
11691
|
+
}
|
|
11692
|
+
if (!record.key.startsWith("head:")) continue;
|
|
11693
|
+
const value = JSON.parse(decoder.decode(record.value));
|
|
11694
|
+
if (typeof value.head !== "string" || typeof value.generation !== "string" || !Array.isArray(value.bases) || !Array.isArray(value.keys) || value.bases.length > MAX_BASES || value.keys.length > MAX_RECEIPTS) continue;
|
|
11695
|
+
if (!value.bases.every((base) => typeof base === "string") || !value.keys.every((key) => typeof key === "string")) continue;
|
|
11696
|
+
this.#journals.set(record.key.slice(5), value);
|
|
11697
|
+
} catch {
|
|
11698
|
+
}
|
|
11699
|
+
}
|
|
11700
|
+
}
|
|
11701
|
+
covers(workspace, current, base) {
|
|
11702
|
+
const value = this.#journals.get(workspace);
|
|
11703
|
+
return value?.head === current && value.bases.includes(base);
|
|
11704
|
+
}
|
|
11705
|
+
receipt(workspace, current, change) {
|
|
11706
|
+
const value = this.#journals.get(workspace);
|
|
11707
|
+
if (value?.head !== current) return void 0;
|
|
11708
|
+
const stored = this.#receipts.get(`receipt:${workspace}:${sha256Hex(change)}`);
|
|
11709
|
+
if (stored?.generation !== value.generation) return void 0;
|
|
11710
|
+
if (stored.head !== value.head && !value.bases.includes(stored.head)) return void 0;
|
|
11711
|
+
return fromBinary(CustodyIntentAdmissionSchema, toBinary(CustodyIntentAdmissionSchema, stored.receipt));
|
|
11712
|
+
}
|
|
11713
|
+
record(workspace, before, after, receipts) {
|
|
11714
|
+
const old = this.#journals.get(workspace);
|
|
11715
|
+
const journalKey = `head:${workspace}`;
|
|
11716
|
+
const value = old?.head === before ? { ...old, head: after, bases: [...old.bases], keys: [...old.keys] } : { head: after, bases: [], keys: [], generation: String((this.#records.get(journalKey)?.revision ?? 0n) + 1n) };
|
|
11717
|
+
if (before && before !== after) value.bases.push(before);
|
|
11718
|
+
value.bases = [...new Set(value.bases)].slice(-MAX_BASES);
|
|
11719
|
+
const keys = new Set(value.keys);
|
|
11720
|
+
const discarded = new Set(old?.generation !== value.generation ? old?.keys : []);
|
|
11721
|
+
for (const { change, receipt } of receipts) {
|
|
11722
|
+
if (receipt.outcome.case !== "admitted") continue;
|
|
11723
|
+
const key = `receipt:${workspace}:${sha256Hex(change)}`;
|
|
11724
|
+
keys.delete(key);
|
|
11725
|
+
keys.add(key);
|
|
11726
|
+
discarded.delete(key);
|
|
11727
|
+
const header2 = encoder.encode(`${JSON.stringify({ generation: value.generation, head: after })}
|
|
11728
|
+
`);
|
|
11729
|
+
const body = toBinary(CustodyIntentAdmissionSchema, receipt);
|
|
11730
|
+
const bytes = new Uint8Array(header2.length + body.length);
|
|
11731
|
+
bytes.set(header2);
|
|
11732
|
+
bytes.set(body, header2.length);
|
|
11733
|
+
const record2 = this.#store.compareExchange(namespace, key, this.#records.get(key)?.revision, bytes);
|
|
11734
|
+
if (record2) this.#records.set(key, record2);
|
|
11735
|
+
this.#receipts.set(key, {
|
|
11736
|
+
generation: value.generation,
|
|
11737
|
+
head: after,
|
|
11738
|
+
receipt: fromBinary(CustodyIntentAdmissionSchema, body)
|
|
11739
|
+
});
|
|
11740
|
+
}
|
|
11741
|
+
const ordered = [...keys];
|
|
11742
|
+
for (const key of ordered.slice(0, -MAX_RECEIPTS)) discarded.add(key);
|
|
11743
|
+
value.keys = ordered.slice(-MAX_RECEIPTS);
|
|
11744
|
+
for (const key of discarded) {
|
|
11745
|
+
this.#store.compareExchange(namespace, key, this.#records.get(key)?.revision, void 0);
|
|
11746
|
+
this.#records.delete(key);
|
|
11747
|
+
this.#receipts.delete(key);
|
|
11748
|
+
}
|
|
11749
|
+
const record = this.#store.compareExchange(
|
|
11750
|
+
namespace,
|
|
11751
|
+
journalKey,
|
|
11752
|
+
this.#records.get(journalKey)?.revision,
|
|
11753
|
+
encoder.encode(JSON.stringify(value))
|
|
11754
|
+
);
|
|
11755
|
+
if (record) this.#records.set(journalKey, record);
|
|
11756
|
+
this.#journals.set(workspace, value);
|
|
11757
|
+
}
|
|
11758
|
+
};
|
|
11759
|
+
|
|
11632
11760
|
// ../src/runtime/custodian_placement.ts
|
|
11633
11761
|
var CustodianPlacement = class {
|
|
11634
11762
|
#kernel;
|
|
@@ -11729,14 +11857,16 @@ var NomosRuntimeComponent = (() => {
|
|
|
11729
11857
|
var CustodyAdmissionDesk = class {
|
|
11730
11858
|
#kernel;
|
|
11731
11859
|
#custody;
|
|
11732
|
-
|
|
11860
|
+
#receipts;
|
|
11861
|
+
constructor(kernel, custody, receipts = new CustodyReceipts()) {
|
|
11733
11862
|
this.#kernel = kernel;
|
|
11734
11863
|
this.#custody = custody;
|
|
11864
|
+
this.#receipts = receipts;
|
|
11735
11865
|
}
|
|
11736
11866
|
admit(request, command) {
|
|
11737
|
-
const
|
|
11738
|
-
if (!
|
|
11739
|
-
const mount = this.#custody.
|
|
11867
|
+
const workspace = request.target?.workspace;
|
|
11868
|
+
if (!workspace) throw new Error("custody admission requires an addressed workspace");
|
|
11869
|
+
const mount = this.#custody.mountForWorkspace(workspace);
|
|
11740
11870
|
if (command.evidencePack.byteLength > 0) {
|
|
11741
11871
|
this.#kernel.applyPack(mount, request.requestId, command.evidencePack);
|
|
11742
11872
|
}
|
|
@@ -11747,21 +11877,42 @@ var NomosRuntimeComponent = (() => {
|
|
|
11747
11877
|
const births = [];
|
|
11748
11878
|
const admittedBase = this.#kernel.head(mount, request.requestId) ?? "";
|
|
11749
11879
|
if (command.fastForwardOnly && offers.length > 0 && (command.baseHead ?? "") !== admittedBase) {
|
|
11880
|
+
for (const offer of offers) {
|
|
11881
|
+
const receipt = this.#receipts.receipt(mount.workspace, admittedBase, offer.changeUsda);
|
|
11882
|
+
if (!receipt) continue;
|
|
11883
|
+
receipt.commitOid = offer.commitOid;
|
|
11884
|
+
const records = sessions.get(offer.session) ?? [];
|
|
11885
|
+
records.push(receipt);
|
|
11886
|
+
sessions.set(offer.session, records);
|
|
11887
|
+
}
|
|
11888
|
+
let delta = custodyReturnDelta(
|
|
11889
|
+
this.#kernel,
|
|
11890
|
+
mount,
|
|
11891
|
+
request.requestId,
|
|
11892
|
+
command.baseHead,
|
|
11893
|
+
admittedBase,
|
|
11894
|
+
admittedBase,
|
|
11895
|
+
command.observedHead
|
|
11896
|
+
);
|
|
11897
|
+
if (command.baseHead && command.observedHead !== admittedBase && this.#receipts.covers(mount.workspace, admittedBase, command.baseHead)) {
|
|
11898
|
+
try {
|
|
11899
|
+
delta = {
|
|
11900
|
+
resultBase: command.baseHead,
|
|
11901
|
+
resultPack: this.#kernel.packDelta(mount, request.requestId, admittedBase, command.baseHead),
|
|
11902
|
+
recoveryRequired: false
|
|
11903
|
+
};
|
|
11904
|
+
} catch {
|
|
11905
|
+
}
|
|
11906
|
+
}
|
|
11750
11907
|
return create(CustodyAdmissionSchema, {
|
|
11751
11908
|
main: admittedBase,
|
|
11752
|
-
...
|
|
11753
|
-
|
|
11754
|
-
mount,
|
|
11755
|
-
request.requestId,
|
|
11756
|
-
command.baseHead,
|
|
11757
|
-
admittedBase,
|
|
11758
|
-
admittedBase,
|
|
11759
|
-
command.observedHead
|
|
11760
|
-
)
|
|
11909
|
+
sessions: [...sessions].map(([session, intents]) => create(CustodySessionAdmissionSchema, { session, intents })),
|
|
11910
|
+
...delta
|
|
11761
11911
|
});
|
|
11762
11912
|
}
|
|
11763
11913
|
let main = admittedBase;
|
|
11764
11914
|
const heldSessions = /* @__PURE__ */ new Map();
|
|
11915
|
+
const receipts = [];
|
|
11765
11916
|
for (const offer of offers) {
|
|
11766
11917
|
const heldBehind = heldSessions.get(offer.session);
|
|
11767
11918
|
const verdict = heldBehind === void 0 ? this.#offer(request, mount, offer) : create(OfferResponseSchema, { outcome: { case: "blockedOnDependency", value: {
|
|
@@ -11771,7 +11922,9 @@ var NomosRuntimeComponent = (() => {
|
|
|
11771
11922
|
heldSessions.set(offer.session, verdict.outcome.value.offerId || offer.commitOid);
|
|
11772
11923
|
}
|
|
11773
11924
|
const records = sessions.get(offer.session) ?? [];
|
|
11774
|
-
|
|
11925
|
+
const receipt = this.#record(offer, verdict);
|
|
11926
|
+
records.push(receipt);
|
|
11927
|
+
receipts.push({ change: offer.changeUsda, receipt });
|
|
11775
11928
|
sessions.set(offer.session, records);
|
|
11776
11929
|
if (verdict.outcome.case === "admitted") {
|
|
11777
11930
|
main = verdict.outcome.value.head;
|
|
@@ -11787,6 +11940,9 @@ var NomosRuntimeComponent = (() => {
|
|
|
11787
11940
|
}
|
|
11788
11941
|
}
|
|
11789
11942
|
}
|
|
11943
|
+
if (receipts.some((entry) => entry.receipt.outcome.case === "admitted")) {
|
|
11944
|
+
this.#receipts.record(mount.workspace, admittedBase, main, receipts);
|
|
11945
|
+
}
|
|
11790
11946
|
return create(CustodyAdmissionSchema, {
|
|
11791
11947
|
main,
|
|
11792
11948
|
sessions: [...sessions].map(
|
|
@@ -14745,8 +14901,8 @@ var NomosRuntimeComponent = (() => {
|
|
|
14745
14901
|
|
|
14746
14902
|
// ../src/runtime/preserved_copies_desk.ts
|
|
14747
14903
|
var PRESERVED_COPIES_NAMESPACE = "nomos.peer-desk.preserved-local-copies/v1";
|
|
14748
|
-
var
|
|
14749
|
-
var
|
|
14904
|
+
var encoder2 = new TextEncoder();
|
|
14905
|
+
var decoder2 = new TextDecoder();
|
|
14750
14906
|
var PreservedCopiesDesk = class {
|
|
14751
14907
|
#store;
|
|
14752
14908
|
constructor(store) {
|
|
@@ -14755,7 +14911,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
14755
14911
|
list(workspace) {
|
|
14756
14912
|
const record = this.#store.list(PRESERVED_COPIES_NAMESPACE).find((entry) => entry.key === workspace);
|
|
14757
14913
|
if (!record) return [];
|
|
14758
|
-
const values = JSON.parse(
|
|
14914
|
+
const values = JSON.parse(decoder2.decode(record.value));
|
|
14759
14915
|
if (!Array.isArray(values)) {
|
|
14760
14916
|
throw new Error(`corrupt preserved-copy record for '${workspace}' at revision ${record.revision}`);
|
|
14761
14917
|
}
|
|
@@ -14769,7 +14925,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
14769
14925
|
PRESERVED_COPIES_NAMESPACE,
|
|
14770
14926
|
copy3.workspace,
|
|
14771
14927
|
current?.revision,
|
|
14772
|
-
|
|
14928
|
+
encoder2.encode(`[${next.map((entry) => toJsonString(PreservedLocalCopySchema, entry)).join(",")}]`)
|
|
14773
14929
|
);
|
|
14774
14930
|
if (!stored) throw new Error(`preserved copy of '${copy3.workspace}' was not recorded`);
|
|
14775
14931
|
}
|
|
@@ -14810,9 +14966,9 @@ var NomosRuntimeComponent = (() => {
|
|
|
14810
14966
|
]);
|
|
14811
14967
|
var SEAT_PREFIX = "nomos-office-seat/v1:";
|
|
14812
14968
|
var SEAT_DIGEST_HEX = 64;
|
|
14813
|
-
var
|
|
14814
|
-
var
|
|
14815
|
-
var header = (digest) =>
|
|
14969
|
+
var encoder3 = new TextEncoder();
|
|
14970
|
+
var decoder3 = new TextDecoder();
|
|
14971
|
+
var header = (digest) => encoder3.encode(`${SEAT_PREFIX}${digest}
|
|
14816
14972
|
`);
|
|
14817
14973
|
var QuarantineReason = Object.freeze({
|
|
14818
14974
|
/** Another office's seat: a copied state directory, or a store lifted from another peer. */
|
|
@@ -14823,7 +14979,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
14823
14979
|
function readSeal(value) {
|
|
14824
14980
|
const headerLength = SEAT_PREFIX.length + SEAT_DIGEST_HEX + 1;
|
|
14825
14981
|
if (value.byteLength < headerLength) return void 0;
|
|
14826
|
-
const text =
|
|
14982
|
+
const text = decoder3.decode(value.subarray(0, headerLength));
|
|
14827
14983
|
if (!text.startsWith(SEAT_PREFIX) || !text.endsWith("\n")) return void 0;
|
|
14828
14984
|
const seat = text.slice(SEAT_PREFIX.length, headerLength - 1);
|
|
14829
14985
|
if (!/^[0-9a-f]{64}$/.test(seat)) return void 0;
|
|
@@ -14847,44 +15003,44 @@ var NomosRuntimeComponent = (() => {
|
|
|
14847
15003
|
this.#seat = seat;
|
|
14848
15004
|
this.#report = report;
|
|
14849
15005
|
}
|
|
14850
|
-
list(
|
|
14851
|
-
if (LOCAL_ONLY_NAMESPACES.has(
|
|
15006
|
+
list(namespace2) {
|
|
15007
|
+
if (LOCAL_ONLY_NAMESPACES.has(namespace2)) return this.#inner.list(namespace2);
|
|
14852
15008
|
const kept = [];
|
|
14853
|
-
for (const record of this.#inner.list(
|
|
15009
|
+
for (const record of this.#inner.list(namespace2)) {
|
|
14854
15010
|
const sealed = readSeal(record.value);
|
|
14855
15011
|
if (sealed?.seat === this.#seat.digest) {
|
|
14856
15012
|
kept.push({ ...record, value: sealed.value.slice() });
|
|
14857
15013
|
continue;
|
|
14858
15014
|
}
|
|
14859
|
-
this.#quarantine(
|
|
15015
|
+
this.#quarantine(namespace2, record, sealed?.seat);
|
|
14860
15016
|
}
|
|
14861
15017
|
return kept;
|
|
14862
15018
|
}
|
|
14863
|
-
compareExchange(
|
|
14864
|
-
if (LOCAL_ONLY_NAMESPACES.has(
|
|
14865
|
-
return this.#inner.compareExchange(
|
|
15019
|
+
compareExchange(namespace2, key, expectedRevision, value) {
|
|
15020
|
+
if (LOCAL_ONLY_NAMESPACES.has(namespace2)) {
|
|
15021
|
+
return this.#inner.compareExchange(namespace2, key, expectedRevision, value);
|
|
14866
15022
|
}
|
|
14867
15023
|
const stored = this.#inner.compareExchange(
|
|
14868
|
-
|
|
15024
|
+
namespace2,
|
|
14869
15025
|
key,
|
|
14870
15026
|
expectedRevision,
|
|
14871
15027
|
value === void 0 ? void 0 : seal(this.#seat.digest, value)
|
|
14872
15028
|
);
|
|
14873
15029
|
if (stored === void 0) return void 0;
|
|
14874
15030
|
const sealed = readSeal(stored.value);
|
|
14875
|
-
if (!sealed) throw new Error(`peer desk record '${
|
|
15031
|
+
if (!sealed) throw new Error(`peer desk record '${namespace2}/${key}' lost its office seat`);
|
|
14876
15032
|
return { ...stored, value: sealed.value.slice() };
|
|
14877
15033
|
}
|
|
14878
15034
|
/** Preserve the foreign record under the quarantine namespace, then free the slot. */
|
|
14879
|
-
#quarantine(
|
|
14880
|
-
const key = `${
|
|
15035
|
+
#quarantine(namespace2, record, recordedSeat) {
|
|
15036
|
+
const key = `${namespace2}\0${record.key}\0${record.revision}`;
|
|
14881
15037
|
try {
|
|
14882
15038
|
this.#inner.compareExchange(QUARANTINED_BINDINGS_NAMESPACE, key, void 0, record.value);
|
|
14883
15039
|
} catch {
|
|
14884
15040
|
}
|
|
14885
|
-
this.#inner.compareExchange(
|
|
15041
|
+
this.#inner.compareExchange(namespace2, record.key, record.revision, void 0);
|
|
14886
15042
|
this.#report(create(QuarantinedBindingSchema, {
|
|
14887
|
-
namespace,
|
|
15043
|
+
namespace: namespace2,
|
|
14888
15044
|
key: record.key,
|
|
14889
15045
|
reason: recordedSeat === void 0 ? QuarantineReason.Unseated : QuarantineReason.ForeignSeat,
|
|
14890
15046
|
recordedSeat: recordedSeat ?? "",
|
|
@@ -14934,6 +15090,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
14934
15090
|
const undiscovered = /* @__PURE__ */ new Set();
|
|
14935
15091
|
for (const restored of this.#follows.recover()) {
|
|
14936
15092
|
following.set(restored.workspace, restored.delayMillis);
|
|
15093
|
+
followed.add(restored.workspace);
|
|
14937
15094
|
}
|
|
14938
15095
|
if (!this.#bootstrapped) {
|
|
14939
15096
|
this.#bootstrapped = true;
|
|
@@ -14971,6 +15128,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
14971
15128
|
stopped.delete(workspace);
|
|
14972
15129
|
} else if (reconciliation.changed) {
|
|
14973
15130
|
following.delete(workspace);
|
|
15131
|
+
followed.delete(workspace);
|
|
14974
15132
|
stopped.add(workspace);
|
|
14975
15133
|
}
|
|
14976
15134
|
} catch (error) {
|
|
@@ -15299,7 +15457,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
15299
15457
|
wasResident: this.kernel.isResident(binding.workspace) !== false
|
|
15300
15458
|
};
|
|
15301
15459
|
this.#links.set(binding.workspace, link);
|
|
15302
|
-
if (link.wasResident) this.#open(link);
|
|
15460
|
+
if (!link.publisher || link.wasResident) this.#open(link);
|
|
15303
15461
|
}
|
|
15304
15462
|
changed(workspace) {
|
|
15305
15463
|
const link = this.#links.get(workspace);
|
|
@@ -15326,6 +15484,9 @@ var NomosRuntimeComponent = (() => {
|
|
|
15326
15484
|
this.#effect(link, { case: "send", value: bytes });
|
|
15327
15485
|
}
|
|
15328
15486
|
export(binding, base, requestId) {
|
|
15487
|
+
if (this.kernel.isResident(binding.workspace) === false) {
|
|
15488
|
+
return create(CustodyOfferBatchRequestSchema, { protocolVersion: 2 });
|
|
15489
|
+
}
|
|
15329
15490
|
const mount = workspaceMount(binding.workspace);
|
|
15330
15491
|
const head = this.kernel.head(mount, requestId);
|
|
15331
15492
|
if (!base || !head || base === head) return create(CustodyOfferBatchRequestSchema, { protocolVersion: 2 });
|
|
@@ -15386,6 +15547,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
15386
15547
|
}
|
|
15387
15548
|
if (frame.message.case === "frontier") {
|
|
15388
15549
|
this.#announced(link, frame.message.value.head);
|
|
15550
|
+
if (this.kernel.isResident(link.binding.workspace) === false) return;
|
|
15389
15551
|
if (!frame.message.value.response) {
|
|
15390
15552
|
this.#send(link, { case: "frontier", value: {
|
|
15391
15553
|
head: this.kernel.head(workspaceMount(link.binding.workspace), ++this.#requestId) ?? "",
|
|
@@ -15402,6 +15564,10 @@ var NomosRuntimeComponent = (() => {
|
|
|
15402
15564
|
if (frame.message.case !== "offers") return;
|
|
15403
15565
|
const batch = frame.message.value;
|
|
15404
15566
|
if (batch.protocolVersion !== 2 || !batch.requestId || batch.source.case !== "inline" || !batch.source.value.offers.length) return;
|
|
15567
|
+
if (this.kernel.isResident(link.binding.workspace) === false) {
|
|
15568
|
+
this.remoteAdvanced?.(link.binding.workspace);
|
|
15569
|
+
return;
|
|
15570
|
+
}
|
|
15405
15571
|
if ([...this.#pending.values()].some((pending) => pending.link === link && pending.bytes.length === bytes.length && pending.bytes.every((byte, index) => byte === bytes[index]))) return;
|
|
15406
15572
|
if (this.#pending.size >= 32) return;
|
|
15407
15573
|
this.#pending.set(request.requestId, { link, bytes });
|
|
@@ -15409,7 +15575,16 @@ var NomosRuntimeComponent = (() => {
|
|
|
15409
15575
|
protocolVersion: 2,
|
|
15410
15576
|
requestId: request.requestId,
|
|
15411
15577
|
target: { workspace: link.binding.workspace, session: link.binding.replicaId },
|
|
15412
|
-
|
|
15578
|
+
// HTTP sender reconciliation controls are not part of a live proposal.
|
|
15579
|
+
// Keeping fastForwardOnly while removing baseHead silently skips every
|
|
15580
|
+
// offer against a nonempty local head. The Kernel judges sealed causality;
|
|
15581
|
+
// live receivers neither ask for a return archive nor confirm the sender.
|
|
15582
|
+
command: { case: "admitCustodyOffers", value: create(CustodyOfferBatchRequestSchema, {
|
|
15583
|
+
...batch,
|
|
15584
|
+
baseHead: void 0,
|
|
15585
|
+
observedHead: void 0,
|
|
15586
|
+
fastForwardOnly: false
|
|
15587
|
+
}) }
|
|
15413
15588
|
});
|
|
15414
15589
|
}
|
|
15415
15590
|
/** Upstream news is a frontier this replica has NEVER seen: neither its own head nor the
|
|
@@ -15418,6 +15593,10 @@ var NomosRuntimeComponent = (() => {
|
|
|
15418
15593
|
#announced(link, head) {
|
|
15419
15594
|
if (!head || link.lastAnnounced === head) return;
|
|
15420
15595
|
link.lastAnnounced = head;
|
|
15596
|
+
if (this.kernel.isResident(link.binding.workspace) === false) {
|
|
15597
|
+
this.remoteAdvanced?.(link.binding.workspace);
|
|
15598
|
+
return;
|
|
15599
|
+
}
|
|
15421
15600
|
const mount = workspaceMount(link.binding.workspace);
|
|
15422
15601
|
if (head === this.kernel.head(mount, ++this.#requestId) || head === this.kernel.resolveRef(mount, ++this.#requestId, "refs/remotes/nomos/main")) return;
|
|
15423
15602
|
this.remoteAdvanced?.(link.binding.workspace);
|
|
@@ -15427,6 +15606,10 @@ var NomosRuntimeComponent = (() => {
|
|
|
15427
15606
|
#placementAnnounced(link, frontier) {
|
|
15428
15607
|
if (!frontier || link.lastPlacementAnnounced === frontier) return;
|
|
15429
15608
|
link.lastPlacementAnnounced = frontier;
|
|
15609
|
+
if (this.kernel.isResident(link.binding.workspace) === false) {
|
|
15610
|
+
this.placementAdvanced?.(link.binding.workspace);
|
|
15611
|
+
return;
|
|
15612
|
+
}
|
|
15430
15613
|
const mount = workspaceMount(link.binding.workspace);
|
|
15431
15614
|
if (frontier === this.kernel.resolveRef(mount, ++this.#requestId, PLACEMENT_REF2)) return;
|
|
15432
15615
|
this.placementAdvanced?.(link.binding.workspace);
|
|
@@ -15443,11 +15626,13 @@ var NomosRuntimeComponent = (() => {
|
|
|
15443
15626
|
disconnect(workspace) {
|
|
15444
15627
|
const link = this.#links.get(workspace);
|
|
15445
15628
|
if (!link) return;
|
|
15629
|
+
if (link.state === "open") this.linkClosed?.(workspace);
|
|
15446
15630
|
this.#effect(link, { case: "close", value: true });
|
|
15447
15631
|
this.#links.delete(workspace);
|
|
15448
15632
|
for (const [id, pending] of this.#pending) if (pending.link === link) this.#pending.delete(id);
|
|
15449
15633
|
}
|
|
15450
15634
|
#hello(link) {
|
|
15635
|
+
if (this.kernel.isResident(link.binding.workspace) === false) return;
|
|
15451
15636
|
const head = this.kernel.head(workspaceMount(link.binding.workspace), ++this.#requestId);
|
|
15452
15637
|
this.#send(link, { case: "frontier", value: { head: head ?? "" } });
|
|
15453
15638
|
}
|
|
@@ -15455,19 +15640,20 @@ var NomosRuntimeComponent = (() => {
|
|
|
15455
15640
|
const now = this.clock.monotonicNanoseconds();
|
|
15456
15641
|
let wake;
|
|
15457
15642
|
for (const link of this.#links.values()) {
|
|
15458
|
-
|
|
15643
|
+
const resident = this.kernel.isResident(link.binding.workspace) !== false;
|
|
15644
|
+
if (link.publisher && !resident) {
|
|
15459
15645
|
if (link.wasResident) this.disconnect(link.binding.workspace);
|
|
15460
15646
|
else wake = wake === void 0 || wake > 250n ? 250n : wake;
|
|
15461
15647
|
continue;
|
|
15462
15648
|
}
|
|
15463
|
-
link.wasResident = true;
|
|
15649
|
+
if (resident) link.wasResident = true;
|
|
15464
15650
|
if (link.state === "opening" && now >= link.due) {
|
|
15465
15651
|
this.#effect(link, { case: "close", value: true });
|
|
15466
15652
|
link.state = "closed";
|
|
15467
15653
|
}
|
|
15468
15654
|
if (link.state === "closed" && now >= link.due) this.#open(link);
|
|
15469
15655
|
if (link.state === "open") {
|
|
15470
|
-
if (link.dirty) {
|
|
15656
|
+
if (link.dirty && resident) {
|
|
15471
15657
|
link.dirty = false;
|
|
15472
15658
|
try {
|
|
15473
15659
|
link.published ??= link.publisher ? this.kernel.head(workspaceMount(link.binding.workspace), ++this.#requestId) : this.kernel.resolveRef(workspaceMount(link.binding.workspace), ++this.#requestId, "refs/remotes/nomos/main");
|
|
@@ -15486,8 +15672,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
15486
15672
|
return wake;
|
|
15487
15673
|
}
|
|
15488
15674
|
close() {
|
|
15489
|
-
for (const
|
|
15490
|
-
this.#links.clear();
|
|
15675
|
+
for (const workspace of [...this.#links.keys()]) this.disconnect(workspace);
|
|
15491
15676
|
this.#pending.clear();
|
|
15492
15677
|
}
|
|
15493
15678
|
};
|
|
@@ -15616,9 +15801,9 @@ var NomosRuntimeComponent = (() => {
|
|
|
15616
15801
|
command.namespace === void 0 ? {} : { "custody.children_namespace": command.namespace },
|
|
15617
15802
|
() => this.#kernel.childWorkspaces(mount, request.requestId)
|
|
15618
15803
|
);
|
|
15619
|
-
const
|
|
15620
|
-
const selected =
|
|
15621
|
-
(child) => child.status === ChildWorkspaceLifecycleStatus.ACTIVE && isKeyedBirthOf(
|
|
15804
|
+
const namespace2 = command.namespace;
|
|
15805
|
+
const selected = namespace2 === void 0 ? result.children : result.children.filter(
|
|
15806
|
+
(child) => child.status === ChildWorkspaceLifecycleStatus.ACTIVE && isKeyedBirthOf(namespace2, child.workspace)
|
|
15622
15807
|
);
|
|
15623
15808
|
return create(ChildWorkspaceListSchema, {
|
|
15624
15809
|
children: selected.map((child) => create(ChildWorkspaceSchema, {
|
|
@@ -15980,40 +16165,6 @@ var NomosRuntimeComponent = (() => {
|
|
|
15980
16165
|
}
|
|
15981
16166
|
};
|
|
15982
16167
|
|
|
15983
|
-
// ../src/runtime/peer_desk_store.ts
|
|
15984
|
-
var recordId = (namespace, key) => `${namespace.length}:${namespace}${key}`;
|
|
15985
|
-
var copy2 = (record) => ({
|
|
15986
|
-
...record,
|
|
15987
|
-
value: record.value.slice()
|
|
15988
|
-
});
|
|
15989
|
-
var MemoryPeerDeskStore = class {
|
|
15990
|
-
#records = /* @__PURE__ */ new Map();
|
|
15991
|
-
list(namespace) {
|
|
15992
|
-
return [...this.#records.values()].filter((record) => record.namespace === namespace).sort((left, right) => left.key.localeCompare(right.key)).map(copy2);
|
|
15993
|
-
}
|
|
15994
|
-
compareExchange(namespace, key, expectedRevision, value) {
|
|
15995
|
-
const id = recordId(namespace, key);
|
|
15996
|
-
const current = this.#records.get(id);
|
|
15997
|
-
if (current?.revision !== expectedRevision) {
|
|
15998
|
-
throw new Error(
|
|
15999
|
-
`peer desk record '${namespace}/${key}' changed at revision ${current?.revision ?? "absent"}`
|
|
16000
|
-
);
|
|
16001
|
-
}
|
|
16002
|
-
if (value === void 0) {
|
|
16003
|
-
this.#records.delete(id);
|
|
16004
|
-
return void 0;
|
|
16005
|
-
}
|
|
16006
|
-
const next = Object.freeze({
|
|
16007
|
-
namespace,
|
|
16008
|
-
key,
|
|
16009
|
-
revision: (current?.revision ?? 0n) + 1n,
|
|
16010
|
-
value: value.slice()
|
|
16011
|
-
});
|
|
16012
|
-
this.#records.set(id, next);
|
|
16013
|
-
return copy2(next);
|
|
16014
|
-
}
|
|
16015
|
-
};
|
|
16016
|
-
|
|
16017
16168
|
// ../src/runtime/correspondence_recovery.ts
|
|
16018
16169
|
var CorrespondenceRecoveryWork = class {
|
|
16019
16170
|
workId;
|
|
@@ -16392,6 +16543,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
16392
16543
|
#offerSequence = 0;
|
|
16393
16544
|
#lastStep;
|
|
16394
16545
|
#probeOnly;
|
|
16546
|
+
#liveConnected;
|
|
16395
16547
|
/** Set when this round adopted the upstream's own head as its base (see #establishBase). */
|
|
16396
16548
|
#establishedBase;
|
|
16397
16549
|
#receiveState;
|
|
@@ -16424,6 +16576,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
16424
16576
|
this.#directoryAnswered = args.directoryAnswered;
|
|
16425
16577
|
this.#placementFetched = args.placementFetched;
|
|
16426
16578
|
this.#probeOnly = args.probeOnly ?? false;
|
|
16579
|
+
this.#liveConnected = args.liveConnected === true;
|
|
16427
16580
|
this.#receiveState = args.receiveState;
|
|
16428
16581
|
this.#completeHistory = args.completeHistory === true;
|
|
16429
16582
|
this.#repairMissingCommit = args.repairMissingCommit === true;
|
|
@@ -16494,6 +16647,9 @@ var NomosRuntimeComponent = (() => {
|
|
|
16494
16647
|
#openRound() {
|
|
16495
16648
|
if (this.#receiveState || this.#replaceLocalHead !== void 0) return this.#leaseEffect();
|
|
16496
16649
|
if (!this.#localHead) return this.#leaseEffect();
|
|
16650
|
+
if (this.#liveConnected && !this.#probeOnly && this.#holdsLocalWork() && this.#previousHead) {
|
|
16651
|
+
return this.#offerOrReconcile();
|
|
16652
|
+
}
|
|
16497
16653
|
const requestId = `${this.#binding.replicaId}:${this.#requestId}:${this.workId}:frontier`;
|
|
16498
16654
|
return this.#beginOffer(encodeInlineCustodyOffer({
|
|
16499
16655
|
session: this.#binding.replicaId,
|
|
@@ -16725,6 +16881,18 @@ var NomosRuntimeComponent = (() => {
|
|
|
16725
16881
|
return this.#finishOfferOutcome(false);
|
|
16726
16882
|
}
|
|
16727
16883
|
const admission = outcome.value;
|
|
16884
|
+
globalThis.__nomosSyncDiagnostic?.("sync.admission", {
|
|
16885
|
+
workspace: this.#mount.workspace,
|
|
16886
|
+
phase: state.phase,
|
|
16887
|
+
local: this.#localHead,
|
|
16888
|
+
tracked: this.#previousHead,
|
|
16889
|
+
remote: admission.main,
|
|
16890
|
+
sealed: admission.sealedMain,
|
|
16891
|
+
resultBase: admission.resultBase,
|
|
16892
|
+
resultBytes: admission.resultPack.byteLength,
|
|
16893
|
+
recoveryRequired: admission.recoveryRequired,
|
|
16894
|
+
summary: summarizeCustodyAdmission(admission)
|
|
16895
|
+
});
|
|
16728
16896
|
this.#desiredHead = admission.main || void 0;
|
|
16729
16897
|
if (!this.#desiredHead) return this.#transportFailure("resident peer returned no admitted frontier", false);
|
|
16730
16898
|
this.#candidateDurable = admission.sealedMain === this.#desiredHead;
|
|
@@ -17341,6 +17509,19 @@ var NomosRuntimeComponent = (() => {
|
|
|
17341
17509
|
return step;
|
|
17342
17510
|
}
|
|
17343
17511
|
#finish(value) {
|
|
17512
|
+
globalThis.__nomosSyncDiagnostic?.("sync.finished", {
|
|
17513
|
+
workspace: value.workspace,
|
|
17514
|
+
previous: value.previousHead,
|
|
17515
|
+
current: value.currentHead,
|
|
17516
|
+
stillAhead: value.stillAhead,
|
|
17517
|
+
deferred: String(value.deferred),
|
|
17518
|
+
admitted: String(value.admitted),
|
|
17519
|
+
reconnect: value.reconnectRequired,
|
|
17520
|
+
directOfferDeferred: value.directOfferDeferred,
|
|
17521
|
+
pushFailed: value.pushFailed,
|
|
17522
|
+
failure: value.pushError?.message,
|
|
17523
|
+
wallMs: elapsedMillis(this.#clock, this.#started)
|
|
17524
|
+
});
|
|
17344
17525
|
this.#state = { phase: WorkspaceSyncPhase.Done };
|
|
17345
17526
|
this.#current = void 0;
|
|
17346
17527
|
return this.#remember({ case: "synced", value });
|
|
@@ -17396,6 +17577,10 @@ var NomosRuntimeComponent = (() => {
|
|
|
17396
17577
|
this.#plan = [this.#args.root];
|
|
17397
17578
|
return this.#advance();
|
|
17398
17579
|
}
|
|
17580
|
+
if (this.#args.liveConnected && this.#args.kernel.resolveRef(this.#args.root.mount, this.#args.requestId, trackedMain2)) {
|
|
17581
|
+
this.#plan = this.#planDependencies();
|
|
17582
|
+
return this.#advance();
|
|
17583
|
+
}
|
|
17399
17584
|
this.#current = this.#work(this.#args.root, `${this.workId}:frontier`, true);
|
|
17400
17585
|
return this.#accept(this.#current.start());
|
|
17401
17586
|
}
|
|
@@ -18581,6 +18766,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
18581
18766
|
#onSyncCompleted;
|
|
18582
18767
|
#onPlacementFetched;
|
|
18583
18768
|
#onShallowMount;
|
|
18769
|
+
#onOutboxHistoryRequired;
|
|
18584
18770
|
#remoteOffers = new CorrespondenceWorkRegistry();
|
|
18585
18771
|
#recoveries = new CorrespondenceWorkRegistry();
|
|
18586
18772
|
#deliveries = new CorrespondenceWorkRegistry();
|
|
@@ -18627,6 +18813,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
18627
18813
|
this.#onSyncCompleted = args.onSyncCompleted;
|
|
18628
18814
|
this.#onPlacementFetched = args.onPlacementFetched;
|
|
18629
18815
|
this.#onShallowMount = args.onShallowMount;
|
|
18816
|
+
this.#onOutboxHistoryRequired = args.onOutboxHistoryRequired;
|
|
18630
18817
|
this.#clock = args.clock;
|
|
18631
18818
|
this.#outboxClock = new OutboxObservationClock(args.clock, args.peerIdentity);
|
|
18632
18819
|
this.#executesCustodianObligations = args.executesCustodianObligations ?? false;
|
|
@@ -18790,6 +18977,15 @@ var NomosRuntimeComponent = (() => {
|
|
|
18790
18977
|
this.#followLane.dependencyAdvanced(workspace);
|
|
18791
18978
|
this.reportFollows();
|
|
18792
18979
|
}
|
|
18980
|
+
/** Received custody can release correspondence and foreign-read dependencies,
|
|
18981
|
+
* but is not newly authored work to send back to its upstream. Recovery is
|
|
18982
|
+
* driven separately by missing history, reconnects and provider announcements.
|
|
18983
|
+
* In particular an optimistic relay is not a durable upstream receipt. */
|
|
18984
|
+
receivedFrontierChanged(workspace) {
|
|
18985
|
+
this.wakeOutbox(workspace);
|
|
18986
|
+
this.#followLane.dependencyAdvanced(workspace);
|
|
18987
|
+
this.reportFollows();
|
|
18988
|
+
}
|
|
18793
18989
|
/**
|
|
18794
18990
|
* Tell a workspace's sessions what its durable follow ALREADY knows.
|
|
18795
18991
|
*
|
|
@@ -19026,8 +19222,16 @@ var NomosRuntimeComponent = (() => {
|
|
|
19026
19222
|
)
|
|
19027
19223
|
);
|
|
19028
19224
|
} catch (error) {
|
|
19225
|
+
if (error instanceof KernelHistoryRequired && this.#onOutboxHistoryRequired) {
|
|
19226
|
+
const retry = this.#onOutboxHistoryRequired(workspace, binding.credentialCapability);
|
|
19227
|
+
this.#outboxDueAt.set(workspace, now + Math.max(250, retry));
|
|
19228
|
+
return { nextAfterMillis: 0 };
|
|
19229
|
+
}
|
|
19029
19230
|
const format = localCopyFormatRefusal(error);
|
|
19030
|
-
if (format === void 0)
|
|
19231
|
+
if (format === void 0) {
|
|
19232
|
+
this.#outboxDueAt.set(workspace, now + 3e4);
|
|
19233
|
+
return { nextAfterMillis: 0 };
|
|
19234
|
+
}
|
|
19031
19235
|
this.#readability.mark(workspace, void 0, format);
|
|
19032
19236
|
this.#outboxDueAt.delete(workspace);
|
|
19033
19237
|
return { nextAfterMillis: 0 };
|
|
@@ -19307,6 +19511,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
19307
19511
|
requestId: request.requestId,
|
|
19308
19512
|
workId: id,
|
|
19309
19513
|
probeOnly,
|
|
19514
|
+
liveConnected: this.#openLinks.has(target3.mount.workspace),
|
|
19310
19515
|
...beforeConverge === void 0 ? {} : { beforeConverge },
|
|
19311
19516
|
...target3.receiveState === void 0 ? {} : { receiveState: target3.receiveState },
|
|
19312
19517
|
...target3.offerHead === void 0 ? {} : { offerHead: target3.offerHead },
|
|
@@ -19334,6 +19539,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
19334
19539
|
root,
|
|
19335
19540
|
work,
|
|
19336
19541
|
outbound: command.admit,
|
|
19542
|
+
liveConnected: this.#openLinks.has(mount.workspace),
|
|
19337
19543
|
dependency: (workspace, source, acquire2 = false) => {
|
|
19338
19544
|
if (this.#roundInFlight(workspace, workId2)) return void 0;
|
|
19339
19545
|
const existing = this.#follows.bindingForWorkspace(workspace);
|
|
@@ -20855,15 +21061,15 @@ var NomosRuntimeComponent = (() => {
|
|
|
20855
21061
|
var HISTORY_ACQUISITION_NAMESPACE = "nomos.peer-desk.history-acquisition/v1";
|
|
20856
21062
|
var HISTORY_BACKGROUND_START_MILLIS = 1e4;
|
|
20857
21063
|
var SLICE_ANSWER_MILLIS = 5 * 6e4;
|
|
20858
|
-
var
|
|
20859
|
-
var
|
|
21064
|
+
var encoder4 = new TextEncoder();
|
|
21065
|
+
var decoder4 = new TextDecoder();
|
|
20860
21066
|
var workId = (workspace) => `history-acquisition:${workspace}`;
|
|
20861
21067
|
var effectId = (workspace, attempt) => `history-acquisition:${workspace}:${HistoryAcquisitionPhase.Acquiring}:${attempt}`;
|
|
20862
21068
|
var encode2 = (work) => {
|
|
20863
21069
|
if (!work.credentialCapability) {
|
|
20864
21070
|
throw new Error(`history acquisition for '${work.workspace}' has not restored its credential capability`);
|
|
20865
21071
|
}
|
|
20866
|
-
return
|
|
21072
|
+
return encoder4.encode(JSON.stringify({
|
|
20867
21073
|
version: 2,
|
|
20868
21074
|
workspace: work.workspace,
|
|
20869
21075
|
credentialCapability: work.credentialCapability,
|
|
@@ -20872,7 +21078,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
20872
21078
|
};
|
|
20873
21079
|
var upgraded = (state) => state.case === "backoff" ? { case: HistoryAcquisitionPhase.Paced, attempt: state.attempt, delayMillis: state.delayMillis, failed: true } : state;
|
|
20874
21080
|
var decode2 = (record) => {
|
|
20875
|
-
const value = JSON.parse(
|
|
21081
|
+
const value = JSON.parse(decoder4.decode(record.value));
|
|
20876
21082
|
if (!value || typeof value !== "object") throw corrupt2(record, "not an object");
|
|
20877
21083
|
const candidate = value;
|
|
20878
21084
|
if (candidate.version !== 1 && candidate.version !== 2 || candidate.workspace !== record.key || !candidate.state) {
|
|
@@ -20935,6 +21141,21 @@ var NomosRuntimeComponent = (() => {
|
|
|
20935
21141
|
this.#ensure(workspace, credentialCapability);
|
|
20936
21142
|
this.#dueAt.set(workspace, this.#now() + HISTORY_BACKGROUND_START_MILLIS);
|
|
20937
21143
|
}
|
|
21144
|
+
/** A background kernel read needs an omitted ancestor now. Queue one bounded
|
|
21145
|
+
* slice on the existing history lane; a failed slice keeps its retry pace. */
|
|
21146
|
+
requestFromBackground(workspace, credentialCapability) {
|
|
21147
|
+
if (!workspace) throw new Error("kernel history requirement names no workspace");
|
|
21148
|
+
this.#ensure(workspace, credentialCapability);
|
|
21149
|
+
const work = this.#get(workspace);
|
|
21150
|
+
const now = this.#now();
|
|
21151
|
+
if (work.state.case === HistoryAcquisitionPhase.Paced && work.state.failed) {
|
|
21152
|
+
const due2 = this.#dueAt.get(workspace) ?? now + work.state.delayMillis;
|
|
21153
|
+
this.#dueAt.set(workspace, due2);
|
|
21154
|
+
if (due2 > now) return due2 - now;
|
|
21155
|
+
}
|
|
21156
|
+
this.#dueAt.set(workspace, now);
|
|
21157
|
+
return 250;
|
|
21158
|
+
}
|
|
20938
21159
|
/** An operation needs history this custody lacks: its next slice now, joining one in flight. */
|
|
20939
21160
|
begin(workspace, credentialCapability) {
|
|
20940
21161
|
if (!workspace) throw new Error("kernel history requirement names no workspace");
|
|
@@ -21243,7 +21464,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
21243
21464
|
this.#trace,
|
|
21244
21465
|
this.#readability
|
|
21245
21466
|
);
|
|
21246
|
-
this.#custodyAdmission = new CustodyAdmissionDesk(this.#kernel, this.#custody);
|
|
21467
|
+
this.#custodyAdmission = new CustodyAdmissionDesk(this.#kernel, this.#custody, new CustodyReceipts(seatedStore));
|
|
21247
21468
|
this.#queries = new KernelQueries(this.#kernel, this.#credentials);
|
|
21248
21469
|
this.#follows = new ReplicaFollowController(
|
|
21249
21470
|
new ReplicaFollowDesk(seatedStore),
|
|
@@ -21405,6 +21626,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
21405
21626
|
// Lazy history: a head-only mount materialises its history in the background, never on
|
|
21406
21627
|
// the path of an operation (architecture/lazy_history.md).
|
|
21407
21628
|
onShallowMount: (workspace, credentialCapability) => this.#historyAcquisition.materialise(workspace, credentialCapability),
|
|
21629
|
+
onOutboxHistoryRequired: (workspace, credentialCapability) => this.#historyAcquisition.requestFromBackground(workspace, credentialCapability),
|
|
21408
21630
|
onSyncCompleted: (session, event) => {
|
|
21409
21631
|
if (event.result?.workspace) {
|
|
21410
21632
|
this.#replicaInventory.placementMayHaveChanged(event.result.workspace);
|
|
@@ -21871,8 +22093,8 @@ var NomosRuntimeComponent = (() => {
|
|
|
21871
22093
|
this.#replicaInventory.placementMayHaveChanged(workspace);
|
|
21872
22094
|
}
|
|
21873
22095
|
}
|
|
21874
|
-
/** Execute a typed paper after the access desk
|
|
21875
|
-
*
|
|
22096
|
+
/** Execute a typed paper after the access desk. Custody admission addresses a
|
|
22097
|
+
* workspace by replica identity; application calls retain session binding. */
|
|
21876
22098
|
#dispatchRequest(request) {
|
|
21877
22099
|
validateRuntimeV2Request(request);
|
|
21878
22100
|
try {
|
|
@@ -21886,18 +22108,20 @@ var NomosRuntimeComponent = (() => {
|
|
|
21886
22108
|
if (!request.target.workspace || !request.target.session) {
|
|
21887
22109
|
throw new Error("addressed runtime request requires workspace and session");
|
|
21888
22110
|
}
|
|
21889
|
-
|
|
21890
|
-
|
|
21891
|
-
if (binding
|
|
21892
|
-
|
|
21893
|
-
|
|
21894
|
-
|
|
22111
|
+
if (request.command.case !== "admitCustodyOffers") {
|
|
22112
|
+
const binding = this.#sessions.bindingIfPresent(request.target.session);
|
|
22113
|
+
if (binding !== void 0) {
|
|
22114
|
+
if (binding.workspace !== request.target.workspace) {
|
|
22115
|
+
throw new Error(
|
|
22116
|
+
`session '${request.target.session}' is bound to workspace '${binding.workspace}', not '${request.target.workspace}'`
|
|
22117
|
+
);
|
|
22118
|
+
}
|
|
22119
|
+
} else {
|
|
22120
|
+
this.#bindInteraction(create(BindSessionRequestSchema, {
|
|
22121
|
+
session: request.target.session,
|
|
22122
|
+
workspace: request.target.workspace
|
|
22123
|
+
}));
|
|
21895
22124
|
}
|
|
21896
|
-
} else {
|
|
21897
|
-
this.#bindInteraction(create(BindSessionRequestSchema, {
|
|
21898
|
-
session: request.target.session,
|
|
21899
|
-
workspace: request.target.workspace
|
|
21900
|
-
}));
|
|
21901
22125
|
}
|
|
21902
22126
|
}
|
|
21903
22127
|
switch (request.command.case) {
|
|
@@ -22094,7 +22318,7 @@ var NomosRuntimeComponent = (() => {
|
|
|
22094
22318
|
ReadMaintenanceCause.ADMITTED_OFFER
|
|
22095
22319
|
);
|
|
22096
22320
|
this.#subscriptions.refreshWorkspace(request.target.workspace);
|
|
22097
|
-
this.#correspondence.
|
|
22321
|
+
this.#correspondence.receivedFrontierChanged(request.target.workspace);
|
|
22098
22322
|
}
|
|
22099
22323
|
return this.#birthCustodyResponse(
|
|
22100
22324
|
request,
|