githolon 0.111.0 → 0.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Nomos developer CLI
2
+
3
+ Compile a domain with `npx githolon compile` and run its generated Dart scenarios
4
+ with `npx githolon test`. Each command has a focused `--help` page.
5
+
6
+ ## Check an installed stack
7
+
8
+ From a consumer project with `githolon`, `@githolon/dsl` and `@githolon/testing`
9
+ installed, run:
10
+
11
+ ```sh
12
+ npx githolon conformance
13
+ ```
14
+
15
+ The command reports the installed CLI, compiler, runtime and testing package
16
+ versions and the kernel SHA-256 actually used. It compiles an isolated generated
17
+ booking application with your installed compiler, then uses the existing real
18
+ runtime harness to check a write, indexed and direct reads, an expected refusal
19
+ with no effect, persisted Git history, and a cold restore followed by another
20
+ write. It removes its temporary application and custody after the check.
21
+
22
+ For CI, use `npx githolon conformance --json`. Exit status is 0 when all checks
23
+ pass, 1 for a failed check, and 2 for invalid command options. A failure names the
24
+ stage, diagnostic and next action. The JSON report includes `passed`, `packages`,
25
+ `runtime`, `checks` and, on failure, `failure`.
26
+
27
+ First use may download verified runtime artifacts. `--offline` forbids runtime
28
+ acquisition from the network. To select an existing verified bundle explicitly:
29
+
30
+ ```sh
31
+ npx githolon conformance --offline --runtime /path/to/runtime --json
32
+ ```
33
+
34
+ The bundle contains `holon.wasm`, `kernel.repository.xml`, `bootstrap.law.usdz`
35
+ and `nomos.law.usdz`; the existing runtime loader verifies compatibility and
36
+ content identity. An invalid explicitly selected bundle fails rather than
37
+ switching to a cached one.
38
+
39
+ This checks the installed Node stack using a standard generated application.
40
+ It does not run your application's own acceptance tests or qualify Flutter,
41
+ cloud deployment or physical devices. Cold restore checks usable data and
42
+ persisted history; the report says when deeper history verification is still
43
+ materialising, rather than claiming a full historical audit.
@@ -3349,7 +3349,7 @@ var init_recovery_desk_pb = __esm({
3349
3349
  // ../adapter/proto/nomos/runtime/v2/observability_desk_pb.js
3350
3350
  import { enumDesc as enumDesc15, fileDesc as fileDesc22, messageDesc as messageDesc22, tsEnum as tsEnum15 } from "@bufbuild/protobuf/codegenv2";
3351
3351
  import { file_google_protobuf_any as file_google_protobuf_any2 } from "@bufbuild/protobuf/wkt";
3352
- var file_nomos_runtime_v2_observability_desk, RuntimeFailureSchema, RuntimeUnavailableSchema, RuntimeRefusalSchema, DiagnosticAttributeSchema, RuntimeEventSchema, FollowsSummarySchema, FollowObservationSchema, CredentialRefreshRequestedSchema, RuntimeReadySchema, WatchChangedSchema, SyncCompletedSchema, LinkChangedSchema, RuntimeSpanSchema, RuntimeFailureKindSchema, RuntimeFailureKind, RuntimeUnavailableReasonSchema, RuntimeUnavailableReason, RuntimeRefusalReasonSchema, RuntimeRefusalReason, FollowObservationPhaseSchema, FollowObservationPhase, LinkStatusSchema, LinkStatus;
3352
+ var file_nomos_runtime_v2_observability_desk, RuntimeFailureSchema, RuntimeUnavailableSchema, RuntimeRefusalSchema, DiagnosticAttributeSchema, RuntimeEventSchema, FollowsSummarySchema, FollowObservationSchema, CredentialRefreshRequestedSchema, RuntimeReadySchema, WatchChangedSchema, SyncCompletedSchema, LinkChangedSchema, RuntimeSpanSchema, WritePreparationSchema, RuntimeFailureKindSchema, RuntimeFailureKind, RuntimeUnavailableReasonSchema, RuntimeUnavailableReason, RuntimeRefusalReasonSchema, RuntimeRefusalReason, FollowObservationPhaseSchema, FollowObservationPhase, LinkStatusSchema, LinkStatus;
3353
3353
  var init_observability_desk_pb = __esm({
3354
3354
  "../adapter/proto/nomos/runtime/v2/observability_desk_pb.js"() {
3355
3355
  "use strict";
@@ -3361,7 +3361,7 @@ var init_observability_desk_pb = __esm({
3361
3361
  init_model_adoption_desk_pb();
3362
3362
  init_receiving_group_desk_pb();
3363
3363
  init_recovery_desk_pb();
3364
- file_nomos_runtime_v2_observability_desk = /* @__PURE__ */ fileDesc22("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]);
3364
+ file_nomos_runtime_v2_observability_desk = /* @__PURE__ */ fileDesc22("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]);
3365
3365
  RuntimeFailureSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 1);
3366
3366
  RuntimeUnavailableSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 2);
3367
3367
  RuntimeRefusalSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 3);
@@ -3375,6 +3375,7 @@ var init_observability_desk_pb = __esm({
3375
3375
  SyncCompletedSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 11);
3376
3376
  LinkChangedSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 12);
3377
3377
  RuntimeSpanSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 15);
3378
+ WritePreparationSchema = /* @__PURE__ */ messageDesc22(file_nomos_runtime_v2_observability_desk, 18);
3378
3379
  RuntimeFailureKindSchema = /* @__PURE__ */ enumDesc15(file_nomos_runtime_v2_observability_desk, 0);
3379
3380
  RuntimeFailureKind = /* @__PURE__ */ tsEnum15(RuntimeFailureKindSchema);
3380
3381
  RuntimeUnavailableReasonSchema = /* @__PURE__ */ enumDesc15(file_nomos_runtime_v2_observability_desk, 1);
@@ -8915,6 +8916,22 @@ var init_credential_sessions = __esm({
8915
8916
  }
8916
8917
  });
8917
8918
 
8919
+ // ../peer-office/src/runtime/credential_failure.ts
8920
+ function recoverableCredential(failure) {
8921
+ return failure.code === "nomos.auth.token_expired" || failure.code === "nomos.auth.token_missing";
8922
+ }
8923
+ function syncNeedsCredentialRefresh(result, failure) {
8924
+ if (failure !== void 0 && recoverableCredential(failure)) return true;
8925
+ const offer = result?.offerReceipt?.outcome;
8926
+ const pushNeedsRefresh = offer?.case === "failure" ? recoverableCredential(offer.value) : result?.pushError?.status === 401;
8927
+ return pushNeedsRefresh || result?.discoveryError?.status === 401;
8928
+ }
8929
+ var init_credential_failure = __esm({
8930
+ "../peer-office/src/runtime/credential_failure.ts"() {
8931
+ "use strict";
8932
+ }
8933
+ });
8934
+
8918
8935
  // ../peer-office/src/runtime/credential_renewal.ts
8919
8936
  function identityTokenClaim(token, claim) {
8920
8937
  const claims = tokenClaims(token);
@@ -9113,19 +9130,11 @@ var init_sha256 = __esm({
9113
9130
 
9114
9131
  // ../peer-office/src/runtime/credential_recovery_desk.ts
9115
9132
  import { create as create16, fromBinary as fromBinary9, toBinary as toBinary8 } from "@bufbuild/protobuf";
9116
- function recoverableCredential(failure) {
9117
- return failure.code === "nomos.auth.token_expired" || failure.code === "nomos.auth.token_missing";
9118
- }
9119
- function syncNeedsCredentialRefresh(event) {
9120
- const failures = [event.result?.pushError, event.result?.discoveryError];
9121
- if (failures.some((failure) => failure?.status === 401 || failure?.status === 403)) return true;
9122
- const text = `${event.failure?.message ?? ""} ${failures.map((failure) => failure?.message ?? "").join(" ")}`.toLowerCase();
9123
- return text.includes("unauthenticated") || text.includes("token expired") || text.includes("invalid token");
9124
- }
9125
9133
  var CredentialRecoveryDesk;
9126
9134
  var init_credential_recovery_desk = __esm({
9127
9135
  "../peer-office/src/runtime/credential_recovery_desk.ts"() {
9128
9136
  "use strict";
9137
+ init_credential_failure();
9129
9138
  init_kernel_pb();
9130
9139
  init_correspondence_desk_pb();
9131
9140
  init_credentials_desk_pb();
@@ -9210,7 +9219,7 @@ var init_credential_recovery_desk = __esm({
9210
9219
  return false;
9211
9220
  }
9212
9221
  observeSync(session, event) {
9213
- if (!syncNeedsCredentialRefresh(event) || this.#tokenless(session)) return;
9222
+ if (!syncNeedsCredentialRefresh(event.result, event.failure) || this.#tokenless(session)) return;
9214
9223
  this.#prune();
9215
9224
  const capability = this.#ports.capabilityFor(session);
9216
9225
  const existing = this.#active.get(capability);
@@ -10417,6 +10426,7 @@ var init_receiving_group_desk = __esm({
10417
10426
  #accounts = /* @__PURE__ */ new Map();
10418
10427
  /** D22: device key hash → the workspaces the console reported this key enrolled in (this process's memory, not truth). */
10419
10428
  #consoleEnrolments = /* @__PURE__ */ new Map();
10429
+ #preparingWrites = /* @__PURE__ */ new Map();
10420
10430
  #sequence = 0;
10421
10431
  #internalRequestId = 30000000000n;
10422
10432
  constructor(ports) {
@@ -10456,16 +10466,124 @@ var init_receiving_group_desk = __esm({
10456
10466
  if (head === account.observedHead) return;
10457
10467
  this.#tails.set(workspace, { ...account, inFlight: false, attempts: 0, notBefore: 0n });
10458
10468
  }
10459
- /** A refused nominal Home action can wait for framework recovery and retry once.
10460
- * Sealed/pending history is never re-signed, and no child is mistaken for Home. */
10469
+ /** Only a proven non-admission can enter recovery. Console-enrolled children
10470
+ * share the owning application's route, selected by credential capability and
10471
+ * principal, never by workspace-name guessing or an unverified payload. */
10461
10472
  recoverOffer(request, response) {
10462
- 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;
10473
+ 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;
10474
+ 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";
10475
+ const revoked = response.outcome.case === "failure" && response.outcome.value.code === "nomos.authz.device_key_revoked";
10476
+ if (!missing && !revoked) return;
10463
10477
  const binding = this.#ports.binding(request.command.value.session);
10464
- const account = binding ? this.#accounts.get(binding.workspace) : void 0;
10465
- if (!account) return;
10478
+ if (!binding) return;
10479
+ const enrolled = [...this.#accounts.values()].find((account2) => {
10480
+ const owner = this.#ports.binding(account2.session);
10481
+ return account2.enrolment && owner?.credentialCapability === binding.credentialCapability && owner.principal === binding.principal;
10482
+ });
10466
10483
  const copy3 = fromBinary14(RuntimeRequestSchema, toBinary11(RuntimeRequestSchema, request));
10484
+ if (enrolled?.enrolment) {
10485
+ if (revoked) return this.#writeRefused(binding.workspace, "This device's access has been revoked.");
10486
+ return this.#begin(request, `enrolled-write-${++this.#sequence}`, (workId2) => this.#prepareEnrolledWrite(copy3, binding, enrolled.application, enrolled.enrolment, workId2));
10487
+ }
10488
+ const account = this.#accounts.get(binding.workspace);
10489
+ if (!account) return;
10467
10490
  return this.#begin(request, `receiving-group-authoring-${++this.#sequence}`, (workId2) => this.#recoverOffer(copy3, response, account, workId2));
10468
10491
  }
10492
+ #writeRefused(workspace, detail, reason = RuntimeRefusalReason.ACCESS_DENIED) {
10493
+ return { case: "refused", value: create23(RuntimeRefusalSchema, {
10494
+ reason,
10495
+ workspace,
10496
+ retryable: false,
10497
+ detail
10498
+ }) };
10499
+ }
10500
+ #writeWaiting(workspace, detail) {
10501
+ return { case: "unavailable", value: create23(RuntimeUnavailableSchema, {
10502
+ reason: RuntimeUnavailableReason.CREDENTIAL_UNAVAILABLE,
10503
+ workspace,
10504
+ retryable: true,
10505
+ retryAfterMillis: 1e3,
10506
+ detail
10507
+ }) };
10508
+ }
10509
+ *#prepareEnrolledWrite(request, binding, application, route, workId2) {
10510
+ if (request.command.case !== "kernelCall") throw new Error("write preparation lost its call");
10511
+ const command = request.command.value;
10512
+ const principal = binding.principal;
10513
+ const unavailable = () => this.#writeWaiting(
10514
+ binding.workspace,
10515
+ "This device is still being prepared to save changes. Your change has not been saved. Try again when connected."
10516
+ );
10517
+ this.#ports.emit(binding.session, { case: "writePreparation", value: create23(WritePreparationSchema, {
10518
+ requestId: command.request.requestId,
10519
+ workspace: binding.workspace
10520
+ }) });
10521
+ const key2 = JSON.stringify([binding.credentialCapability, principal, binding.workspace]);
10522
+ const shared = this.#preparingWrites.get(key2);
10523
+ const deadline = this.#ports.clock.monotonicNanoseconds() + 30000000000n;
10524
+ let wake = 0;
10525
+ if (shared) {
10526
+ while (!shared.settled) {
10527
+ if (this.#ports.clock.monotonicNanoseconds() >= deadline) return unavailable();
10528
+ const receipt = yield { case: "wake", value: create23(PeerWakeEffectSchema, {
10529
+ effectId: `${workId2}:join-${++wake}`,
10530
+ delayMillis: 250
10531
+ }) };
10532
+ if (receipt.outcome.case !== "woken") return unavailable();
10533
+ }
10534
+ if (shared.result) return shared.result;
10535
+ } else {
10536
+ const preparation = { settled: false };
10537
+ this.#preparingWrites.set(key2, preparation);
10538
+ try {
10539
+ const secret = this.#ports.authorSecretIfPresent(binding.session);
10540
+ if (!secret) return preparation.result = this.#writeRefused(binding.workspace, "Sign in again to set up this device.", RuntimeRefusalReason.INVALID_CREDENTIAL);
10541
+ const keyHash = sha256Hex(this.#ports.deriveSigningPublicKey(secret));
10542
+ let posture = this.#ports.posture(request, binding.session, principal, secret, false);
10543
+ if (posture.deviceSignerStatus === DeviceSignerStatus.REVOKED) {
10544
+ return preparation.result = this.#writeRefused(binding.workspace, "This device's access has been revoked.");
10545
+ }
10546
+ if (!posture.enrolledDevice || posture.deviceSignerStatus !== DeviceSignerStatus.ACTIVE) {
10547
+ const enrolled = yield* this.#enrolAtConsole(
10548
+ route,
10549
+ binding,
10550
+ `${application}|${principal}`,
10551
+ principal,
10552
+ keyHash,
10553
+ [binding.workspace],
10554
+ `${workId2}:console`
10555
+ );
10556
+ 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();
10557
+ if (!(binding.workspace in enrolled.value.heads)) {
10558
+ return preparation.result = this.#writeRefused(binding.workspace, "This device could not obtain access to save changes in this workspace.");
10559
+ }
10560
+ while (true) {
10561
+ posture = this.#ports.posture(request, binding.session, principal, secret, false);
10562
+ if (posture.deviceSignerStatus === DeviceSignerStatus.REVOKED) {
10563
+ return preparation.result = this.#writeRefused(binding.workspace, "This device's access has been revoked.");
10564
+ }
10565
+ if (posture.enrolledDevice && posture.deviceSignerStatus === DeviceSignerStatus.ACTIVE) break;
10566
+ if (this.#ports.clock.monotonicNanoseconds() >= deadline) return preparation.result = unavailable();
10567
+ const receipt = yield { case: "wake", value: create23(PeerWakeEffectSchema, {
10568
+ effectId: `${workId2}:observe-${++wake}`,
10569
+ delayMillis: 500
10570
+ }) };
10571
+ if (receipt.outcome.case !== "woken") return preparation.result = unavailable();
10572
+ }
10573
+ }
10574
+ } catch (error) {
10575
+ if (error instanceof ReceivingGroupRefusal) {
10576
+ return preparation.result = this.#writeRefused(binding.workspace, "This device could not obtain access to save changes in this workspace.");
10577
+ }
10578
+ preparation.result = unavailable();
10579
+ throw error;
10580
+ } finally {
10581
+ preparation.settled = true;
10582
+ this.#preparingWrites.delete(key2);
10583
+ }
10584
+ }
10585
+ return { case: "retried", request, response: this.#ports.call(request, command) };
10586
+ }
10469
10587
  *#recoverOffer(request, response, account, workId2) {
10470
10588
  const workspace = this.#ports.binding(account.session).workspace;
10471
10589
  const deadline = this.#ports.clock.monotonicNanoseconds() + 60000000000n;
@@ -10533,6 +10651,7 @@ var init_receiving_group_desk = __esm({
10533
10651
  this.#opening.clear();
10534
10652
  this.#accounts.clear();
10535
10653
  this.#consoleEnrolments.clear();
10654
+ this.#preparingWrites.clear();
10536
10655
  }
10537
10656
  #begin(request, workId2, procedure) {
10538
10657
  const held = {
@@ -14424,6 +14543,7 @@ var init_replica_follow_controller = __esm({
14424
14543
  init_replica_follow_state();
14425
14544
  init_local_copy_readability();
14426
14545
  init_placement_desk();
14546
+ init_credential_failure();
14427
14547
  ReplicaFollowReconciliationKind = Object.freeze({
14428
14548
  Following: "following",
14429
14549
  NotFollowing: "not_following"
@@ -14691,12 +14811,12 @@ var init_replica_follow_controller = __esm({
14691
14811
  this.#desk.transition(result.workspace, { case: ReplicaFollowEventKind.WentOffline, nowUnixMillis });
14692
14812
  return delayUntilDue(this.#desk.get(result.workspace), nowUnixMillis);
14693
14813
  }
14694
- const credentialFailure = [result.pushError, result.discoveryError].find((failure) => failure?.status === 401 || failure?.status === 403);
14695
- if (credentialFailure) {
14814
+ if (syncNeedsCredentialRefresh(result)) {
14815
+ const offer = result.offerReceipt?.outcome;
14696
14816
  const transition = this.#desk.transition(result.workspace, {
14697
14817
  case: ReplicaFollowEventKind.CredentialRejected,
14698
14818
  nowUnixMillis,
14699
- failure: credentialFailure.message || `remote rejected credential with HTTP ${credentialFailure.status}`
14819
+ failure: (offer?.case === "failure" ? offer.value.message : void 0) || result.pushError?.message || result.discoveryError?.message || "remote requires a refreshed credential"
14700
14820
  });
14701
14821
  if (transition.effects.some((effect) => effect.case === ReplicaFollowEffectKind.RefreshCredential)) {
14702
14822
  return 0;
@@ -23412,6 +23532,7 @@ var init_peer_office = __esm({
23412
23532
  return this.#responses.modelAdoption(request, step);
23413
23533
  }
23414
23534
  #receivingGroupResponse(request, step) {
23535
+ if (step.case === "refused") return this.#response(request, { case: "refused", value: step.value });
23415
23536
  if (step.case === "retried") return this.#birthCustodyResponse(step.request, this.#birthCustody.afterKernelCall(step.request, step.response));
23416
23537
  if (step.case === "pending") return this.#response(request, { case: "correspondencePending", value: step.value });
23417
23538
  if (step.case === "failure") return this.#failure(request, step.code, step.message);
@@ -0,0 +1,72 @@
1
+ // THE HEADLINE FIXTURE — a law with a REAL aggregate invariant (#41: declared
2
+ // invariants run at the gate). `@githolon/testing`'s own tests prove the
3
+ // promise: `expect(app.takeSeat(...)).rejects.toThrow(/seats-exceed-capacity/)`.
4
+ import { z, aggregate, t, Lww, MapOf, directive, create, idOf, refOf, instance, setEntry, query, valueObject } from "@githolon/dsl";
5
+
6
+ const Seat = valueObject("Seat", {
7
+ status: z.enum(["active", "cancelled"]),
8
+ takenAt: z.string(),
9
+ });
10
+
11
+ export const Booking = aggregate(
12
+ "Booking",
13
+ {
14
+ label: t.string().merge(Lww),
15
+ capacity: t.int().merge(Lww),
16
+ seats: t.map(Seat.field()).merge(MapOf(Lww)),
17
+ },
18
+ {
19
+ /** ACTIVE SEATS ≤ CAPACITY — the declared aggregate invariant. */
20
+ invariant: (snap) => {
21
+ const capacity = typeof snap["capacity"] === "number" ? (snap["capacity"] as number) : 0;
22
+ const seats = snap["seats"];
23
+ let active = 0;
24
+ if (seats && typeof seats === "object") {
25
+ for (const seat of Object.values(seats as Record<string, { status?: string }>)) {
26
+ if (seat.status === "active") active += 1;
27
+ }
28
+ }
29
+ return active > capacity ? { reject: "seats-exceed-capacity" } : { accept: true };
30
+ },
31
+ },
32
+ ).public();
33
+
34
+ export const openBooking = directive("openBooking")
35
+ .creates(Booking)
36
+ .payload(z.object({ label: z.string().min(1), capacity: z.number().int() }))
37
+ .plan((p) => {
38
+ create(Booking).set("label", p.label).set("capacity", p.capacity);
39
+ return [];
40
+ });
41
+
42
+ export const takeSeat = directive("takeSeat")
43
+ .mutates(Booking)
44
+ .payload(z.object({ bookingId: idOf(Booking), attendee: z.string().min(1), takenAt: z.string() }))
45
+ .plan((p) => [
46
+ setEntry(
47
+ instance(Booking, p.bookingId),
48
+ "seats",
49
+ p.attendee,
50
+ { status: "active", takenAt: p.takenAt },
51
+ ),
52
+ ]);
53
+
54
+ export const bookingsByLabel = query("bookingsByLabel").key("label").returns(Booking);
55
+
56
+ // Exercise full addresses and explicit null through the generated facade,
57
+ // real offers, custody and query-result decoder, not a hand-built response.
58
+ export const ReferenceCard = aggregate("ReferenceCard", {
59
+ label: t.string().merge(Lww),
60
+ booking: t.nomosRef(Booking).merge(Lww),
61
+ note: t.nullable(t.string().merge(Lww), { reason: "A card may explicitly have no note" }),
62
+ }).public();
63
+
64
+ export const createReferenceCard = directive("createReferenceCard")
65
+ .creates(ReferenceCard)
66
+ .payload(z.object({ label: z.string(), booking: refOf(Booking), note: z.string().nullable() }))
67
+ .plan((p) => {
68
+ create(ReferenceCard).set("label", p.label).set("booking", p.booking).set("note", p.note);
69
+ return [];
70
+ });
71
+
72
+ export const referenceCardsByLabel = query("referenceCardsByLabel").key("label").returns(ReferenceCard);
@@ -0,0 +1 @@
1
+ export default { name: "seats", domains: [{ key: "seats", features: [{ key: "seats", modules: ["./domains/booking.ts"] }] }] };
@@ -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);