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 +43 -0
- package/dist/compile_mountability_entry.js +141 -20
- package/dist/conformance-fixture/domains/booking.ts +72 -0
- package/dist/conformance-fixture/nomos.project.ts +1 -0
- package/dist/conformance-probe.mjs +69 -0
- package/dist/dev-server.mjs +133 -19
- package/dist/full-cli.mjs +382 -83
- package/package.json +2 -2
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+
|
|
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
|
-
/**
|
|
10460
|
-
*
|
|
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"
|
|
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
|
-
|
|
10465
|
-
|
|
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
|
-
|
|
14695
|
-
|
|
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:
|
|
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);
|