@githolon/dsl 0.108.6 → 0.110.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/assets/operation-contract.wasm +0 -0
- package/check_package.mjs +12 -15
- package/compile_package.mjs +17 -18
- package/compile_proof.mjs +16 -1
- package/dart/CHANGELOG.md +76 -1
- package/dart/README.md +25 -2
- package/dart/lib/src/admission_decision.dart +41 -0
- package/dart/lib/src/application_framework_calls.dart +52 -2
- package/dart/lib/src/application_model_adoption.dart +187 -0
- package/dart/lib/src/application_status.dart +73 -0
- package/dart/lib/src/console_enrolment.dart +271 -0
- package/dart/lib/src/console_http_io.dart +26 -0
- package/dart/lib/src/console_http_stub.dart +7 -0
- package/dart/lib/src/dev_cloud.dart +69 -22
- package/dart/lib/src/generated_call.dart +83 -23
- package/dart/lib/src/kernel_primitives.dart +119 -0
- package/dart/lib/src/nms_conformance_runtime.dart +1 -1
- package/dart/lib/src/nms_generated_runtime.dart +32 -10
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/node_runner_transport.dart +41 -46
- package/dart/lib/src/observed_session_directory.dart +70 -0
- package/dart/lib/src/operation_receipts.dart +112 -0
- package/dart/lib/src/peer_application_streams.dart +103 -0
- package/dart/lib/src/reception/dart_reception.dart +4280 -0
- package/dart/lib/src/reception/event_desk.dart +211 -0
- package/dart/lib/src/reception/extremum_read.dart +46 -0
- package/dart/lib/src/reception/local_copies.dart +371 -0
- package/dart/lib/src/reception/peer_office_connection.dart +11 -0
- package/dart/lib/src/reception/progress_desk.dart +267 -0
- package/dart/lib/src/reception/reception_contract.dart +11 -0
- package/dart/lib/src/reception/reception_session.dart +284 -0
- package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
- package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
- package/dart/lib/src/replica_readiness.dart +123 -0
- package/dart/lib/src/runner/node-entry.mjs +23905 -15774
- package/dart/lib/src/runtime_v2_gateway.dart +56 -3
- package/dart/lib/src/runtime_v2_transport.dart +544 -3
- package/dart/lib/src/session_bound.dart +200 -311
- package/dart/lib/src/signing_identity_kernel.dart +84 -0
- package/dart/lib/src/sync_status_projection.dart +548 -0
- package/dart/lib/src/sync_status_reducer.dart +170 -0
- package/dart/lib/src/test_harness.dart +809 -1153
- package/dart/lib/src/testing/test_custody.dart +66 -0
- package/dart/lib/src/testing/test_peer.dart +328 -0
- package/dart/lib/src/typed_watch_registry.dart +169 -0
- package/dart/lib/src/workspace_open_progress.dart +27 -0
- package/dart/pubspec.lock +24 -1
- package/dart/pubspec.yaml +7 -2
- package/dart/pubspec_overrides.yaml +2 -0
- package/dart/test/admission_decision_test.dart +48 -0
- package/dart/test/background_model_adoption_test.dart +228 -0
- package/dart/test/bundle_version_pairing_test.dart +4 -4
- package/dart/test/child_authentication_repair_test.dart +359 -0
- package/dart/test/cloud_bound_local_shell_test.dart +119 -0
- package/dart/test/console_enrolment_refusal_test.dart +52 -0
- package/dart/test/console_enrolment_test.dart +227 -0
- package/dart/test/errors_test.dart +5 -5
- package/dart/test/event_plane_seam_test.dart +50 -164
- package/dart/test/extremum_read_test.dart +58 -0
- package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
- package/dart/test/generated_query_test.dart +32 -0
- package/dart/test/harness_phase_timeout_test.dart +18 -23
- package/dart/test/kernel_author_after_read_test.dart +242 -0
- package/dart/test/kernel_fence_test.dart +137 -0
- package/dart/test/local_copies_test.dart +222 -0
- package/dart/test/model_adoption_test.dart +198 -0
- package/dart/test/node_peer_local_custody_test.dart +153 -0
- package/dart/test/offer_authentication_proof_test.dart +352 -52
- package/dart/test/operation_compatibility_test.dart +151 -0
- package/dart/test/platform_credential_effect_test.dart +386 -0
- package/dart/test/receiving_group_open_test.dart +213 -0
- package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
- package/dart/test/reception_span_trace_test.dart +23 -0
- package/dart/test/replica_readiness_test.dart +156 -0
- package/dart/test/runtime_projections_test.dart +92 -0
- package/dart/test/runtime_v2_gateway_test.dart +131 -0
- package/dart/test/signing_identity_kernel_test.dart +75 -0
- package/dart/test/sync_status_preparation_report_test.dart +29 -0
- package/dart/test/sync_status_reducer_test.dart +419 -0
- package/dart/test/test_harness_test.dart +71 -95
- package/dart/test/typed_query_watch_test.dart +170 -0
- package/dart/test/typed_watch_registry_test.dart +249 -0
- package/dart_lints/README.md +18 -0
- package/dart_lints/lib/nomos_lints.dart +70 -0
- package/dart_lints/pubspec.lock +580 -0
- package/dart_lints/pubspec.yaml +12 -0
- package/dart_lints/test/reference_identity_test.dart +75 -0
- package/dart_types/CHANGELOG.md +18 -0
- package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
- package/dart_types/lib/nomos_types.dart +9 -1
- package/dart_types/lib/src/admission_decision.dart +37 -0
- package/dart_types/lib/src/aggregate_meta.dart +1 -1
- package/dart_types/lib/src/approved_model.dart +65 -0
- package/dart_types/lib/src/custody.dart +10 -18
- package/dart_types/lib/src/error_info.dart +4 -4
- package/dart_types/lib/src/errors.dart +29 -29
- package/dart_types/lib/src/foreign_ref.dart +62 -33
- package/dart_types/lib/src/local_work_rejected.dart +3 -3
- package/dart_types/lib/src/nomos_ref.dart +3 -1
- package/dart_types/lib/src/principal.dart +2 -2
- package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
- package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/runtime_outcome.dart +133 -0
- package/dart_types/lib/src/subscriptions.dart +116 -23
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/extremum_subscriptions_test.dart +40 -0
- package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
- package/dart_types/test/nomos_ref_address_test.dart +25 -0
- package/dart_types/test/ordered_subscriptions_test.dart +34 -0
- package/operation_contract_check.mjs +24 -0
- package/package.json +11 -6
- package/src/aggregate.ts +70 -10
- package/src/application_topology.ts +18 -11
- package/src/attested.ts +3 -0
- package/src/attested_core.ts +46 -3
- package/src/birth_meter_ensure.ts +19 -7
- package/src/births.ts +29 -4
- package/src/build_package.ts +140 -13
- package/src/business_birth.ts +181 -4
- package/src/codegen_call_proto.ts +1274 -0
- package/src/codegen_call_usda.ts +49 -6
- package/src/codegen_dart.ts +79 -44
- package/src/codegen_dart_client.ts +458 -800
- package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
- package/src/codegen_dart_framework_calls.ts +320 -37
- package/src/codegen_dart_indexed_variant.ts +159 -0
- package/src/codegen_dart_scenario.ts +42 -13
- package/src/codegen_proof.ts +3 -3
- package/src/codegen_provider_dart.ts +5 -0
- package/src/codegen_query_proto.ts +158 -0
- package/src/codegen_refusal.ts +189 -0
- package/src/codegen_result_proto.ts +931 -0
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +464 -616
- package/src/codegen_workspace_access.ts +105 -0
- package/src/compatibility_graph.ts +759 -0
- package/src/compatibility_usda.ts +264 -0
- package/src/compile_package_main.ts +2083 -1248
- package/src/custody_placement.ts +156 -0
- package/src/custody_placement_usda.ts +91 -0
- package/src/decl_shapes.ts +21 -2
- package/src/describe_model.ts +1 -0
- package/src/directive.ts +59 -2
- package/src/drivers.ts +51 -0
- package/src/engine_entry.ts +52 -8
- package/src/evolve_preview.ts +11 -4
- package/src/exists.ts +2 -0
- package/src/fields.ts +75 -11
- package/src/flow_gate.ts +2 -1
- package/src/framework/application_home.ts +170 -18
- package/src/framework/attested_receipts.ts +8 -3
- package/src/framework/auth_provider_law.ts +169 -9
- package/src/framework/birth_certificate_law.ts +4 -0
- package/src/framework/capability.ts +34 -3
- package/src/framework/child_authentication.ts +346 -0
- package/src/framework/console_governance.ts +295 -0
- package/src/framework/delegated_roles.ts +301 -0
- package/src/framework/domain_lifecycle.ts +26 -13
- package/src/framework/founding_genesis.ts +193 -0
- package/src/framework/framework_aggregates.ts +1 -1
- package/src/framework/genesis.ts +6 -1
- package/src/framework/governance_relations.ts +19 -0
- package/src/framework/home.ts +5 -734
- package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
- package/src/framework/model_authority_repair.ts +116 -0
- package/src/framework/model_authority_seed.ts +185 -0
- package/src/framework/model_transition.ts +211 -0
- package/src/framework/owned_custody.ts +1 -1
- package/src/framework/principal_enrollment.ts +302 -0
- package/src/framework/receiving_group.ts +857 -0
- package/src/framework/receiving_group_recovery.ts +314 -0
- package/src/framework/relations.ts +4 -8
- package/src/framework/signing_identity.ts +242 -95
- package/src/framework/source_roster.ts +11 -5
- package/src/framework/workspace_access.ts +149 -0
- package/src/framework/workspace_invariant.ts +73 -52
- package/src/framework/workspaces.ts +407 -40
- package/src/framework_call_definitions.ts +32 -3
- package/src/generated_client_bundle_boundary.ts +97 -0
- package/src/generated_client_names.ts +1 -0
- package/src/identity_usda.ts +27 -0
- package/src/index.ts +183 -12
- package/src/indexed_variant.ts +83 -0
- package/src/intent.ts +173 -45
- package/src/law_check.ts +8 -5
- package/src/law_dependency_index.ts +231 -0
- package/src/law_graph.ts +508 -71
- package/src/law_graph_usda.ts +170 -24
- package/src/law_identity.ts +119 -81
- package/src/law_source_map.ts +4 -1
- package/src/law_units.ts +498 -0
- package/src/law_value_type.ts +7 -3
- package/src/member_authentication.ts +302 -0
- package/src/null_meta.ts +1 -1
- package/src/openusd_compiled_layer.ts +132 -0
- package/src/operation_contract_check.ts +31 -0
- package/src/ordered_read.ts +2 -1
- package/src/package_config.ts +33 -12
- package/src/package_dependencies.ts +1 -0
- package/src/plan_source_slice.ts +30 -1
- package/src/protobuf_field_number.ts +36 -0
- package/src/provenance_wire.ts +6 -0
- package/src/query.ts +2 -1
- package/src/read.ts +50 -0
- package/src/relation.ts +4 -1
- package/src/relation_schema.ts +15 -2
- package/src/report.ts +2 -2
- package/src/sqlite_computation_bundle.ts +78 -0
- package/src/sqlite_computed.ts +102 -0
- package/src/sqlite_counts.ts +154 -0
- package/src/sqlite_layout.ts +823 -0
- package/src/sqlite_reads.ts +275 -0
- package/src/sqlite_samples.ts +185 -0
- package/src/stable_id_identity_bridge.ts +1 -1
- package/src/stable_ids_for_module.ts +16 -4
- package/src/test_call_usda.ts +6 -6
- package/src/usda_relationship_integrity.ts +20 -3
- package/src/usda_text.ts +21 -1
- package/src/value_object.ts +81 -11
- package/src/wire.ts +22 -0
- package/src/wire_encode.ts +227 -20
- package/src/workspace_sharding.ts +15 -6
- package/src/workspace_sharing.ts +51 -49
- package/src/zod_introspection.ts +2 -0
- package/compat_package.mjs +0 -46
- package/dart/lib/src/home.dart +0 -15
- package/dart/lib/src/runner/offline-install.mjs +0 -15367
- package/dart/lib/src/source_trust.dart +0 -51
- package/dart/lib/src/webview_bridge.dart +0 -6540
- package/dart/lib/src/workspace_name.dart +0 -30
- package/dart/test/acquire_session_credentials_test.dart +0 -150
- package/dart/test/acquire_session_test.dart +0 -534
- package/dart/test/adv_realm_interference_test.dart +0 -600
- package/dart/test/cloud_bound_topology_test.dart +0 -168
- package/dart/test/cluster_births_test.dart +0 -202
- package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
- package/dart/test/cluster_local_autosync_test.dart +0 -123
- package/dart/test/cluster_scale_test.dart +0 -122
- package/dart/test/compat_test.dart +0 -61
- package/dart/test/dlq_session_surface_test.dart +0 -222
- package/dart/test/first_app_gauntlet_test.dart +0 -386
- package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
- package/dart/test/four_layer_nested_topology_test.dart +0 -290
- package/dart/test/home_parity_test.dart +0 -13
- package/dart/test/local_sync_inert_test.dart +0 -107
- package/dart/test/node_runner_transport_test.dart +0 -78
- package/dart/test/parent_signer_recovery_test.dart +0 -155
- package/dart/test/residency_refusal_test.dart +0 -49
- package/dart/test/sealing_client_test.dart +0 -181
- package/dart/test/session_bound_test.dart +0 -285
- package/dart/test/stale_bundle_test.dart +0 -80
- package/dart/test/vo_read_typing_test.dart +0 -131
- package/dart/test/watch_after_offer_stall_test.dart +0 -100
- package/dart/test/webview_bridge_test.dart +0 -1930
- package/dart/test/workspace_name_test.dart +0 -24
- package/runtime/generated-application-host.js +0 -22860
- package/src/codegen_query_usda.ts +0 -214
- package/src/compat_manifest.ts +0 -26
- package/src/compat_package_main.ts +0 -224
- package/src/shape_compat.ts +0 -352
- package/src/usd_state.ts +0 -505
package/src/law_source_map.ts
CHANGED
|
@@ -82,7 +82,10 @@ export class DomainSourceMap {
|
|
|
82
82
|
private readonly texts = new Map<string, string | null>();
|
|
83
83
|
|
|
84
84
|
/** `files` — the ORDERED module paths composing the domain (config order; first is the fallback anchor). */
|
|
85
|
-
|
|
85
|
+
private readonly files: readonly string[];
|
|
86
|
+
constructor(files: readonly string[]) {
|
|
87
|
+
this.files = files;
|
|
88
|
+
}
|
|
86
89
|
|
|
87
90
|
private text(file: string): string | null {
|
|
88
91
|
if (!this.texts.has(file)) {
|
package/src/law_units.ts
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
// D21c — per-domain law units, authored by the compiler.
|
|
2
|
+
//
|
|
3
|
+
// D21 (architecture/identity_target_model.md): law is installed per domain and composed by the
|
|
4
|
+
// kernel. The unit of law is one domain — its layer, its routes and the plans those routes name —
|
|
5
|
+
// content-addressed. The compiler only AUTHORS units. It may preview a composition (the coverage
|
|
6
|
+
// check below), but the composed stage and its projections are the kernel's to derive.
|
|
7
|
+
//
|
|
8
|
+
// Units are split from the package the compiler already emits, so today's package bytes and closure
|
|
9
|
+
// identity do not move, and the split is the one the kernel's `DomainLawUnit::split`
|
|
10
|
+
// (kernel/src/law_units.rs) makes from the same package, so both hash identically. The format is
|
|
11
|
+
// specified in architecture/law_units_format.md.
|
|
12
|
+
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
|
|
15
|
+
/** One authenticated file of a law closure, at its package logical path. */
|
|
16
|
+
export interface LawUnitInputAsset {
|
|
17
|
+
readonly logicalPath: string;
|
|
18
|
+
readonly sha256: string;
|
|
19
|
+
readonly bytes: Uint8Array;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** One route of the package route table: an execution selector naming one plan by hash. */
|
|
23
|
+
export interface LawUnitRoute {
|
|
24
|
+
readonly selector: string;
|
|
25
|
+
readonly planSha256: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type LawUnitKind = "domain" | "framework" | "composition";
|
|
29
|
+
|
|
30
|
+
export interface LawUnitAsset {
|
|
31
|
+
readonly logicalPath: string;
|
|
32
|
+
readonly sha256: string;
|
|
33
|
+
readonly bytes: Uint8Array;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface LawUnit {
|
|
37
|
+
/** `framework`, `composition` or `domain:<d>` — kind-qualified, because a domain may itself be
|
|
38
|
+
* named like a reserved word or begin with `__`. */
|
|
39
|
+
readonly key: string;
|
|
40
|
+
readonly kind: LawUnitKind;
|
|
41
|
+
/** The domain, for a domain unit. */
|
|
42
|
+
readonly domain?: string;
|
|
43
|
+
/** sha256 over the unit's tagged, sorted inventory and route pairs (see `lawUnitHash`). */
|
|
44
|
+
readonly hash: string;
|
|
45
|
+
/** The unit's own routes, byte-ordered by selector. Typed pairs, not a file: the kernel's composer
|
|
46
|
+
* synthesizes the one `runtime/routes.usda` from the union of every installed unit's routes. */
|
|
47
|
+
readonly routes: readonly LawUnitRoute[];
|
|
48
|
+
/** Every file of the unit at its package logical path, byte-ordered. */
|
|
49
|
+
readonly assets: readonly LawUnitAsset[];
|
|
50
|
+
/** `unit.usda`: the unit's manifest (key, hash, inventory, routes). A carrier, never itself hashed. */
|
|
51
|
+
readonly manifest: Uint8Array;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const FRAMEWORK_UNIT = "framework";
|
|
55
|
+
export const COMPOSITION_UNIT = "composition";
|
|
56
|
+
export const domainUnitKey = (domain: string): string => `domain:${domain}`;
|
|
57
|
+
|
|
58
|
+
export const LAW_UNIT_HASH_TAG = "nomos-law-unit-v1";
|
|
59
|
+
export const LAW_UNIT_FORMAT = "nomos.law-unit.v1";
|
|
60
|
+
export const LAW_UNIT_MANIFEST = "unit.usda";
|
|
61
|
+
|
|
62
|
+
/** Files of the package that the kernel synthesizes or derives from the installed units. */
|
|
63
|
+
const DERIVED_LOGICAL_PATHS = new Set([
|
|
64
|
+
"root.usda",
|
|
65
|
+
"runtime/routes.usda",
|
|
66
|
+
"runtime/composed-law.usdc",
|
|
67
|
+
"runtime/read-projection.usda",
|
|
68
|
+
"runtime/read-projection.usdc",
|
|
69
|
+
"runtime/command-projection.usda",
|
|
70
|
+
"runtime/command-projection.usdc",
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
/** Byte order on ASCII strings — the order Rust's `BTreeMap<String, _>` gives. */
|
|
74
|
+
const byteOrder = (left: string, right: string): number =>
|
|
75
|
+
left < right ? -1 : left > right ? 1 : 0;
|
|
76
|
+
|
|
77
|
+
const sha256Hex = (bytes: Uint8Array | string): string =>
|
|
78
|
+
createHash("sha256").update(bytes).digest("hex");
|
|
79
|
+
|
|
80
|
+
const utf8 = (text: string): Uint8Array => new TextEncoder().encode(text);
|
|
81
|
+
|
|
82
|
+
const DOMAIN_LAYER = /^domains\/([^/]+)\.usda$/;
|
|
83
|
+
const PLAN_FILE = /^runtime\/plans\/([0-9a-f]{64})\.(mjs|usda)$/;
|
|
84
|
+
const BASE_FILE = /^runtime\/bases\/([0-9a-f]{64})\.(mjs|usda)$/;
|
|
85
|
+
|
|
86
|
+
export const isDerivedLawPath = (logicalPath: string): boolean =>
|
|
87
|
+
DERIVED_LOGICAL_PATHS.has(logicalPath);
|
|
88
|
+
|
|
89
|
+
/** What a domain layer declares, for route ownership: its aggregates' `nomos:wireType` and
|
|
90
|
+
* `nomos:label` (prims `/Nomos/Domains/<d>/Aggregates/<a>`) and its invariants' `nomos:label`
|
|
91
|
+
* (prims `/Nomos/Domains/<d>/Invariants/<n>`) — the same prims the kernel's split reads. */
|
|
92
|
+
export interface DomainDeclarations {
|
|
93
|
+
readonly aggregateWireTypes: ReadonlySet<string>;
|
|
94
|
+
readonly aggregateLabels: ReadonlySet<string>;
|
|
95
|
+
readonly invariantLabels: ReadonlySet<string>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Scan a compiler-authored domain layer for the declarations route ownership reads. The layer is
|
|
99
|
+
* emitted one opinion per line with each prim's braces on their own lines; a line ending `= {`
|
|
100
|
+
* opens a dictionary value (closed by its own `}`), which is not a prim. */
|
|
101
|
+
export function scanDomainDeclarations(usda: string): DomainDeclarations {
|
|
102
|
+
const aggregateWireTypes = new Set<string>();
|
|
103
|
+
const aggregateLabels = new Set<string>();
|
|
104
|
+
const invariantLabels = new Set<string>();
|
|
105
|
+
const frames: Array<string | null> = [];
|
|
106
|
+
let pendingPrim: string | null = null;
|
|
107
|
+
let body = false;
|
|
108
|
+
for (const raw of usda.split("\n")) {
|
|
109
|
+
const line = raw.trim();
|
|
110
|
+
const prim = /^(?:def|over|class)\b[^=]*?"([^"]+)"\s*(?:\(\s*)?$/.exec(line);
|
|
111
|
+
if (!body) {
|
|
112
|
+
// Skip the layer header `( ... )`: the body starts at the first prim.
|
|
113
|
+
if (prim === null) continue;
|
|
114
|
+
body = true;
|
|
115
|
+
}
|
|
116
|
+
if (prim !== null) {
|
|
117
|
+
pendingPrim = prim[1]!;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (line === "{") {
|
|
121
|
+
frames.push(pendingPrim);
|
|
122
|
+
pendingPrim = null;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (line === "}") {
|
|
126
|
+
frames.pop();
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (line.endsWith("= {")) {
|
|
130
|
+
frames.push(null);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const property = /\bnomos:(wireType|label) = ("(?:[^"\\]|\\.)*")$/.exec(line);
|
|
134
|
+
if (property === null) continue;
|
|
135
|
+
if (frames.includes(null)) continue;
|
|
136
|
+
const at = frames as string[];
|
|
137
|
+
if (at.length !== 5 || at[0] !== "Nomos" || at[1] !== "Domains") continue;
|
|
138
|
+
const value = JSON.parse(property[2]!) as string;
|
|
139
|
+
if (at[3] === "Aggregates") {
|
|
140
|
+
(property[1] === "wireType" ? aggregateWireTypes : aggregateLabels).add(value);
|
|
141
|
+
} else if (at[3] === "Invariants" && property[1] === "label") {
|
|
142
|
+
invariantLabels.add(value);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { aggregateWireTypes, aggregateLabels, invariantLabels };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** The unit key that owns a route. A domain's own plan and offers belong to it. A report on one
|
|
149
|
+
* subject belongs to the one domain that declares that subject: an aggregate (by `nomos:wireType`,
|
|
150
|
+
* else by `nomos:label`) for `aggregateInvariant` / `combine` / `derive`, an invariant (by
|
|
151
|
+
* `nomos:label`) for `workspaceInvariant` / `workspaceInvariantReads`. Everything else — `describe`,
|
|
152
|
+
* `report:report:*`, `report:invariant:*`, and any subject declared by no domain or by several —
|
|
153
|
+
* spans the composed set and belongs to the composition. */
|
|
154
|
+
export function routeOwner(
|
|
155
|
+
selector: string,
|
|
156
|
+
declarations: ReadonlyMap<string, DomainDeclarations>
|
|
157
|
+
): string {
|
|
158
|
+
// Exactly the kernel's `selector_domain`: everything after `plan:domain:`, or the text between
|
|
159
|
+
// `plan:offer:` and the next `:`.
|
|
160
|
+
const domainPlan = /^plan:domain:(.*)$/s.exec(selector);
|
|
161
|
+
if (domainPlan !== null) return domainUnitKey(domainPlan[1]!);
|
|
162
|
+
const offer = /^plan:offer:([^:]*):/.exec(selector);
|
|
163
|
+
if (offer !== null) return domainUnitKey(offer[1]!);
|
|
164
|
+
const declaring = (
|
|
165
|
+
pick: (d: DomainDeclarations) => ReadonlySet<string>,
|
|
166
|
+
subject: string
|
|
167
|
+
): string[] =>
|
|
168
|
+
[...declarations].filter(([, d]) => pick(d).has(subject)).map(([domain]) => domain);
|
|
169
|
+
const aggregate = /^report:(?:aggregateInvariant|combine|derive):(.*)$/s.exec(selector);
|
|
170
|
+
if (aggregate !== null) {
|
|
171
|
+
const subject = aggregate[1]!;
|
|
172
|
+
let owners = declaring((d) => d.aggregateWireTypes, subject);
|
|
173
|
+
if (owners.length === 0) owners = declaring((d) => d.aggregateLabels, subject);
|
|
174
|
+
return owners.length === 1 ? domainUnitKey(owners[0]!) : COMPOSITION_UNIT;
|
|
175
|
+
}
|
|
176
|
+
const invariant = /^report:(?:workspaceInvariant|workspaceInvariantReads):(.*)$/s.exec(selector);
|
|
177
|
+
if (invariant !== null) {
|
|
178
|
+
const owners = declaring((d) => d.invariantLabels, invariant[1]!);
|
|
179
|
+
return owners.length === 1 ? domainUnitKey(owners[0]!) : COMPOSITION_UNIT;
|
|
180
|
+
}
|
|
181
|
+
return COMPOSITION_UNIT;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The directory a unit is written to: its key with `:` made path-portable, then its hash. */
|
|
185
|
+
export const lawUnitDirectoryName = (unit: Pick<LawUnit, "key" | "hash">): string =>
|
|
186
|
+
`${unit.key.replace(":", "-")}-${unit.hash}`;
|
|
187
|
+
|
|
188
|
+
/** The package's `runtime/routes.usda`: every route, one prim each, in selector collation order. Also
|
|
189
|
+
* rebuilt from the emitted law units by their coverage preview below, which proves the units
|
|
190
|
+
* carry exactly the package's routes. */
|
|
191
|
+
export function packageRoutesLayerUsda(routes: readonly LawUnitRoute[]): string {
|
|
192
|
+
const routeOpinions: string[] = [
|
|
193
|
+
"#usda 1.0",
|
|
194
|
+
"(",
|
|
195
|
+
" customLayerData = {",
|
|
196
|
+
' string "nomos:format" = "nomos.law-layer.v3"',
|
|
197
|
+
' string "nomos:logicalPath" = "runtime/routes"',
|
|
198
|
+
" }",
|
|
199
|
+
")",
|
|
200
|
+
"",
|
|
201
|
+
'def Scope "__NomosRuntime_7e9c"',
|
|
202
|
+
"{",
|
|
203
|
+
' custom string nomos:kind = "runtime"',
|
|
204
|
+
' custom string nomos:format = "nomos.openusd-plan-metadata.v3"',
|
|
205
|
+
"",
|
|
206
|
+
' def Scope "Routes"',
|
|
207
|
+
" {",
|
|
208
|
+
];
|
|
209
|
+
[...routes]
|
|
210
|
+
.sort((left, right) => left.selector.localeCompare(right.selector))
|
|
211
|
+
.forEach((route, index) => {
|
|
212
|
+
routeOpinions.push(
|
|
213
|
+
` def Scope "r${String(index).padStart(6, "0")}"`,
|
|
214
|
+
" {",
|
|
215
|
+
` custom string nomos:selector = ${JSON.stringify(
|
|
216
|
+
route.selector
|
|
217
|
+
)}`,
|
|
218
|
+
` custom string nomos:plan = "${route.planSha256}"`,
|
|
219
|
+
" }",
|
|
220
|
+
""
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
if (routeOpinions[routeOpinions.length - 1] === "") routeOpinions.pop();
|
|
224
|
+
routeOpinions.push(" }", "}", "");
|
|
225
|
+
return routeOpinions.join("\n");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Unit identity — agreed with the kernel's `DomainLawUnit` (kernel/src/law_units.rs):
|
|
229
|
+
* sha256("nomos-law-unit-v1\0" key "\0" "assets\0" (logicalPath "\0" sha256 "\0")*
|
|
230
|
+
* "routes\0" (selector "\0" planSha256 "\0")*), assets by logical path and routes by
|
|
231
|
+
* selector, each in byte order, digests lowercase hex. */
|
|
232
|
+
export function lawUnitHash(
|
|
233
|
+
key: string,
|
|
234
|
+
inventory: readonly { readonly logicalPath: string; readonly sha256: string }[],
|
|
235
|
+
routes: readonly LawUnitRoute[]
|
|
236
|
+
): string {
|
|
237
|
+
const hash = createHash("sha256");
|
|
238
|
+
hash.update(`${LAW_UNIT_HASH_TAG}\0`);
|
|
239
|
+
hash.update(key);
|
|
240
|
+
hash.update("\0");
|
|
241
|
+
hash.update("assets\0");
|
|
242
|
+
for (const asset of [...inventory].sort((l, r) => byteOrder(l.logicalPath, r.logicalPath))) {
|
|
243
|
+
hash.update(asset.logicalPath);
|
|
244
|
+
hash.update("\0");
|
|
245
|
+
hash.update(asset.sha256);
|
|
246
|
+
hash.update("\0");
|
|
247
|
+
}
|
|
248
|
+
hash.update("routes\0");
|
|
249
|
+
for (const route of [...routes].sort((l, r) => byteOrder(l.selector, r.selector))) {
|
|
250
|
+
hash.update(route.selector);
|
|
251
|
+
hash.update("\0");
|
|
252
|
+
hash.update(route.planSha256);
|
|
253
|
+
hash.update("\0");
|
|
254
|
+
}
|
|
255
|
+
return hash.digest("hex");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function unitManifestUsda(unit: Omit<LawUnit, "manifest">): string {
|
|
259
|
+
return [
|
|
260
|
+
"#usda 1.0",
|
|
261
|
+
"(",
|
|
262
|
+
' defaultPrim = "__NomosLawUnit_7e9c"',
|
|
263
|
+
" customLayerData = {",
|
|
264
|
+
` string "nomos:format" = "${LAW_UNIT_FORMAT}"`,
|
|
265
|
+
" }",
|
|
266
|
+
")",
|
|
267
|
+
"",
|
|
268
|
+
'def NomosLawUnit "__NomosLawUnit_7e9c"',
|
|
269
|
+
"{",
|
|
270
|
+
` custom string nomos:unit = ${JSON.stringify(unit.key)}`,
|
|
271
|
+
` custom token nomos:unitKind = "${unit.kind}"`,
|
|
272
|
+
...(unit.domain === undefined
|
|
273
|
+
? []
|
|
274
|
+
: [` custom string nomos:domain = ${JSON.stringify(unit.domain)}`]),
|
|
275
|
+
` custom string nomos:unitHash = "${unit.hash}"`,
|
|
276
|
+
"",
|
|
277
|
+
' def Scope "Assets"',
|
|
278
|
+
" {",
|
|
279
|
+
...unit.assets.flatMap((asset) => [
|
|
280
|
+
` def NomosLawAsset "a_${sha256Hex(asset.logicalPath)}"`,
|
|
281
|
+
" {",
|
|
282
|
+
` custom string nomos:logicalPath = ${JSON.stringify(asset.logicalPath)}`,
|
|
283
|
+
` custom string nomos:sha256 = "${asset.sha256}"`,
|
|
284
|
+
" }",
|
|
285
|
+
]),
|
|
286
|
+
" }",
|
|
287
|
+
"",
|
|
288
|
+
' def Scope "Routes"',
|
|
289
|
+
" {",
|
|
290
|
+
...unit.routes.flatMap((route) => [
|
|
291
|
+
` def NomosLawRoute "s_${sha256Hex(route.selector)}"`,
|
|
292
|
+
" {",
|
|
293
|
+
` custom string nomos:selector = ${JSON.stringify(route.selector)}`,
|
|
294
|
+
` custom string nomos:plan = "${route.planSha256}"`,
|
|
295
|
+
" }",
|
|
296
|
+
]),
|
|
297
|
+
" }",
|
|
298
|
+
"}",
|
|
299
|
+
"",
|
|
300
|
+
].join("\n");
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Split an emitted package into its law units: one per domain layer, the framework unit
|
|
304
|
+
* (`framework.usda`, byte-identical in every package) and the composition unit (`package.usda`, the
|
|
305
|
+
* package-specific runtime bases, and the routes that span domains). A plan travels in every unit
|
|
306
|
+
* whose routes name it: units are content-addressed, so a shared plan is one blob in git. */
|
|
307
|
+
export function splitLawUnits(
|
|
308
|
+
closureAssets: readonly LawUnitInputAsset[],
|
|
309
|
+
routes: readonly LawUnitRoute[]
|
|
310
|
+
): LawUnit[] {
|
|
311
|
+
const fail = (message: string): never => {
|
|
312
|
+
throw new Error(`law units: ${message}`);
|
|
313
|
+
};
|
|
314
|
+
const byPath = new Map<string, LawUnitInputAsset>();
|
|
315
|
+
for (const asset of closureAssets) {
|
|
316
|
+
if (byPath.has(asset.logicalPath)) fail(`duplicate package path '${asset.logicalPath}'`);
|
|
317
|
+
if (sha256Hex(asset.bytes) !== asset.sha256) {
|
|
318
|
+
fail(`'${asset.logicalPath}' bytes do not match its declared sha256`);
|
|
319
|
+
}
|
|
320
|
+
byPath.set(asset.logicalPath, asset);
|
|
321
|
+
}
|
|
322
|
+
interface Member {
|
|
323
|
+
kind: LawUnitKind;
|
|
324
|
+
domain?: string;
|
|
325
|
+
paths: Set<string>;
|
|
326
|
+
routes: LawUnitRoute[];
|
|
327
|
+
}
|
|
328
|
+
const members = new Map<string, Member>();
|
|
329
|
+
const unit = (key: string, kind: LawUnitKind, domain?: string): Member => {
|
|
330
|
+
let entry = members.get(key);
|
|
331
|
+
if (entry === undefined) {
|
|
332
|
+
entry = { kind, ...(domain === undefined ? {} : { domain }), paths: new Set(), routes: [] };
|
|
333
|
+
members.set(key, entry);
|
|
334
|
+
}
|
|
335
|
+
return entry;
|
|
336
|
+
};
|
|
337
|
+
unit(FRAMEWORK_UNIT, "framework");
|
|
338
|
+
unit(COMPOSITION_UNIT, "composition");
|
|
339
|
+
const declarations = new Map<string, DomainDeclarations>();
|
|
340
|
+
const planHashes = new Set<string>();
|
|
341
|
+
for (const [logicalPath, asset] of byPath) {
|
|
342
|
+
if (DERIVED_LOGICAL_PATHS.has(logicalPath)) continue;
|
|
343
|
+
const domain = DOMAIN_LAYER.exec(logicalPath);
|
|
344
|
+
if (domain !== null) {
|
|
345
|
+
const name = domain[1]!;
|
|
346
|
+
unit(domainUnitKey(name), "domain", name).paths.add(logicalPath);
|
|
347
|
+
declarations.set(name, scanDomainDeclarations(new TextDecoder().decode(asset.bytes)));
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const plan = PLAN_FILE.exec(logicalPath);
|
|
351
|
+
if (plan !== null) {
|
|
352
|
+
planHashes.add(plan[1]!);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (logicalPath === "framework.usda") {
|
|
356
|
+
unit(FRAMEWORK_UNIT, "framework").paths.add(logicalPath);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (logicalPath === "package.usda" || BASE_FILE.test(logicalPath)) {
|
|
360
|
+
unit(COMPOSITION_UNIT, "composition").paths.add(logicalPath);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
fail(`package file '${logicalPath}' is neither unit law nor a known derived projection`);
|
|
364
|
+
}
|
|
365
|
+
const seenSelectors = new Set<string>();
|
|
366
|
+
const referencedPlans = new Set<string>();
|
|
367
|
+
for (const route of routes) {
|
|
368
|
+
if (seenSelectors.has(route.selector)) fail(`selector '${route.selector}' is routed twice`);
|
|
369
|
+
seenSelectors.add(route.selector);
|
|
370
|
+
const owner = routeOwner(route.selector, declarations);
|
|
371
|
+
const entry = members.get(owner);
|
|
372
|
+
if (entry === undefined) {
|
|
373
|
+
return fail(`route '${route.selector}' names '${owner}', which has no domain layer`);
|
|
374
|
+
}
|
|
375
|
+
for (const extension of ["mjs", "usda"]) {
|
|
376
|
+
const planPath = `runtime/plans/${route.planSha256}.${extension}`;
|
|
377
|
+
if (!byPath.has(planPath)) fail(`route '${route.selector}' names missing '${planPath}'`);
|
|
378
|
+
entry.paths.add(planPath);
|
|
379
|
+
}
|
|
380
|
+
entry.routes.push(route);
|
|
381
|
+
referencedPlans.add(route.planSha256);
|
|
382
|
+
}
|
|
383
|
+
for (const plan of planHashes) {
|
|
384
|
+
if (!referencedPlans.has(plan)) fail(`plan '${plan}' is in the package but no route names it`);
|
|
385
|
+
}
|
|
386
|
+
return [...members]
|
|
387
|
+
.sort(([left], [right]) => byteOrder(left, right))
|
|
388
|
+
.map(([key, entry]) => {
|
|
389
|
+
const unitRoutes = [...entry.routes].sort((l, r) => byteOrder(l.selector, r.selector));
|
|
390
|
+
const assets: LawUnitAsset[] = [...entry.paths].sort(byteOrder).map((logicalPath) => {
|
|
391
|
+
const asset = byPath.get(logicalPath)!;
|
|
392
|
+
return { logicalPath, sha256: asset.sha256, bytes: asset.bytes };
|
|
393
|
+
});
|
|
394
|
+
const withoutManifest = {
|
|
395
|
+
key,
|
|
396
|
+
kind: entry.kind,
|
|
397
|
+
...(entry.domain === undefined ? {} : { domain: entry.domain }),
|
|
398
|
+
hash: lawUnitHash(key, assets, unitRoutes),
|
|
399
|
+
routes: unitRoutes,
|
|
400
|
+
assets,
|
|
401
|
+
};
|
|
402
|
+
return { ...withoutManifest, manifest: utf8(unitManifestUsda(withoutManifest)) };
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** The compiler's composition PREVIEW: prove that the units cover exactly the package's non-derived
|
|
407
|
+
* law. Every domain layer, framework layer, base and plan of the package is in some unit and nothing
|
|
408
|
+
* else is; a path held by two units is a plan, byte-identical in both; every route is held by exactly
|
|
409
|
+
* one unit, its owner, and names a plan that unit carries; every plan a unit carries is named by one
|
|
410
|
+
* of its routes; and the union of unit routes rebuilds the package's own `runtime/routes.usda` byte
|
|
411
|
+
* for byte. Throws on the first discrepancy. A check only — never a shipped composition. */
|
|
412
|
+
export function assertLawUnitsCoverPackage(
|
|
413
|
+
units: readonly LawUnit[],
|
|
414
|
+
closureAssets: readonly LawUnitInputAsset[],
|
|
415
|
+
routes: readonly LawUnitRoute[]
|
|
416
|
+
): void {
|
|
417
|
+
const fail = (message: string): never => {
|
|
418
|
+
throw new Error(`law unit coverage: ${message}`);
|
|
419
|
+
};
|
|
420
|
+
const declarations = new Map<string, DomainDeclarations>();
|
|
421
|
+
for (const asset of closureAssets) {
|
|
422
|
+
const domain = DOMAIN_LAYER.exec(asset.logicalPath);
|
|
423
|
+
if (domain !== null) {
|
|
424
|
+
declarations.set(domain[1]!, scanDomainDeclarations(new TextDecoder().decode(asset.bytes)));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const keys = new Set<string>();
|
|
428
|
+
const union = new Map<string, string>();
|
|
429
|
+
const unionRoutes = new Map<string, string>();
|
|
430
|
+
for (const unit of units) {
|
|
431
|
+
if (keys.has(unit.key)) fail(`unit '${unit.key}' appears twice`);
|
|
432
|
+
keys.add(unit.key);
|
|
433
|
+
if (lawUnitHash(unit.key, unit.assets, unit.routes) !== unit.hash) {
|
|
434
|
+
fail(`unit '${unit.key}' hash does not match its inventory and routes`);
|
|
435
|
+
}
|
|
436
|
+
const own = new Map(unit.assets.map((asset) => [asset.logicalPath, asset] as const));
|
|
437
|
+
if (own.size !== unit.assets.length) fail(`unit '${unit.key}' lists a path twice`);
|
|
438
|
+
const namedPlans = new Set<string>();
|
|
439
|
+
for (const route of unit.routes) {
|
|
440
|
+
if (unionRoutes.has(route.selector)) fail(`selector '${route.selector}' is held by two units`);
|
|
441
|
+
if (routeOwner(route.selector, declarations) !== unit.key) {
|
|
442
|
+
fail(`unit '${unit.key}' holds route '${route.selector}', which it does not own`);
|
|
443
|
+
}
|
|
444
|
+
unionRoutes.set(route.selector, route.planSha256);
|
|
445
|
+
for (const extension of ["mjs", "usda"]) {
|
|
446
|
+
if (!own.has(`runtime/plans/${route.planSha256}.${extension}`)) {
|
|
447
|
+
fail(`unit '${unit.key}' route '${route.selector}' names a plan the unit does not carry`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
namedPlans.add(route.planSha256);
|
|
451
|
+
}
|
|
452
|
+
for (const asset of unit.assets) {
|
|
453
|
+
if (sha256Hex(asset.bytes) !== asset.sha256) {
|
|
454
|
+
fail(`unit '${unit.key}' '${asset.logicalPath}' bytes do not match`);
|
|
455
|
+
}
|
|
456
|
+
const plan = PLAN_FILE.exec(asset.logicalPath);
|
|
457
|
+
if (plan !== null && !namedPlans.has(plan[1]!)) {
|
|
458
|
+
fail(`unit '${unit.key}' carries plan '${plan[1]}' that none of its routes name`);
|
|
459
|
+
}
|
|
460
|
+
const prior = union.get(asset.logicalPath);
|
|
461
|
+
if (prior !== undefined && prior !== asset.sha256) fail(`'${asset.logicalPath}' differs between units`);
|
|
462
|
+
if (prior !== undefined && plan === null) {
|
|
463
|
+
fail(`'${asset.logicalPath}' is held by two units (only plans may be shared)`);
|
|
464
|
+
}
|
|
465
|
+
union.set(asset.logicalPath, asset.sha256);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
const expected = new Map(
|
|
469
|
+
closureAssets
|
|
470
|
+
.filter((asset) => !DERIVED_LOGICAL_PATHS.has(asset.logicalPath))
|
|
471
|
+
.map((asset) => [asset.logicalPath, asset.sha256] as const)
|
|
472
|
+
);
|
|
473
|
+
for (const [logicalPath, sha256] of expected) {
|
|
474
|
+
const held = union.get(logicalPath);
|
|
475
|
+
if (held === undefined) fail(`package file '${logicalPath}' is in no unit`);
|
|
476
|
+
if (held !== sha256) fail(`package file '${logicalPath}' differs in its unit`);
|
|
477
|
+
}
|
|
478
|
+
for (const logicalPath of union.keys()) {
|
|
479
|
+
if (!expected.has(logicalPath)) fail(`unit file '${logicalPath}' is not package law`);
|
|
480
|
+
}
|
|
481
|
+
if (unionRoutes.size !== routes.length) {
|
|
482
|
+
fail(`units hold ${unionRoutes.size} routes; the package has ${routes.length}`);
|
|
483
|
+
}
|
|
484
|
+
for (const route of routes) {
|
|
485
|
+
if (unionRoutes.get(route.selector) !== route.planSha256) {
|
|
486
|
+
fail(`route '${route.selector}' is not held as the package routes it`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
const packageRoutes = closureAssets.find((asset) => asset.logicalPath === "runtime/routes.usda");
|
|
490
|
+
if (packageRoutes !== undefined) {
|
|
491
|
+
const rebuilt = packageRoutesLayerUsda(
|
|
492
|
+
[...unionRoutes].map(([selector, planSha256]) => ({ selector, planSha256 }))
|
|
493
|
+
);
|
|
494
|
+
if (sha256Hex(rebuilt) !== packageRoutes.sha256) {
|
|
495
|
+
fail("the units' routes do not rebuild the package's runtime/routes.usda");
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
package/src/law_value_type.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
import { enumTypeNameOf } from "./enum_type.js";
|
|
3
|
-
import { isGitObjectIdSchema, isSha256DigestSchema } from "./fields.js";
|
|
3
|
+
import { isGitObjectIdSchema, isSha256DigestSchema, type GeometryKind } from "./fields.js";
|
|
4
4
|
import { recipientMetaOf } from "./recipient.js";
|
|
5
5
|
import {
|
|
6
6
|
NOMOS_UNIT_BRAND,
|
|
@@ -45,7 +45,8 @@ export interface LawValueMember {
|
|
|
45
45
|
*/
|
|
46
46
|
export type LawValueSemantic =
|
|
47
47
|
| { readonly kind: "sha256-digest" | "git-object-id" }
|
|
48
|
-
| { readonly kind: "branded-id" | "unit"
|
|
48
|
+
| { readonly kind: "branded-id" | "unit"; readonly name: string }
|
|
49
|
+
| { readonly kind: "value-object"; readonly name: string; readonly geometry?: GeometryKind }
|
|
49
50
|
| { readonly kind: "recipient"; readonly subject: "User" }
|
|
50
51
|
| {
|
|
51
52
|
readonly kind: "id-reference" | "address-reference";
|
|
@@ -234,7 +235,10 @@ function semanticOf(schema: z.ZodTypeAny): LawValueSemantic | undefined {
|
|
|
234
235
|
const unit = (schema as unknown as Record<symbol, unknown>)[NOMOS_UNIT_BRAND];
|
|
235
236
|
if (typeof unit === "string") return { kind: "unit", name: unit };
|
|
236
237
|
const valueObject = voMetaOf(schema);
|
|
237
|
-
if (valueObject !== undefined) return {
|
|
238
|
+
if (valueObject !== undefined) return {
|
|
239
|
+
kind: "value-object", name: valueObject.name,
|
|
240
|
+
...(valueObject.geometry === undefined ? {} : { geometry: valueObject.geometry }),
|
|
241
|
+
};
|
|
238
242
|
return undefined;
|
|
239
243
|
}
|
|
240
244
|
|