githolon 0.110.1 → 0.111.1

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.
@@ -0,0 +1,69 @@
1
+ // src/conformance_probe.ts
2
+ import assert from "node:assert/strict";
3
+ import { writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ var [testingEntry, fixture, resultFile, runtime, offline] = process.argv.slice(2);
7
+ var report = { passed: false, packages: [], checks: [] };
8
+ var keepAlive = setInterval(() => {
9
+ }, 1e3);
10
+ var stage = "load generated application";
11
+ try {
12
+ const { testHolon, Refusal, kernelContractRequirements } = await import(pathToFileURL(testingEntry).href);
13
+ const { seatsClient } = await import(pathToFileURL(join(fixture, "build/seats.reception.mjs")).href);
14
+ stage = "runtime acquisition";
15
+ const h = await testHolon({
16
+ law: join(fixture, "build/seats.law.usdz"),
17
+ deterministic: true,
18
+ ...runtime ? { runtimeDir: runtime } : {},
19
+ offline: offline === "true"
20
+ });
21
+ report.runtime = { kernelSha256: h.kernelSha256, contracts: kernelContractRequirements };
22
+ report.checks.push({ name: stage, passed: true });
23
+ const app = h.app(seatsClient, { actor: "person:conformance" });
24
+ stage = "generated write and read";
25
+ const { booking } = await app.openBooking({ label: "conformance", capacity: 1 });
26
+ await app.takeSeat({ bookingId: booking, attendee: "alice", takenAt: "2026-01-01T00:00:00.000Z" });
27
+ const before = await app.bookings.find(booking);
28
+ assert.equal(before.label, "conformance");
29
+ assert.equal(before.seats.alice.status, "active");
30
+ assert.equal((await app.bookingsByLabel({ label: "conformance" })).length, 1);
31
+ report.checks.push({ name: stage, passed: true });
32
+ stage = "expected refusal has no effect";
33
+ const history = h.intents();
34
+ await assert.rejects(
35
+ app.takeSeat({ bookingId: booking, attendee: "bob", takenAt: "2026-01-01T00:00:01.000Z" }),
36
+ (error) => error instanceof Refusal && error.refusal.includes("seats-exceed-capacity")
37
+ );
38
+ assert.deepEqual(await app.bookings.find(booking), before);
39
+ assert.deepEqual(h.intents(), history);
40
+ report.checks.push({ name: stage, passed: true });
41
+ stage = "persisted history verifies";
42
+ const persisted = await h.verify();
43
+ assert.equal(persisted.valid, true, JSON.stringify(persisted));
44
+ assert.ok(history.length >= 3, "admitted application writes must be present in physical custody");
45
+ report.checks.push({ name: stage, passed: true });
46
+ stage = "cold restore preserves data and history";
47
+ const restored = await h.restart();
48
+ const restoredApp = restored.app(seatsClient, { actor: "person:conformance" });
49
+ assert.deepEqual(await restoredApp.bookings.find(booking), before);
50
+ assert.deepEqual(restored.intents(), history);
51
+ const verified = await restored.verify();
52
+ const materialising = verified.walk === "present" && verified.history?.state === "materialising";
53
+ assert.ok(verified.valid || materialising, JSON.stringify(verified));
54
+ assert.equal(restored.kernelSha256, h.kernelSha256);
55
+ const next = await restoredApp.openBooking({ label: "after-restore", capacity: 1 });
56
+ assert.equal((await restoredApp.bookings.find(next.booking)).label, "after-restore");
57
+ report.checks.push({ name: stage, passed: true, ...materialising ? { detail: "Restored data and persisted history match; historical verification is still materialising." } : {} });
58
+ report.passed = true;
59
+ } catch (error) {
60
+ report.checks.push({ name: stage, passed: false });
61
+ report.failure = {
62
+ stage,
63
+ detail: error instanceof Error ? error.message : String(error),
64
+ action: stage === "runtime acquisition" ? "Use a compatible verified runtime directory with --runtime, or run online once to populate the runtime cache. Check the reported package versions before retrying." : "Reinstall the project's locked Nomos packages and retry. If the same check fails, report this diagnostic and the package/kernel versions to Nomos; this isolated fixture should pass."
65
+ };
66
+ }
67
+ clearInterval(keepAlive);
68
+ writeFileSync(resultFile, JSON.stringify(report));
69
+ process.exit(report.passed ? 0 : 1);
@@ -631,7 +631,7 @@ var CustodyBreakPolicySchema = /* @__PURE__ */ enumDesc13(file_nomos_runtime_v2_
631
631
  var CustodyBreakPolicy = /* @__PURE__ */ tsEnum13(CustodyBreakPolicySchema);
632
632
 
633
633
  // ../adapter/proto/nomos/runtime/v2/observability_desk_pb.js
634
- var file_nomos_runtime_v2_observability_desk = /* @__PURE__ */ fileDesc21("Cilub21vcy9ydW50aW1lL3YyL29ic2VydmFiaWxpdHlfZGVzay5wcm90bxIQbm9tb3MucnVudGltZS52MiJCCgxUcmFjZUNvbnRleHQSEAoIdHJhY2VfaWQYASABKAwSDwoHc3Bhbl9pZBgCIAEoDBIPCgdzYW1wbGVkGAMgASgIIp0CCg5SdW50aW1lRmFpbHVyZRIMCgRjb2RlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSEQoJY29tcG9uZW50GAMgASgJEhYKCXdvcmtzcGFjZRgEIAEoCUgAiAEBEhMKBmRvbWFpbhgFIAEoCUgBiAEBEhYKCWRpcmVjdGl2ZRgGIAEoCUgCiAEBEjkKCmF0dHJpYnV0ZXMYByADKAsyJS5ub21vcy5ydW50aW1lLnYyLkRpYWdub3N0aWNBdHRyaWJ1dGUSMgoEa2luZBgIIAEoDjIkLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZUZhaWx1cmVLaW5kQgwKCl93b3Jrc3BhY2VCCQoHX2RvbWFpbkIMCgpfZGlyZWN0aXZlIr4BChJSdW50aW1lVW5hdmFpbGFibGUSOgoGcmVhc29uGAEgASgOMioubm9tb3MucnVudGltZS52Mi5SdW50aW1lVW5hdmFpbGFibGVSZWFzb24SEQoJd29ya3NwYWNlGAIgASgJEhEKCXJldHJ5YWJsZRgDIAEoCBIfChJyZXRyeV9hZnRlcl9taWxsaXMYBCABKA1IAIgBARIOCgZkZXRhaWwYBSABKAlCFQoTX3JldHJ5X2FmdGVyX21pbGxpcyJ+Cg5SdW50aW1lUmVmdXNhbBI2CgZyZWFzb24YASABKA4yJi5ub21vcy5ydW50aW1lLnYyLlJ1bnRpbWVSZWZ1c2FsUmVhc29uEhEKCXdvcmtzcGFjZRgCIAEoCRIRCglyZXRyeWFibGUYAyABKAgSDgoGZGV0YWlsGAQgASgJIqUBChNEaWFnbm9zdGljQXR0cmlidXRlEgwKBG5hbWUYASABKAkSFgoMc3RyaW5nX3ZhbHVlGAIgASgJSAASFwoNaW50ZWdlcl92YWx1ZRgDIAEoEkgAEhYKDGRvdWJsZV92YWx1ZRgEIAEoAUgAEhcKDWJvb2xlYW5fdmFsdWUYBSABKAhIABIVCgtieXRlc192YWx1ZRgGIAEoDEgAQgcKBXZhbHVlIuMKCgxSdW50aW1lRXZlbnQSEAoIc2VxdWVuY2UYASABKAQSFAoHc2Vzc2lvbhgCIAEoCUgBiAEBEi8KBXJlYWR5GAogASgLMh4ubm9tb3MucnVudGltZS52Mi5SdW50aW1lUmVhZHlIABI3Cg13YXRjaF9jaGFuZ2VkGAsgASgLMh4ubm9tb3MucnVudGltZS52Mi5XYXRjaENoYW5nZWRIABI5Cg5zeW5jX2NvbXBsZXRlZBgMIAEoCzIfLm5vbW9zLnJ1bnRpbWUudjIuU3luY0NvbXBsZXRlZEgAEjUKDGxpbmtfY2hhbmdlZBgNIAEoCzIdLm5vbW9zLnJ1bnRpbWUudjIuTGlua0NoYW5nZWRIABI5Cg5zaWduYWxfY2hhbmdlZBgOIAEoCzIfLm5vbW9zLnJ1bnRpbWUudjIuU2lnbmFsQ2hhbmdlZEgAEjsKD2N1c3RvZHlfY2hhbmdlZBgPIAEoCzIgLm5vbW9zLnJ1bnRpbWUudjIuQ3VzdG9keUNoYW5nZWRIABJCChNsb2NhbF93b3JrX3JlamVjdGVkGBAgASgLMiMubm9tb3MucnVudGltZS52Mi5Mb2NhbFdvcmtSZWplY3RlZEgAEjMKC2xhd19jaGFuZ2VkGBEgASgLMhwubm9tb3MucnVudGltZS52Mi5MYXdDaGFuZ2VkSAASQwoPa2VybmVsX3Byb2dyZXNzGBIgASgLMigubm9tb3MucnVudGltZS52Mi5LZXJuZWxQcm9ncmVzc09ic2VydmVkSAASLQoEc3BhbhgTIAEoCzIdLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZVNwYW5IABI/ChF0cmFuc2Zlcl9wcm9ncmVzcxgUIAEoCzIiLm5vbW9zLnJ1bnRpbWUudjIuVHJhbnNmZXJQcm9ncmVzc0gAEkkKFG1haW50ZW5hbmNlX3Byb2dyZXNzGBUgASgLMikubm9tb3MucnVudGltZS52Mi5SZWFkTWFpbnRlbmFuY2VQcm9ncmVzc0gAEjsKDXNvY2tldF9lZmZlY3QYFiABKAsyIi5ub21vcy5ydW50aW1lLnYyLlBlZXJTb2NrZXRFZmZlY3RIABJUChxjcmVkZW50aWFsX3JlZnJlc2hfcmVxdWVzdGVkGBcgASgLMiwubm9tb3MucnVudGltZS52Mi5DcmVkZW50aWFsUmVmcmVzaFJlcXVlc3RlZEgAElIKG3JlY2VpdmluZ19ncm91cF9jb252ZXJnZW5jZRgYIAEoCzIrLm5vbW9zLnJ1bnRpbWUudjIuUmVjZWl2aW5nR3JvdXBDb252ZXJnZW5jZUgAEkoKF21vZGVsX2Fkb3B0aW9uX3Byb2dyZXNzGBkgASgLMicubm9tb3MucnVudGltZS52Mi5Nb2RlbEFkb3B0aW9uUHJvZ3Jlc3NIABI7Cg9mb2xsb3dzX3N1bW1hcnkYGiABKAsyIC5ub21vcy5ydW50aW1lLnYyLkZvbGxvd3NTdW1tYXJ5SAASRAoUbG9jYWxfY29weV9wcmVzZXJ2ZWQYGyABKAsyJC5ub21vcy5ydW50aW1lLnYyLlByZXNlcnZlZExvY2FsQ29weUgAEk4KGWZvcmVpZ25fcGxhY2VtZW50X2lnbm9yZWQYHCABKAsyKS5ub21vcy5ydW50aW1lLnYyLkZvcmVpZ25QbGFjZW1lbnRJZ25vcmVkSAASQwoTYmluZGluZ19xdWFyYW50aW5lZBgdIAEoCzIkLm5vbW9zLnJ1bnRpbWUudjIuUXVhcmFudGluZWRCaW5kaW5nSABCBwoFZXZlbnRCCgoIX3Nlc3Npb24ivAEKDkZvbGxvd3NTdW1tYXJ5EhAKCGZvbGxvd2VkGAEgASgNEg8KB3NldHRsZWQYAiABKA0SDAoEbGl2ZRgDIAEoDRI3Cgp3b3Jrc3BhY2VzGAQgAygLMiMubm9tb3MucnVudGltZS52Mi5Gb2xsb3dPYnNlcnZhdGlvbhIkChdvYnNlcnZlZF9hdF91bml4X21pbGxpcxgFIAEoBEgAiAEBQhoKGF9vYnNlcnZlZF9hdF91bml4X21pbGxpcyLRAgoRRm9sbG93T2JzZXJ2YXRpb24SEQoJd29ya3NwYWNlGAEgASgJEjcKBXBoYXNlGAIgASgOMigubm9tb3MucnVudGltZS52Mi5Gb2xsb3dPYnNlcnZhdGlvblBoYXNlEgwKBGxpdmUYAyABKAgSEwoGZGV0YWlsGAQgASgJSACIAQESIQoUcmV0cnlfYXRfdW5peF9taWxsaXMYBSABKARIAYgBARIfChJkdWVfYXRfdW5peF9taWxsaXMYBiABKARIAogBARIUCgdhdHRlbXB0GAcgASgNSAOIAQESGgoNYWN0aXZlX2VmZmVjdBgIIAEoCUgEiAEBQgkKB19kZXRhaWxCFwoVX3JldHJ5X2F0X3VuaXhfbWlsbGlzQhUKE19kdWVfYXRfdW5peF9taWxsaXNCCgoIX2F0dGVtcHRCEAoOX2FjdGl2ZV9lZmZlY3QiVgoaQ3JlZGVudGlhbFJlZnJlc2hSZXF1ZXN0ZWQSOAoHcGVuZGluZxgBIAEoCzInLm5vbW9zLnJ1bnRpbWUudjIuQ29ycmVzcG9uZGVuY2VQZW5kaW5nIj4KDFJ1bnRpbWVSZWFkeRIXCg9ydW50aW1lX3ZlcnNpb24YASABKAkSFQoNa2VybmVsX3NoYTI1NhgCIAEoDCL8AQoMV2F0Y2hDaGFuZ2VkEhcKD3N1YnNjcmlwdGlvbl9pZBgBIAEoCRITCgtyZXN1bHRfdXNkYRgCIAEoDBI2CgdmYWlsdXJlGAMgASgLMiAubm9tb3MucnVudGltZS52Mi5SdW50aW1lRmFpbHVyZUgAiAEBEjUKEmFwcGxpY2F0aW9uX3Jlc3VsdBgEIAEoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlIAYgBARIaCg1pbnRlZ2VyX3ZhbHVlGAUgASgDSAKIAQFCCgoIX2ZhaWx1cmVCFQoTX2FwcGxpY2F0aW9uX3Jlc3VsdEIQCg5faW50ZWdlcl92YWx1ZSKcAQoNU3luY0NvbXBsZXRlZBIOCgZyZWFzb24YASABKAkSNwoGcmVzdWx0GAIgASgLMicubm9tb3MucnVudGltZS52Mi5TeW5jV29ya3NwYWNlUmVzcG9uc2USNgoHZmFpbHVyZRgDIAEoCzIgLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZUZhaWx1cmVIAIgBAUIKCghfZmFpbHVyZSI7CgtMaW5rQ2hhbmdlZBIsCgZzdGF0dXMYASABKA4yHC5ub21vcy5ydW50aW1lLnYyLkxpbmtTdGF0dXMiOAoNU2lnbmFsQ2hhbmdlZBIOCgZkb21haW4YASABKAkSFwoPcHJvamVjdGlvbl91c2RhGAIgASgMIlAKCkxhd0NoYW5nZWQSDgoGZG9tYWluGAEgASgJEhYKDnBhY2thZ2Vfc2hhMjU2GAIgASgJEhoKEmNvbXBhdGliaWxpdHlfdXNkYRgDIAEoDCLdAQoLUnVudGltZVNwYW4SEAoIdHJhY2VfaWQYASABKAwSDwoHc3Bhbl9pZBgCIAEoDBIbCg5wYXJlbnRfc3Bhbl9pZBgDIAEoDEgAiAEBEgwKBG5hbWUYBCABKAkSGgoSc3RhcnRlZF91bml4X25hbm9zGAUgASgEEhYKDmR1cmF0aW9uX25hbm9zGAYgASgEEjkKCmF0dHJpYnV0ZXMYByADKAsyJS5ub21vcy5ydW50aW1lLnYyLkRpYWdub3N0aWNBdHRyaWJ1dGVCEQoPX3BhcmVudF9zcGFuX2lkIuoBChZLZXJuZWxQcm9ncmVzc09ic2VydmVkEjkKCHNuYXBzaG90GAEgASgLMicubm9tb3Mua2VybmVsLnYxLktlcm5lbFByb2dyZXNzU25hcHNob3QSJAocaG9zdF9vYnNlcnZlZF9lbGFwc2VkX21pY3JvcxgCIAEoBBIqCiJob3N0X29ic2VydmVkX3BoYXNlX2VsYXBzZWRfbWljcm9zGAMgASgEEh4KFnByb2Nlc3NfcmVzaWRlbnRfYnl0ZXMYBCABKAQSIwobcHJvY2Vzc19wZWFrX3Jlc2lkZW50X2J5dGVzGAUgASgEIoIBChBUcmFuc2ZlclByb2dyZXNzEhYKDnJlY2VpdmVkX2J5dGVzGAEgASgEEhgKC3RvdGFsX2J5dGVzGAIgASgESACIAQESLAoEa2luZBgDIAEoDjIeLm5vbW9zLnJ1bnRpbWUudjIuVHJhbnNmZXJLaW5kQg4KDF90b3RhbF9ieXRlcyrKAQoSUnVudGltZUZhaWx1cmVLaW5kEiQKIFJVTlRJTUVfRkFJTFVSRV9LSU5EX1VOU1BFQ0lGSUVEEAASIQodUlVOVElNRV9GQUlMVVJFX0tJTkRfSU5URVJOQUwQARIhCh1SVU5USU1FX0ZBSUxVUkVfS0lORF9QUk9UT0NPTBACEiIKHlJVTlRJTUVfRkFJTFVSRV9LSU5EX0lOVEVHUklUWRADEiQKIFJVTlRJTUVfRkFJTFVSRV9LSU5EX1VOU1VQUE9SVEVEEAQqpwMKGFJ1bnRpbWVVbmF2YWlsYWJsZVJlYXNvbhIqCiZSVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9VTlNQRUNJRklFRBAAEjIKLlJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX1JFTU9URV9PTkxZX09GRkxJTkUQARIxCi1SVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9SRU1PVEVfVU5SRUFDSEFCTEUQAhItCilSVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9SRU1PVEVfVElNRU9VVBADEjYKMlJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX0xPQ0FMX1JFUExJQ0FfTk9UX1JFQURZEAQSNQoxUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fQ1JFREVOVElBTF9VTkFWQUlMQUJMRRAFEjAKLFJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX1dPUktTUEFDRV9PUEVOSU5HEAYSKAokUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fUEVFUl9CVVNZEAcq8AEKFFJ1bnRpbWVSZWZ1c2FsUmVhc29uEiYKIlJVTlRJTUVfUkVGVVNBTF9SRUFTT05fVU5TUEVDSUZJRUQQABItCilSVU5USU1FX1JFRlVTQUxfUkVBU09OX0lOVkFMSURfQ1JFREVOVElBTBABEigKJFJVTlRJTUVfUkVGVVNBTF9SRUFTT05fQUNDRVNTX0RFTklFRBACEisKJ1JVTlRJTUVfUkVGVVNBTF9SRUFTT05fUExBQ0VNRU5UX1BPTElDWRADEioKJlJVTlRJTUVfUkVGVVNBTF9SRUFTT05fU0VTU0lPTl9VTkJPVU5EEAQqlQQKFkZvbGxvd09ic2VydmF0aW9uUGhhc2USKAokRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1VOU1BFQ0lGSUVEEAASJAogRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX0RFU0lSRUQQARIgChxGT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfRFVFEAISJAogRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1JVTk5JTkcQAxIkCiBGT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfU0VUVExFRBAEEjAKLEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9BV0FJVElOR19ERVBFTkRFTkNZEAUSJAogRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX09GRkxJTkUQBhIvCitGT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfSU5WQUxJRF9DUkVERU5USUFMEAcSJAogRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX0JBQ0tPRkYQCBIsCihGT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfUkVCT1JOX1JFTU9URUxZEAkSLAooRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1JFUExBQ0lOR19MT0NBTBAKEjIKLkZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9MT0NBTF9DT1BZX1VOUkVBREFCTEUQCypXCgpMaW5rU3RhdHVzEhsKF0xJTktfU1RBVFVTX1VOU1BFQ0lGSUVEEAASFAoQTElOS19TVEFUVVNfT1BFThABEhYKEkxJTktfU1RBVFVTX0NMT1NFRBACKnYKDFRyYW5zZmVyS2luZBIdChlUUkFOU0ZFUl9LSU5EX1VOU1BFQ0lGSUVEEAASFwoTVFJBTlNGRVJfS0lORF9ERUxUQRABEhYKElRSQU5TRkVSX0tJTkRfRlVMTBACEhYKElRSQU5TRkVSX0tJTkRfUFVTSBADYgZwcm90bzM", [file_google_protobuf_any2, file_nomos_kernel_v1_progress, file_nomos_runtime_v2_correspondence_desk, file_nomos_runtime_v2_custody_desk, file_nomos_runtime_v2_placement_desk, file_nomos_runtime_v2_maintenance_desk, file_nomos_runtime_v2_model_adoption_desk, file_nomos_runtime_v2_receiving_group_desk, file_nomos_runtime_v2_recovery_desk]);
634
+ var file_nomos_runtime_v2_observability_desk = /* @__PURE__ */ fileDesc21("Cilub21vcy9ydW50aW1lL3YyL29ic2VydmFiaWxpdHlfZGVzay5wcm90bxIQbm9tb3MucnVudGltZS52MiJCCgxUcmFjZUNvbnRleHQSEAoIdHJhY2VfaWQYASABKAwSDwoHc3Bhbl9pZBgCIAEoDBIPCgdzYW1wbGVkGAMgASgIIp0CCg5SdW50aW1lRmFpbHVyZRIMCgRjb2RlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSEQoJY29tcG9uZW50GAMgASgJEhYKCXdvcmtzcGFjZRgEIAEoCUgAiAEBEhMKBmRvbWFpbhgFIAEoCUgBiAEBEhYKCWRpcmVjdGl2ZRgGIAEoCUgCiAEBEjkKCmF0dHJpYnV0ZXMYByADKAsyJS5ub21vcy5ydW50aW1lLnYyLkRpYWdub3N0aWNBdHRyaWJ1dGUSMgoEa2luZBgIIAEoDjIkLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZUZhaWx1cmVLaW5kQgwKCl93b3Jrc3BhY2VCCQoHX2RvbWFpbkIMCgpfZGlyZWN0aXZlIr4BChJSdW50aW1lVW5hdmFpbGFibGUSOgoGcmVhc29uGAEgASgOMioubm9tb3MucnVudGltZS52Mi5SdW50aW1lVW5hdmFpbGFibGVSZWFzb24SEQoJd29ya3NwYWNlGAIgASgJEhEKCXJldHJ5YWJsZRgDIAEoCBIfChJyZXRyeV9hZnRlcl9taWxsaXMYBCABKA1IAIgBARIOCgZkZXRhaWwYBSABKAlCFQoTX3JldHJ5X2FmdGVyX21pbGxpcyJ+Cg5SdW50aW1lUmVmdXNhbBI2CgZyZWFzb24YASABKA4yJi5ub21vcy5ydW50aW1lLnYyLlJ1bnRpbWVSZWZ1c2FsUmVhc29uEhEKCXdvcmtzcGFjZRgCIAEoCRIRCglyZXRyeWFibGUYAyABKAgSDgoGZGV0YWlsGAQgASgJIqUBChNEaWFnbm9zdGljQXR0cmlidXRlEgwKBG5hbWUYASABKAkSFgoMc3RyaW5nX3ZhbHVlGAIgASgJSAASFwoNaW50ZWdlcl92YWx1ZRgDIAEoEkgAEhYKDGRvdWJsZV92YWx1ZRgEIAEoAUgAEhcKDWJvb2xlYW5fdmFsdWUYBSABKAhIABIVCgtieXRlc192YWx1ZRgGIAEoDEgAQgcKBXZhbHVlIqQLCgxSdW50aW1lRXZlbnQSEAoIc2VxdWVuY2UYASABKAQSFAoHc2Vzc2lvbhgCIAEoCUgBiAEBEi8KBXJlYWR5GAogASgLMh4ubm9tb3MucnVudGltZS52Mi5SdW50aW1lUmVhZHlIABI3Cg13YXRjaF9jaGFuZ2VkGAsgASgLMh4ubm9tb3MucnVudGltZS52Mi5XYXRjaENoYW5nZWRIABI5Cg5zeW5jX2NvbXBsZXRlZBgMIAEoCzIfLm5vbW9zLnJ1bnRpbWUudjIuU3luY0NvbXBsZXRlZEgAEjUKDGxpbmtfY2hhbmdlZBgNIAEoCzIdLm5vbW9zLnJ1bnRpbWUudjIuTGlua0NoYW5nZWRIABI5Cg5zaWduYWxfY2hhbmdlZBgOIAEoCzIfLm5vbW9zLnJ1bnRpbWUudjIuU2lnbmFsQ2hhbmdlZEgAEjsKD2N1c3RvZHlfY2hhbmdlZBgPIAEoCzIgLm5vbW9zLnJ1bnRpbWUudjIuQ3VzdG9keUNoYW5nZWRIABJCChNsb2NhbF93b3JrX3JlamVjdGVkGBAgASgLMiMubm9tb3MucnVudGltZS52Mi5Mb2NhbFdvcmtSZWplY3RlZEgAEjMKC2xhd19jaGFuZ2VkGBEgASgLMhwubm9tb3MucnVudGltZS52Mi5MYXdDaGFuZ2VkSAASQwoPa2VybmVsX3Byb2dyZXNzGBIgASgLMigubm9tb3MucnVudGltZS52Mi5LZXJuZWxQcm9ncmVzc09ic2VydmVkSAASLQoEc3BhbhgTIAEoCzIdLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZVNwYW5IABI/ChF0cmFuc2Zlcl9wcm9ncmVzcxgUIAEoCzIiLm5vbW9zLnJ1bnRpbWUudjIuVHJhbnNmZXJQcm9ncmVzc0gAEkkKFG1haW50ZW5hbmNlX3Byb2dyZXNzGBUgASgLMikubm9tb3MucnVudGltZS52Mi5SZWFkTWFpbnRlbmFuY2VQcm9ncmVzc0gAEjsKDXNvY2tldF9lZmZlY3QYFiABKAsyIi5ub21vcy5ydW50aW1lLnYyLlBlZXJTb2NrZXRFZmZlY3RIABJUChxjcmVkZW50aWFsX3JlZnJlc2hfcmVxdWVzdGVkGBcgASgLMiwubm9tb3MucnVudGltZS52Mi5DcmVkZW50aWFsUmVmcmVzaFJlcXVlc3RlZEgAElIKG3JlY2VpdmluZ19ncm91cF9jb252ZXJnZW5jZRgYIAEoCzIrLm5vbW9zLnJ1bnRpbWUudjIuUmVjZWl2aW5nR3JvdXBDb252ZXJnZW5jZUgAEkoKF21vZGVsX2Fkb3B0aW9uX3Byb2dyZXNzGBkgASgLMicubm9tb3MucnVudGltZS52Mi5Nb2RlbEFkb3B0aW9uUHJvZ3Jlc3NIABI7Cg9mb2xsb3dzX3N1bW1hcnkYGiABKAsyIC5ub21vcy5ydW50aW1lLnYyLkZvbGxvd3NTdW1tYXJ5SAASRAoUbG9jYWxfY29weV9wcmVzZXJ2ZWQYGyABKAsyJC5ub21vcy5ydW50aW1lLnYyLlByZXNlcnZlZExvY2FsQ29weUgAEk4KGWZvcmVpZ25fcGxhY2VtZW50X2lnbm9yZWQYHCABKAsyKS5ub21vcy5ydW50aW1lLnYyLkZvcmVpZ25QbGFjZW1lbnRJZ25vcmVkSAASQwoTYmluZGluZ19xdWFyYW50aW5lZBgdIAEoCzIkLm5vbW9zLnJ1bnRpbWUudjIuUXVhcmFudGluZWRCaW5kaW5nSAASPwoRd3JpdGVfcHJlcGFyYXRpb24YHiABKAsyIi5ub21vcy5ydW50aW1lLnYyLldyaXRlUHJlcGFyYXRpb25IAEIHCgVldmVudEIKCghfc2Vzc2lvbiK8AQoORm9sbG93c1N1bW1hcnkSEAoIZm9sbG93ZWQYASABKA0SDwoHc2V0dGxlZBgCIAEoDRIMCgRsaXZlGAMgASgNEjcKCndvcmtzcGFjZXMYBCADKAsyIy5ub21vcy5ydW50aW1lLnYyLkZvbGxvd09ic2VydmF0aW9uEiQKF29ic2VydmVkX2F0X3VuaXhfbWlsbGlzGAUgASgESACIAQFCGgoYX29ic2VydmVkX2F0X3VuaXhfbWlsbGlzItECChFGb2xsb3dPYnNlcnZhdGlvbhIRCgl3b3Jrc3BhY2UYASABKAkSNwoFcGhhc2UYAiABKA4yKC5ub21vcy5ydW50aW1lLnYyLkZvbGxvd09ic2VydmF0aW9uUGhhc2USDAoEbGl2ZRgDIAEoCBITCgZkZXRhaWwYBCABKAlIAIgBARIhChRyZXRyeV9hdF91bml4X21pbGxpcxgFIAEoBEgBiAEBEh8KEmR1ZV9hdF91bml4X21pbGxpcxgGIAEoBEgCiAEBEhQKB2F0dGVtcHQYByABKA1IA4gBARIaCg1hY3RpdmVfZWZmZWN0GAggASgJSASIAQFCCQoHX2RldGFpbEIXChVfcmV0cnlfYXRfdW5peF9taWxsaXNCFQoTX2R1ZV9hdF91bml4X21pbGxpc0IKCghfYXR0ZW1wdEIQCg5fYWN0aXZlX2VmZmVjdCJWChpDcmVkZW50aWFsUmVmcmVzaFJlcXVlc3RlZBI4CgdwZW5kaW5nGAEgASgLMicubm9tb3MucnVudGltZS52Mi5Db3JyZXNwb25kZW5jZVBlbmRpbmciPgoMUnVudGltZVJlYWR5EhcKD3J1bnRpbWVfdmVyc2lvbhgBIAEoCRIVCg1rZXJuZWxfc2hhMjU2GAIgASgMIvwBCgxXYXRjaENoYW5nZWQSFwoPc3Vic2NyaXB0aW9uX2lkGAEgASgJEhMKC3Jlc3VsdF91c2RhGAIgASgMEjYKB2ZhaWx1cmUYAyABKAsyIC5ub21vcy5ydW50aW1lLnYyLlJ1bnRpbWVGYWlsdXJlSACIAQESNQoSYXBwbGljYXRpb25fcmVzdWx0GAQgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueUgBiAEBEhoKDWludGVnZXJfdmFsdWUYBSABKANIAogBAUIKCghfZmFpbHVyZUIVChNfYXBwbGljYXRpb25fcmVzdWx0QhAKDl9pbnRlZ2VyX3ZhbHVlIpwBCg1TeW5jQ29tcGxldGVkEg4KBnJlYXNvbhgBIAEoCRI3CgZyZXN1bHQYAiABKAsyJy5ub21vcy5ydW50aW1lLnYyLlN5bmNXb3Jrc3BhY2VSZXNwb25zZRI2CgdmYWlsdXJlGAMgASgLMiAubm9tb3MucnVudGltZS52Mi5SdW50aW1lRmFpbHVyZUgAiAEBQgoKCF9mYWlsdXJlIjsKC0xpbmtDaGFuZ2VkEiwKBnN0YXR1cxgBIAEoDjIcLm5vbW9zLnJ1bnRpbWUudjIuTGlua1N0YXR1cyI4Cg1TaWduYWxDaGFuZ2VkEg4KBmRvbWFpbhgBIAEoCRIXCg9wcm9qZWN0aW9uX3VzZGEYAiABKAwiUAoKTGF3Q2hhbmdlZBIOCgZkb21haW4YASABKAkSFgoOcGFja2FnZV9zaGEyNTYYAiABKAkSGgoSY29tcGF0aWJpbGl0eV91c2RhGAMgASgMIt0BCgtSdW50aW1lU3BhbhIQCgh0cmFjZV9pZBgBIAEoDBIPCgdzcGFuX2lkGAIgASgMEhsKDnBhcmVudF9zcGFuX2lkGAMgASgMSACIAQESDAoEbmFtZRgEIAEoCRIaChJzdGFydGVkX3VuaXhfbmFub3MYBSABKAQSFgoOZHVyYXRpb25fbmFub3MYBiABKAQSOQoKYXR0cmlidXRlcxgHIAMoCzIlLm5vbW9zLnJ1bnRpbWUudjIuRGlhZ25vc3RpY0F0dHJpYnV0ZUIRCg9fcGFyZW50X3NwYW5faWQi6gEKFktlcm5lbFByb2dyZXNzT2JzZXJ2ZWQSOQoIc25hcHNob3QYASABKAsyJy5ub21vcy5rZXJuZWwudjEuS2VybmVsUHJvZ3Jlc3NTbmFwc2hvdBIkChxob3N0X29ic2VydmVkX2VsYXBzZWRfbWljcm9zGAIgASgEEioKImhvc3Rfb2JzZXJ2ZWRfcGhhc2VfZWxhcHNlZF9taWNyb3MYAyABKAQSHgoWcHJvY2Vzc19yZXNpZGVudF9ieXRlcxgEIAEoBBIjChtwcm9jZXNzX3BlYWtfcmVzaWRlbnRfYnl0ZXMYBSABKAQiggEKEFRyYW5zZmVyUHJvZ3Jlc3MSFgoOcmVjZWl2ZWRfYnl0ZXMYASABKAQSGAoLdG90YWxfYnl0ZXMYAiABKARIAIgBARIsCgRraW5kGAMgASgOMh4ubm9tb3MucnVudGltZS52Mi5UcmFuc2ZlcktpbmRCDgoMX3RvdGFsX2J5dGVzIjkKEFdyaXRlUHJlcGFyYXRpb24SEgoKcmVxdWVzdF9pZBgBIAEoCRIRCgl3b3Jrc3BhY2UYAiABKAkqygEKElJ1bnRpbWVGYWlsdXJlS2luZBIkCiBSVU5USU1FX0ZBSUxVUkVfS0lORF9VTlNQRUNJRklFRBAAEiEKHVJVTlRJTUVfRkFJTFVSRV9LSU5EX0lOVEVSTkFMEAESIQodUlVOVElNRV9GQUlMVVJFX0tJTkRfUFJPVE9DT0wQAhIiCh5SVU5USU1FX0ZBSUxVUkVfS0lORF9JTlRFR1JJVFkQAxIkCiBSVU5USU1FX0ZBSUxVUkVfS0lORF9VTlNVUFBPUlRFRBAEKqcDChhSdW50aW1lVW5hdmFpbGFibGVSZWFzb24SKgomUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fVU5TUEVDSUZJRUQQABIyCi5SVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9SRU1PVEVfT05MWV9PRkZMSU5FEAESMQotUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fUkVNT1RFX1VOUkVBQ0hBQkxFEAISLQopUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fUkVNT1RFX1RJTUVPVVQQAxI2CjJSVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9MT0NBTF9SRVBMSUNBX05PVF9SRUFEWRAEEjUKMVJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX0NSRURFTlRJQUxfVU5BVkFJTEFCTEUQBRIwCixSVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9XT1JLU1BBQ0VfT1BFTklORxAGEigKJFJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX1BFRVJfQlVTWRAHKvABChRSdW50aW1lUmVmdXNhbFJlYXNvbhImCiJSVU5USU1FX1JFRlVTQUxfUkVBU09OX1VOU1BFQ0lGSUVEEAASLQopUlVOVElNRV9SRUZVU0FMX1JFQVNPTl9JTlZBTElEX0NSRURFTlRJQUwQARIoCiRSVU5USU1FX1JFRlVTQUxfUkVBU09OX0FDQ0VTU19ERU5JRUQQAhIrCidSVU5USU1FX1JFRlVTQUxfUkVBU09OX1BMQUNFTUVOVF9QT0xJQ1kQAxIqCiZSVU5USU1FX1JFRlVTQUxfUkVBU09OX1NFU1NJT05fVU5CT1VORBAEKpUEChZGb2xsb3dPYnNlcnZhdGlvblBoYXNlEigKJEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9VTlNQRUNJRklFRBAAEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9ERVNJUkVEEAESIAocRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX0RVRRACEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9SVU5OSU5HEAMSJAogRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1NFVFRMRUQQBBIwCixGT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfQVdBSVRJTkdfREVQRU5ERU5DWRAFEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9PRkZMSU5FEAYSLworRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX0lOVkFMSURfQ1JFREVOVElBTBAHEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9CQUNLT0ZGEAgSLAooRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1JFQk9STl9SRU1PVEVMWRAJEiwKKEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9SRVBMQUNJTkdfTE9DQUwQChIyCi5GT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfTE9DQUxfQ09QWV9VTlJFQURBQkxFEAsqVwoKTGlua1N0YXR1cxIbChdMSU5LX1NUQVRVU19VTlNQRUNJRklFRBAAEhQKEExJTktfU1RBVFVTX09QRU4QARIWChJMSU5LX1NUQVRVU19DTE9TRUQQAip2CgxUcmFuc2ZlcktpbmQSHQoZVFJBTlNGRVJfS0lORF9VTlNQRUNJRklFRBAAEhcKE1RSQU5TRkVSX0tJTkRfREVMVEEQARIWChJUUkFOU0ZFUl9LSU5EX0ZVTEwQAhIWChJUUkFOU0ZFUl9LSU5EX1BVU0gQA2IGcHJvdG8z", [file_google_protobuf_any2, file_nomos_kernel_v1_progress, file_nomos_runtime_v2_correspondence_desk, file_nomos_runtime_v2_custody_desk, file_nomos_runtime_v2_placement_desk, file_nomos_runtime_v2_maintenance_desk, file_nomos_runtime_v2_model_adoption_desk, file_nomos_runtime_v2_receiving_group_desk, file_nomos_runtime_v2_recovery_desk]);
635
635
  var RuntimeFailureSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 1);
636
636
  var RuntimeUnavailableSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 2);
637
637
  var RuntimeRefusalSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 3);
@@ -645,6 +645,7 @@ var WatchChangedSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_obs
645
645
  var SyncCompletedSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 11);
646
646
  var LinkChangedSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 12);
647
647
  var RuntimeSpanSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 15);
648
+ var WritePreparationSchema = /* @__PURE__ */ messageDesc21(file_nomos_runtime_v2_observability_desk, 18);
648
649
  var RuntimeFailureKindSchema = /* @__PURE__ */ enumDesc14(file_nomos_runtime_v2_observability_desk, 0);
649
650
  var RuntimeFailureKind = /* @__PURE__ */ tsEnum14(RuntimeFailureKindSchema);
650
651
  var RuntimeUnavailableReasonSchema = /* @__PURE__ */ enumDesc14(file_nomos_runtime_v2_observability_desk, 1);
@@ -6707,6 +6708,17 @@ var CredentialSessions = class {
6707
6708
  // ../peer-office/src/runtime/credential_recovery_desk.ts
6708
6709
  import { create as create21, fromBinary as fromBinary13, toBinary as toBinary13 } from "@bufbuild/protobuf";
6709
6710
 
6711
+ // ../peer-office/src/runtime/credential_failure.ts
6712
+ function recoverableCredential(failure2) {
6713
+ return failure2.code === "nomos.auth.token_expired" || failure2.code === "nomos.auth.token_missing";
6714
+ }
6715
+ function syncNeedsCredentialRefresh(result, failure2) {
6716
+ if (failure2 !== void 0 && recoverableCredential(failure2)) return true;
6717
+ const offer = result?.offerReceipt?.outcome;
6718
+ const pushNeedsRefresh = offer?.case === "failure" ? recoverableCredential(offer.value) : result?.pushError?.status === 401;
6719
+ return pushNeedsRefresh || result?.discoveryError?.status === 401;
6720
+ }
6721
+
6710
6722
  // ../peer-office/src/runtime/credential_renewal.ts
6711
6723
  var RENEW_BEFORE_MILLIS = 5 * 6e4;
6712
6724
  var BASE64URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
@@ -6970,7 +6982,7 @@ var CredentialRecoveryDesk = class {
6970
6982
  return false;
6971
6983
  }
6972
6984
  observeSync(session, event) {
6973
- if (!syncNeedsCredentialRefresh(event) || this.#tokenless(session)) return;
6985
+ if (!syncNeedsCredentialRefresh(event.result, event.failure) || this.#tokenless(session)) return;
6974
6986
  this.#prune();
6975
6987
  const capability = this.#ports.capabilityFor(session);
6976
6988
  const existing = this.#active.get(capability);
@@ -7172,15 +7184,6 @@ var CredentialRecoveryDesk = class {
7172
7184
  this.#completed.clear();
7173
7185
  }
7174
7186
  };
7175
- function recoverableCredential(failure2) {
7176
- return failure2.code === "nomos.auth.token_expired" || failure2.code === "nomos.auth.token_missing";
7177
- }
7178
- function syncNeedsCredentialRefresh(event) {
7179
- const failures = [event.result?.pushError, event.result?.discoveryError];
7180
- if (failures.some((failure2) => failure2?.status === 401 || failure2?.status === 403)) return true;
7181
- const text2 = `${event.failure?.message ?? ""} ${failures.map((failure2) => failure2?.message ?? "").join(" ")}`.toLowerCase();
7182
- return text2.includes("unauthenticated") || text2.includes("token expired") || text2.includes("invalid token");
7183
- }
7184
7187
 
7185
7188
  // ../peer-office/src/runtime/device_identity_desk.ts
7186
7189
  import { create as create22 } from "@bufbuild/protobuf";
@@ -8098,6 +8101,7 @@ var ReceivingGroupDesk = class {
8098
8101
  #accounts = /* @__PURE__ */ new Map();
8099
8102
  /** D22: device key hash → the workspaces the console reported this key enrolled in (this process's memory, not truth). */
8100
8103
  #consoleEnrolments = /* @__PURE__ */ new Map();
8104
+ #preparingWrites = /* @__PURE__ */ new Map();
8101
8105
  #sequence = 0;
8102
8106
  #internalRequestId = 30000000000n;
8103
8107
  constructor(ports) {
@@ -8137,16 +8141,124 @@ var ReceivingGroupDesk = class {
8137
8141
  if (head === account.observedHead) return;
8138
8142
  this.#tails.set(workspace, { ...account, inFlight: false, attempts: 0, notBefore: 0n });
8139
8143
  }
8140
- /** A refused nominal Home action can wait for framework recovery and retry once.
8141
- * Sealed/pending history is never re-signed, and no child is mistaken for Home. */
8144
+ /** Only a proven non-admission can enter recovery. Console-enrolled children
8145
+ * share the owning application's route, selected by credential capability and
8146
+ * principal, never by workspace-name guessing or an unverified payload. */
8142
8147
  recoverOffer(request, response) {
8143
- if (!this.#ports.call || request.command.case !== "kernelCall" || request.command.value.credentialUse !== CredentialUse.SESSION || request.command.value.request?.operation.case !== "offer" || request.command.value.request.operation.value.intent.case !== "call" || response.outcome.case !== "failure" || !["nomos.authz.signer_enrollment_missing", "nomos.authz.device_key_revoked"].includes(response.outcome.value.code)) return;
8148
+ if (!this.#ports.call || request.command.case !== "kernelCall" || request.command.value.credentialUse !== CredentialUse.SESSION || request.command.value.request?.operation.case !== "offer" || request.command.value.request.operation.value.intent.case !== "call") return;
8149
+ const missing = response.outcome.case === "failure" ? response.outcome.value.code === "nomos.authz.signer_enrollment_missing" : response.outcome.case === "offer" && response.outcome.value.outcome.case === "refused" && response.outcome.value.outcome.value.refusal?.code === KernelRefusalCode.FORGED_PRINCIPAL && response.outcome.value.outcome.value.refusal.details?.fields.actor?.kind.case === "text" && response.outcome.value.outcome.value.refusal.details.fields.actor.kind.value === "unenrolled-signer-key";
8150
+ const revoked = response.outcome.case === "failure" && response.outcome.value.code === "nomos.authz.device_key_revoked";
8151
+ if (!missing && !revoked) return;
8144
8152
  const binding = this.#ports.binding(request.command.value.session);
8145
- const account = binding ? this.#accounts.get(binding.workspace) : void 0;
8146
- if (!account) return;
8153
+ if (!binding) return;
8154
+ const enrolled = [...this.#accounts.values()].find((account2) => {
8155
+ const owner = this.#ports.binding(account2.session);
8156
+ return account2.enrolment && owner?.credentialCapability === binding.credentialCapability && owner.principal === binding.principal;
8157
+ });
8147
8158
  const copy3 = fromBinary18(RuntimeRequestSchema, toBinary16(RuntimeRequestSchema, request));
8159
+ if (enrolled?.enrolment) {
8160
+ if (revoked) return this.#writeRefused(binding.workspace, "This device's access has been revoked.");
8161
+ return this.#begin(request, `enrolled-write-${++this.#sequence}`, (workId2) => this.#prepareEnrolledWrite(copy3, binding, enrolled.application, enrolled.enrolment, workId2));
8162
+ }
8163
+ const account = this.#accounts.get(binding.workspace);
8164
+ if (!account) return;
8148
8165
  return this.#begin(request, `receiving-group-authoring-${++this.#sequence}`, (workId2) => this.#recoverOffer(copy3, response, account, workId2));
8149
8166
  }
8167
+ #writeRefused(workspace, detail, reason = RuntimeRefusalReason.ACCESS_DENIED) {
8168
+ return { case: "refused", value: create28(RuntimeRefusalSchema, {
8169
+ reason,
8170
+ workspace,
8171
+ retryable: false,
8172
+ detail
8173
+ }) };
8174
+ }
8175
+ #writeWaiting(workspace, detail) {
8176
+ return { case: "unavailable", value: create28(RuntimeUnavailableSchema, {
8177
+ reason: RuntimeUnavailableReason.CREDENTIAL_UNAVAILABLE,
8178
+ workspace,
8179
+ retryable: true,
8180
+ retryAfterMillis: 1e3,
8181
+ detail
8182
+ }) };
8183
+ }
8184
+ *#prepareEnrolledWrite(request, binding, application, route, workId2) {
8185
+ if (request.command.case !== "kernelCall") throw new Error("write preparation lost its call");
8186
+ const command = request.command.value;
8187
+ const principal = binding.principal;
8188
+ const unavailable = () => this.#writeWaiting(
8189
+ binding.workspace,
8190
+ "This device is still being prepared to save changes. Your change has not been saved. Try again when connected."
8191
+ );
8192
+ this.#ports.emit(binding.session, { case: "writePreparation", value: create28(WritePreparationSchema, {
8193
+ requestId: command.request.requestId,
8194
+ workspace: binding.workspace
8195
+ }) });
8196
+ const key = JSON.stringify([binding.credentialCapability, principal, binding.workspace]);
8197
+ const shared = this.#preparingWrites.get(key);
8198
+ const deadline = this.#ports.clock.monotonicNanoseconds() + 30000000000n;
8199
+ let wake = 0;
8200
+ if (shared) {
8201
+ while (!shared.settled) {
8202
+ if (this.#ports.clock.monotonicNanoseconds() >= deadline) return unavailable();
8203
+ const receipt = yield { case: "wake", value: create28(PeerWakeEffectSchema, {
8204
+ effectId: `${workId2}:join-${++wake}`,
8205
+ delayMillis: 250
8206
+ }) };
8207
+ if (receipt.outcome.case !== "woken") return unavailable();
8208
+ }
8209
+ if (shared.result) return shared.result;
8210
+ } else {
8211
+ const preparation = { settled: false };
8212
+ this.#preparingWrites.set(key, preparation);
8213
+ try {
8214
+ const secret = this.#ports.authorSecretIfPresent(binding.session);
8215
+ if (!secret) return preparation.result = this.#writeRefused(binding.workspace, "Sign in again to set up this device.", RuntimeRefusalReason.INVALID_CREDENTIAL);
8216
+ const keyHash = sha256Hex(this.#ports.deriveSigningPublicKey(secret));
8217
+ let posture = this.#ports.posture(request, binding.session, principal, secret, false);
8218
+ if (posture.deviceSignerStatus === DeviceSignerStatus.REVOKED) {
8219
+ return preparation.result = this.#writeRefused(binding.workspace, "This device's access has been revoked.");
8220
+ }
8221
+ if (!posture.enrolledDevice || posture.deviceSignerStatus !== DeviceSignerStatus.ACTIVE) {
8222
+ const enrolled = yield* this.#enrolAtConsole(
8223
+ route,
8224
+ binding,
8225
+ `${application}|${principal}`,
8226
+ principal,
8227
+ keyHash,
8228
+ [binding.workspace],
8229
+ `${workId2}:console`
8230
+ );
8231
+ if (enrolled.case === "deferred") return preparation.result = enrolled.credentialRefused ? this.#writeRefused(binding.workspace, "Sign in again to set up this device.", RuntimeRefusalReason.INVALID_CREDENTIAL) : unavailable();
8232
+ if (!(binding.workspace in enrolled.value.heads)) {
8233
+ return preparation.result = this.#writeRefused(binding.workspace, "This device could not obtain access to save changes in this workspace.");
8234
+ }
8235
+ while (true) {
8236
+ posture = this.#ports.posture(request, binding.session, principal, secret, false);
8237
+ if (posture.deviceSignerStatus === DeviceSignerStatus.REVOKED) {
8238
+ return preparation.result = this.#writeRefused(binding.workspace, "This device's access has been revoked.");
8239
+ }
8240
+ if (posture.enrolledDevice && posture.deviceSignerStatus === DeviceSignerStatus.ACTIVE) break;
8241
+ if (this.#ports.clock.monotonicNanoseconds() >= deadline) return preparation.result = unavailable();
8242
+ const receipt = yield { case: "wake", value: create28(PeerWakeEffectSchema, {
8243
+ effectId: `${workId2}:observe-${++wake}`,
8244
+ delayMillis: 500
8245
+ }) };
8246
+ if (receipt.outcome.case !== "woken") return preparation.result = unavailable();
8247
+ }
8248
+ }
8249
+ } catch (error) {
8250
+ if (error instanceof ReceivingGroupRefusal) {
8251
+ return preparation.result = this.#writeRefused(binding.workspace, "This device could not obtain access to save changes in this workspace.");
8252
+ }
8253
+ preparation.result = unavailable();
8254
+ throw error;
8255
+ } finally {
8256
+ preparation.settled = true;
8257
+ this.#preparingWrites.delete(key);
8258
+ }
8259
+ }
8260
+ return { case: "retried", request, response: this.#ports.call(request, command) };
8261
+ }
8150
8262
  *#recoverOffer(request, response, account, workId2) {
8151
8263
  const workspace = this.#ports.binding(account.session).workspace;
8152
8264
  const deadline = this.#ports.clock.monotonicNanoseconds() + 60000000000n;
@@ -8214,6 +8326,7 @@ var ReceivingGroupDesk = class {
8214
8326
  this.#opening.clear();
8215
8327
  this.#accounts.clear();
8216
8328
  this.#consoleEnrolments.clear();
8329
+ this.#preparingWrites.clear();
8217
8330
  }
8218
8331
  #begin(request, workId2, procedure) {
8219
8332
  const held = {
@@ -12161,12 +12274,12 @@ var ReplicaFollowController = class {
12161
12274
  this.#desk.transition(result.workspace, { case: ReplicaFollowEventKind.WentOffline, nowUnixMillis });
12162
12275
  return delayUntilDue(this.#desk.get(result.workspace), nowUnixMillis);
12163
12276
  }
12164
- const credentialFailure = [result.pushError, result.discoveryError].find((failure2) => failure2?.status === 401 || failure2?.status === 403);
12165
- if (credentialFailure) {
12277
+ if (syncNeedsCredentialRefresh(result)) {
12278
+ const offer = result.offerReceipt?.outcome;
12166
12279
  const transition = this.#desk.transition(result.workspace, {
12167
12280
  case: ReplicaFollowEventKind.CredentialRejected,
12168
12281
  nowUnixMillis,
12169
- failure: credentialFailure.message || `remote rejected credential with HTTP ${credentialFailure.status}`
12282
+ failure: (offer?.case === "failure" ? offer.value.message : void 0) || result.pushError?.message || result.discoveryError?.message || "remote requires a refreshed credential"
12170
12283
  });
12171
12284
  if (transition.effects.some((effect) => effect.case === ReplicaFollowEffectKind.RefreshCredential)) {
12172
12285
  return 0;
@@ -14249,7 +14362,6 @@ var WorkspaceSyncPhase = Object.freeze({
14249
14362
  Done: "done"
14250
14363
  });
14251
14364
  var trackedMain = "refs/remotes/nomos/main";
14252
- var NO_COMMON_BASE = "this replica holds local history with no frontier its upstream ever confirmed; convergence needs a common admitted base \u2014 drop the local copy to refetch it, or re-discover a provider holding this lineage";
14253
14365
  var deferredRemote = "refs/remotes/nomos/deferred";
14254
14366
  var deferredLocal = "refs/nomos/sync-deferred-local";
14255
14367
  var judgedThisLifetime = /* @__PURE__ */ new Map();
@@ -14460,38 +14572,13 @@ var WorkspaceSyncWork = class {
14460
14572
  }), { case: "awaiting", requestId });
14461
14573
  }
14462
14574
  /**
14463
- * NO COMMON BASE — a round that cannot converge, and must not pay for history to find out.
14464
- *
14465
- * This replica holds a non-empty ledger but has never recorded a frontier its upstream
14466
- * confirmed (`refs/remotes/nomos/main` is absent). The kernel refuses convergence in that
14467
- * state ("a non-empty live ledger requires a common admitted base"), so every step after the
14468
- * O(1) frontier probe is wasted work — and it is not cheap waste: the fetch negotiates with
14469
- * no `have` (a full-history pack), and the dependency planner decodes EVERY intent from
14470
- * genesis and inspects every change, once per round. That is O(history) per follow round,
14471
- * repeated at every retry, for a round that can only end in a refusal.
14472
- *
14473
- * The one base this round can establish costs nothing and is established before this is
14474
- * asked: an upstream holding exactly this replica's head (the probe's answer) converges it
14475
- * and records the tracking frontier. Anything else needs the local copy to be dropped and
14476
- * refetched (an application decision, which preserves the copy), or a re-discovery that
14477
- * names a provider holding this lineage. Both are reported, at O(1), as this failure.
14478
- */
14479
- /**
14480
- * Establish this round's base when none is tracked, without walking any history it can avoid.
14481
- *
14482
- * The upstream just named its own frontier. If that commit is in THIS replica's lineage, it is
14483
- * a common admitted base by definition — both sides hold it — and adopting it turns the round
14484
- * into an ordinary fast-forward: the offer carries only the suffix above it, the fetch can name
14485
- * it as a truthful `have`, and convergence has the base the kernel requires. One commit walk
14486
- * (no change decoding, no pack, no network) decides it.
14487
- *
14488
- * If it is not in this replica's lineage, no base exists to establish and the round is refused
14489
- * (#noCommonBase) before it leases, fetches or plans anything.
14490
- *
14491
- * A kernel without the commit walk cannot be asked, so it keeps the previous behaviour.
14575
+ * Establish a cheap base when the provider's current tip is in our local chain.
14576
+ * A negative answer means the base is unknown: both sides may have advanced from
14577
+ * an earlier shared commit. Acquire the candidate and let the kernel discover
14578
+ * and judge that history. A tracking bookmark is not an admission prerequisite.
14492
14579
  */
14493
14580
  #establishBase(upstreamHead) {
14494
- if (!this.#noCommonBase() || !this.#kernel.historySummary) return true;
14581
+ if (!this.#missingTrackedBase() || !this.#kernel.historySummary) return true;
14495
14582
  const summary = this.#kernel.historySummary(this.#mount, this.#requestId, upstreamHead, this.#localHead);
14496
14583
  if (!summary.reachedBase) return false;
14497
14584
  this.#previousHead = upstreamHead;
@@ -14506,26 +14593,9 @@ var WorkspaceSyncWork = class {
14506
14593
  get establishedBase() {
14507
14594
  return this.#establishedBase;
14508
14595
  }
14509
- #noCommonBase() {
14596
+ #missingTrackedBase() {
14510
14597
  return this.#previousHead === void 0 && this.#localHead !== void 0 && this.#replaceLocalHead === void 0;
14511
14598
  }
14512
- #noCommonBaseResult() {
14513
- return this.#finish(create59(SyncWorkspaceResponseSchema, {
14514
- workspace: this.#mount.workspace,
14515
- ...this.#localHead === void 0 ? {} : { currentHead: this.#localHead },
14516
- stillAhead: true,
14517
- ...this.#offerReceipt === void 0 ? {} : { offerReceipt: this.#offerReceipt },
14518
- pushError: create59(RuntimeTransportFailureSchema, {
14519
- endpoint: this.#offerEndpoint(),
14520
- status: 409,
14521
- refused: true,
14522
- message: NO_COMMON_BASE
14523
- }),
14524
- timings: create59(SyncPhaseTimingsSchema, {
14525
- convergeMillis: elapsedMillis(this.#clock, this.#started)
14526
- })
14527
- }));
14528
- }
14529
14599
  #holdsLocalWork() {
14530
14600
  return this.#command.admit && !!this.#localHead && this.#localHead !== this.#previousHead;
14531
14601
  }
@@ -14677,7 +14747,6 @@ var WorkspaceSyncWork = class {
14677
14747
  if (!this.#desiredHead) return this.#transportFailure("resident peer returned no admitted frontier", false);
14678
14748
  this.#candidateDurable = admission.sealedMain === this.#desiredHead;
14679
14749
  if (state.phase === WorkspaceSyncPhase.Probe && this.#desiredHead !== this.#localHead) {
14680
- if (!this.#establishBase(this.#desiredHead)) return this.#noCommonBaseResult();
14681
14750
  if (this.#alreadyJudged(this.#desiredHead)) {
14682
14751
  return this.#finish(create59(SyncWorkspaceResponseSchema, {
14683
14752
  workspace: this.#mount.workspace,
@@ -14689,6 +14758,22 @@ var WorkspaceSyncWork = class {
14689
14758
  offerReceipt: this.#offerReceipt
14690
14759
  }));
14691
14760
  }
14761
+ if (!this.#establishBase(this.#desiredHead)) {
14762
+ this.#offerAfterConverge = this.#command.admit;
14763
+ this.#rebaseFrom = void 0;
14764
+ return this.#leaseEffect();
14765
+ }
14766
+ if (this.#establishedBase && !this.#candidateDurable && this.#kernel.resolveRef(this.#mount, this.#requestId, trackedMain) === void 0) {
14767
+ return this.#finish(create59(SyncWorkspaceResponseSchema, {
14768
+ workspace: this.#mount.workspace,
14769
+ currentHead: this.#localHead,
14770
+ previousHead: this.#previousHead,
14771
+ stillAhead: true,
14772
+ directOfferDeferred: true,
14773
+ reconnectRequired: false,
14774
+ offerReceipt: this.#offerReceipt
14775
+ }));
14776
+ }
14692
14777
  if (this.#probeOnly) {
14693
14778
  this.#needsReconciliation = true;
14694
14779
  return this.#finish(create59(SyncWorkspaceResponseSchema, {
@@ -14734,7 +14819,7 @@ var WorkspaceSyncWork = class {
14734
14819
  return this.#converge(this.#desiredHead, admission.resultPack.byteLength, 0);
14735
14820
  }
14736
14821
  if (this.#desiredHead === this.#previousHead) return this.#converge(this.#desiredHead, 0, 0);
14737
- if (!this.#establishBase(this.#desiredHead)) return this.#noCommonBaseResult();
14822
+ this.#establishBase(this.#desiredHead);
14738
14823
  if (admission.recoveryRequired !== false) return this.#leaseEffect();
14739
14824
  return this.#transportFailure("resident peer supplied neither the missing delta nor a history gap", false);
14740
14825
  }
@@ -14957,7 +15042,7 @@ var WorkspaceSyncWork = class {
14957
15042
  }
14958
15043
  }
14959
15044
  #converge(candidateHead, receivedBytes, prefetchMillis) {
14960
- if (!this.#establishBase(candidateHead)) return this.#noCommonBaseResult();
15045
+ this.#establishBase(candidateHead);
14961
15046
  this.#beforeConverge?.(candidateHead, this.#previousHead);
14962
15047
  const convergeStarted = this.#clock.monotonicNanoseconds();
14963
15048
  let judged;
@@ -17402,13 +17487,21 @@ var CorrespondenceDesk = class {
17402
17487
  }
17403
17488
  #observeSyncResult(requestId, workId2, result) {
17404
17489
  const timings = result.timings;
17490
+ const receipt = result.offerReceipt?.outcome;
17491
+ const admission = receipt?.case === "admission" ? receipt.value : void 0;
17405
17492
  this.#events.instant("peer.follow.sync-result", {
17406
17493
  request: create64(RuntimeRequestSchema, { protocolVersion: 2, requestId }),
17407
17494
  workspace: result.workspace
17408
17495
  }, {
17409
17496
  "sync.workId": workId2,
17410
17497
  ...result.currentHead ? { "sync.head": result.currentHead } : {},
17498
+ ...result.previousHead ? { "sync.previousHead": result.previousHead } : {},
17499
+ ...admission?.main ? { "sync.providerHead": admission.main } : {},
17500
+ ...admission?.sealedMain ? { "sync.sealedHead": admission.sealedMain } : {},
17411
17501
  "sync.stillAhead": result.stillAhead,
17502
+ "sync.reconnectRequired": result.reconnectRequired,
17503
+ "sync.refused": result.refused,
17504
+ "sync.deferred": result.deferred,
17412
17505
  "sync.directOfferDeferred": result.directOfferDeferred,
17413
17506
  "sync.offline": result.offline,
17414
17507
  ...timings ? {
@@ -20494,6 +20587,7 @@ var PeerOffice = class {
20494
20587
  return this.#responses.modelAdoption(request, step);
20495
20588
  }
20496
20589
  #receivingGroupResponse(request, step) {
20590
+ if (step.case === "refused") return this.#response(request, { case: "refused", value: step.value });
20497
20591
  if (step.case === "retried") return this.#birthCustodyResponse(step.request, this.#birthCustody.afterKernelCall(step.request, step.response));
20498
20592
  if (step.case === "pending") return this.#response(request, { case: "correspondencePending", value: step.value });
20499
20593
  if (step.case === "failure") return this.#failure(request, step.code, step.message);