@githolon/dsl 0.108.7 → 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 +1994 -1189
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.110.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"./stable-ids": "./src/stable_ids.ts",
|
|
21
21
|
"./compose": "./src/compose.ts",
|
|
22
22
|
"./application-composition": "./src/application_composition.ts",
|
|
23
|
-
"./usd-state": "./src/usd_state.ts",
|
|
24
23
|
"./engine-entry": "./src/engine_entry.ts",
|
|
25
24
|
"./compile-proof": {
|
|
26
25
|
"types": "./compile_proof.d.mts",
|
|
@@ -43,6 +42,8 @@
|
|
|
43
42
|
"./package.json": "./package.json"
|
|
44
43
|
},
|
|
45
44
|
"files": [
|
|
45
|
+
"assets/operation-contract.wasm",
|
|
46
|
+
"operation_contract_check.mjs",
|
|
46
47
|
"src",
|
|
47
48
|
"!src/**/*.test.ts",
|
|
48
49
|
"!src/framework/identity.ts",
|
|
@@ -50,26 +51,30 @@
|
|
|
50
51
|
"!dart/.dart_tool",
|
|
51
52
|
"!dart/build",
|
|
52
53
|
"dart_types",
|
|
54
|
+
"dart_lints",
|
|
55
|
+
"!dart_lints/.dart_tool",
|
|
56
|
+
"!dart_lints/build",
|
|
53
57
|
"!dart_types/.dart_tool",
|
|
54
58
|
"!dart_types/build",
|
|
55
|
-
"runtime",
|
|
56
59
|
"compile_proof.mjs",
|
|
57
60
|
"compile_proof.d.mts",
|
|
58
61
|
"compile_package.mjs",
|
|
59
62
|
"check_package.mjs",
|
|
60
|
-
"compat_package.mjs",
|
|
61
63
|
"lsp_server.mjs"
|
|
62
64
|
],
|
|
63
65
|
"publishConfig": {
|
|
64
66
|
"access": "public"
|
|
65
67
|
},
|
|
66
68
|
"scripts": {
|
|
67
|
-
"build:
|
|
68
|
-
"prepack": "npm run build:
|
|
69
|
+
"build:contracts": "node ../scripts/build_operation_contract_checker.mjs",
|
|
70
|
+
"prepack": "npm run build:contracts",
|
|
69
71
|
"typecheck": "tsc --noEmit",
|
|
70
72
|
"test": "vitest run"
|
|
71
73
|
},
|
|
72
74
|
"dependencies": {
|
|
75
|
+
"@githolon/runtime": "^0.110.0",
|
|
76
|
+
"@bufbuild/protobuf": "^2.13.0",
|
|
77
|
+
"@bufbuild/protoc-gen-es": "^2.13.0",
|
|
73
78
|
"esbuild": "0.24.2",
|
|
74
79
|
"tsx": "^4.19.2",
|
|
75
80
|
"typescript": "^5.6.3",
|
package/src/aggregate.ts
CHANGED
|
@@ -26,8 +26,21 @@ import { Lww } from "./drivers.js";
|
|
|
26
26
|
* PRESENCE ONLY is hashed in the manifest (like a directive `plan`); the body ships
|
|
27
27
|
* in the engine bundle, never in the ledger.
|
|
28
28
|
*/
|
|
29
|
-
export type AggregateInvariantVerdict =
|
|
30
|
-
|
|
29
|
+
export type AggregateInvariantVerdict =
|
|
30
|
+
| { accept: true }
|
|
31
|
+
| { reject: string }
|
|
32
|
+
/** Refuse admission without committing a strike or changing business state. */
|
|
33
|
+
| { refuse: string };
|
|
34
|
+
/**
|
|
35
|
+
* `previous` is the snapshot immediately before this event; null means creation.
|
|
36
|
+
* Undefined means a legacy caller did not supply transition context. A predicate
|
|
37
|
+
* requiring that context must fail closed, never interpret undefined as creation.
|
|
38
|
+
* Only touched aggregate types declaring an invariant reach this callback.
|
|
39
|
+
*/
|
|
40
|
+
export type AggregateInvariantFn = (
|
|
41
|
+
snapshot: Readonly<Record<string, unknown>>,
|
|
42
|
+
previous?: Readonly<Record<string, unknown>> | null,
|
|
43
|
+
) => AggregateInvariantVerdict;
|
|
31
44
|
|
|
32
45
|
/**
|
|
33
46
|
* READ VISIBILITY (the native-relations read gate) — the DECLARED posture of an
|
|
@@ -361,6 +374,13 @@ type AggregateOptions = {
|
|
|
361
374
|
visibility?: ReadVisibility;
|
|
362
375
|
global?: boolean;
|
|
363
376
|
attributed?: boolean;
|
|
377
|
+
/**
|
|
378
|
+
* `"candidates"` decides every first-writer field of this aggregate (and the entries of a
|
|
379
|
+
* first-writer map) from the SET of changes instead of their arrival order - see
|
|
380
|
+
* `FirstWriterCandidates`. Fields with any other merge policy are untouched. This changes the
|
|
381
|
+
* aggregate's law, so it ships through a domain rollout, never as a silent edit.
|
|
382
|
+
*/
|
|
383
|
+
firstWriter?: "candidates";
|
|
364
384
|
};
|
|
365
385
|
|
|
366
386
|
export function aggregate<const Id extends string, F extends Record<string, Field>>(
|
|
@@ -389,6 +409,22 @@ export function aggregate<const Id extends string, F extends Record<string, Fiel
|
|
|
389
409
|
);
|
|
390
410
|
}
|
|
391
411
|
const { stored, hasMany } = partitionFields(fields);
|
|
412
|
+
for (const [name, field] of Object.entries(stored)) {
|
|
413
|
+
const opaqueJsonLeaf = field.kind === "json";
|
|
414
|
+
const opaqueJsonMap = field.kind === "map" && field.mapValueKind === "json";
|
|
415
|
+
if (!opaqueJsonLeaf && !opaqueJsonMap) continue;
|
|
416
|
+
const declaredShape = field.valueObject?.name ?? field.mapValueVo?.name;
|
|
417
|
+
// Named value objects lower to the kernel's recursive ValueObject algebra and nested USDA prims.
|
|
418
|
+
// The historical FieldKind remains `json` only as a source/API compatibility label; it is never
|
|
419
|
+
// permitted to select Value::Json when a nominal descriptor is present.
|
|
420
|
+
if (declaredShape !== undefined) continue;
|
|
421
|
+
throw new Error(
|
|
422
|
+
`aggregate '${id}': field '${name}'${declaredShape === undefined ? "" : ` (${declaredShape})`} ` +
|
|
423
|
+
`would persist as opaque JSON, which cannot be authoritative Nomos state. ` +
|
|
424
|
+
`Declare a named valueObject so its members lower structurally into USDA, use independently composed ` +
|
|
425
|
+
`aggregate fields/records, or retain an exact foreign document through t.evidence() when source fidelity is required.`,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
392
428
|
// THE TIER FIELDS (`fulfilment.ts`). Completeness is law-state, so it is a real declared field
|
|
393
429
|
// — hashed, projected, queryable, evolvable — not something a reader re-derives by guessing
|
|
394
430
|
// which columns happen to be null. The blocked sibling records a TERMINAL reason, so "no
|
|
@@ -501,7 +537,30 @@ export function aggregate<const Id extends string, F extends Record<string, Fiel
|
|
|
501
537
|
// can be attributed"). Each attributed field's wire driver is wrapped
|
|
502
538
|
// `{"Attributed": <inner>}` — the law-era mechanism (old kernels refuse it cleanly;
|
|
503
539
|
// unattributed fields/domains stay byte-identical).
|
|
504
|
-
|
|
540
|
+
// `{ firstWriter: "candidates" }`: swap the policy BEFORE attribution wraps it, so an
|
|
541
|
+
// attributed first-writer field becomes Attributed(FirstWriterCandidates).
|
|
542
|
+
if (opts?.firstWriter === "candidates") {
|
|
543
|
+
const candidates = (driver: { kind: string; inner?: unknown }): unknown =>
|
|
544
|
+
driver.kind === "FirstWriterWins"
|
|
545
|
+
? { kind: "FirstWriterCandidates" }
|
|
546
|
+
: driver.kind === "MapOf" && (driver.inner as { kind?: string } | undefined)?.kind === "FirstWriterWins"
|
|
547
|
+
? { kind: "MapOf", inner: { kind: "FirstWriterCandidates" } }
|
|
548
|
+
: undefined;
|
|
549
|
+
for (const [name, f] of Object.entries(stored)) {
|
|
550
|
+
const swapped = candidates((f as Field).driver as { kind: string; inner?: unknown });
|
|
551
|
+
if (swapped === undefined) continue;
|
|
552
|
+
// Clone by descriptors: a lazy `t.ref(() => Agg)` getter must not be forced here.
|
|
553
|
+
const clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(f)) as Field;
|
|
554
|
+
Object.defineProperty(clone, "driver", {
|
|
555
|
+
value: swapped,
|
|
556
|
+
enumerable: true,
|
|
557
|
+
configurable: true,
|
|
558
|
+
writable: false,
|
|
559
|
+
});
|
|
560
|
+
(stored as Record<string, Field>)[name] = clone;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const LWW_CLASS_KINDS = new Set(["FirstWriterWins", "FirstWriterCandidates", "Lww", "LwwCausal", "LwwBy"]);
|
|
505
564
|
const attributableDriver = (f: Field) => LWW_CLASS_KINDS.has((f.driver as { kind?: string }).kind ?? "");
|
|
506
565
|
const attributableKind = (f: Field) =>
|
|
507
566
|
f.kind !== "set" && f.kind !== "map" && f.kind !== "counter" && f.kind !== "position";
|
|
@@ -574,22 +633,23 @@ export function aggregate<const Id extends string, F extends Record<string, Fiel
|
|
|
574
633
|
const fulfils = opts?.fulfils;
|
|
575
634
|
const afterFulfilment: AggregateInvariantFn | undefined =
|
|
576
635
|
fulfils !== undefined
|
|
577
|
-
? (snapshot) => {
|
|
636
|
+
? (snapshot, previous) => {
|
|
578
637
|
const verdict = fulfils.invariant(snapshot);
|
|
579
638
|
if ("reject" in verdict) return { reject: `${id}: ${verdict.reject}` };
|
|
580
|
-
|
|
639
|
+
if ("refuse" in verdict) return verdict;
|
|
640
|
+
return userInvariant !== undefined ? userInvariant(snapshot, previous) : { accept: true };
|
|
581
641
|
}
|
|
582
642
|
: userInvariant;
|
|
583
643
|
const composedInvariant: AggregateInvariantFn | undefined =
|
|
584
644
|
fromBirthFields.length > 0
|
|
585
|
-
? (snapshot) => {
|
|
645
|
+
? (snapshot, previous) => {
|
|
586
646
|
for (const name of fromBirthFields) {
|
|
587
647
|
const v = snapshot[name];
|
|
588
648
|
if (v === undefined || v === null) {
|
|
589
649
|
return { reject: `${id}.${name} is fromBirth() — every ${id} must carry it from creation (the plan left it unset)` };
|
|
590
650
|
}
|
|
591
651
|
}
|
|
592
|
-
return afterFulfilment !== undefined ? afterFulfilment(snapshot) : { accept: true };
|
|
652
|
+
return afterFulfilment !== undefined ? afterFulfilment(snapshot, previous) : { accept: true };
|
|
593
653
|
}
|
|
594
654
|
: afterFulfilment;
|
|
595
655
|
|
|
@@ -661,12 +721,12 @@ export function aggregate<const Id extends string, F extends Record<string, Fiel
|
|
|
661
721
|
// `.fromBirth()` plus the composed invariant means even a hand-authored create cannot omit it.
|
|
662
722
|
ownedFields[OWNER_FIELD] = attributionField(t.string().fromBirth());
|
|
663
723
|
ownedEncrypted.sort();
|
|
664
|
-
ownedInvariant = (snapshot) => {
|
|
724
|
+
ownedInvariant = (snapshot, previous) => {
|
|
665
725
|
const owner = snapshot[OWNER_FIELD];
|
|
666
726
|
if (typeof owner !== "string" || owner.length === 0) {
|
|
667
727
|
return { reject: `${id} is .owned() — Nomos must stamp its verified creator` };
|
|
668
728
|
}
|
|
669
|
-
return composedInvariant !== undefined ? composedInvariant(snapshot) : { accept: true };
|
|
729
|
+
return composedInvariant !== undefined ? composedInvariant(snapshot, previous) : { accept: true };
|
|
670
730
|
};
|
|
671
731
|
}
|
|
672
732
|
|
|
@@ -737,7 +797,7 @@ export function aggregate<const Id extends string, F extends Record<string, Fiel
|
|
|
737
797
|
|
|
738
798
|
/** Lww-class driver: a wholesale-replace merge (`Lww`, or `MapOf` wrapping an Lww-class inner). */
|
|
739
799
|
function isLwwClass(driver: { kind: string; inner?: { kind: string } }): boolean {
|
|
740
|
-
if (driver.kind === "FirstWriterWins" || driver.kind === "Lww") return true;
|
|
800
|
+
if (driver.kind === "FirstWriterWins" || driver.kind === "FirstWriterCandidates" || driver.kind === "Lww") return true;
|
|
741
801
|
if (driver.kind === "MapOf" && driver.inner) return isLwwClass(driver.inner as { kind: string });
|
|
742
802
|
return false;
|
|
743
803
|
}
|
|
@@ -17,8 +17,8 @@ type TopologyDirective = DomainModule["directives"][number] & {
|
|
|
17
17
|
export interface ApplicationTopology {
|
|
18
18
|
/** Co-resident business domains bound to the application workspace. */
|
|
19
19
|
readonly rootDomains: readonly string[];
|
|
20
|
-
/**
|
|
21
|
-
readonly
|
|
20
|
+
/** Domains whose law lives in a verified parent workspace. This is lineage, never placement. */
|
|
21
|
+
readonly parentWorkspaceDomains: readonly string[];
|
|
22
22
|
/** Deterministic primary facet for generated narration/scenarios; not a storage-topology choice. */
|
|
23
23
|
readonly homeDomain: string;
|
|
24
24
|
readonly homeModule: DomainModule;
|
|
@@ -39,8 +39,9 @@ const publicLanguageOf = (module: DomainModule): readonly TopologyDirective[] =>
|
|
|
39
39
|
*
|
|
40
40
|
* Domains are vocabulary, not storage partitions. They are co-resident by default. A declared
|
|
41
41
|
* cross-domain business birth is the evidence that its target belongs in a child workspace; a
|
|
42
|
-
* verified-parent effect is
|
|
43
|
-
*
|
|
42
|
+
* verified-parent effect is evidence only that its target belongs in a different workspace and
|
|
43
|
+
* must not be bound into the participant's receiving group. Neither relationship says where either
|
|
44
|
+
* workspace is placed, replicated, or executed.
|
|
44
45
|
*
|
|
45
46
|
* The primary domain is only a deterministic generated-surface/narration choice: an explicit receiving-group
|
|
46
47
|
* language wins, then a literal `home`, then declaration order. It does not move the other root domains.
|
|
@@ -68,7 +69,7 @@ export function resolveApplicationTopology(
|
|
|
68
69
|
const homeDomain = domainOf(homeModule);
|
|
69
70
|
return {
|
|
70
71
|
rootDomains: [homeDomain],
|
|
71
|
-
|
|
72
|
+
parentWorkspaceDomains: [],
|
|
72
73
|
homeDomain,
|
|
73
74
|
homeModule,
|
|
74
75
|
};
|
|
@@ -108,7 +109,7 @@ export function resolveApplicationTopology(
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
const targetedByAnotherDomain = new Set<string>();
|
|
111
|
-
const
|
|
112
|
+
const parentWorkspaceDomains = new Set<string>();
|
|
112
113
|
const parentsByDomain = new Map<string, Set<string>>();
|
|
113
114
|
const childrenByDomain = new Map<string, Set<string>>();
|
|
114
115
|
const birthSources = new Set<string>();
|
|
@@ -149,7 +150,7 @@ export function resolveApplicationTopology(
|
|
|
149
150
|
for (const parent of parentsByDomain.get(source) ?? []) {
|
|
150
151
|
if (seen.has(parent)) continue;
|
|
151
152
|
seen.add(parent);
|
|
152
|
-
|
|
153
|
+
parentWorkspaceDomains.add(parent);
|
|
153
154
|
pending.push(parent);
|
|
154
155
|
}
|
|
155
156
|
}
|
|
@@ -157,7 +158,7 @@ export function resolveApplicationTopology(
|
|
|
157
158
|
// Packages without an explicit receiving group retain the conservative interpretation: a
|
|
158
159
|
// verified-parent target cannot be silently opened in the same workspace as its requester.
|
|
159
160
|
for (const parents of parentsByDomain.values()) {
|
|
160
|
-
for (const parent of parents)
|
|
161
|
+
for (const parent of parents) parentWorkspaceDomains.add(parent);
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
|
|
@@ -176,7 +177,13 @@ export function resolveApplicationTopology(
|
|
|
176
177
|
const target = [...owners][0]!;
|
|
177
178
|
birthSources.add(source);
|
|
178
179
|
if (target !== source) {
|
|
179
|
-
|
|
180
|
+
// A verified ancestor may birth both the participant receiving group
|
|
181
|
+
// and other sibling workspaces. Only the participant itself is rooted
|
|
182
|
+
// in this generated application; the ancestor's other children remain
|
|
183
|
+
// separate lives and are opened through typed references.
|
|
184
|
+
const isParticipantBirthFromAncestor =
|
|
185
|
+
parentWorkspaceDomains.has(source) && target === participantDomain;
|
|
186
|
+
if (!isParticipantBirthFromAncestor) {
|
|
180
187
|
targetedByAnotherDomain.add(target);
|
|
181
188
|
}
|
|
182
189
|
const children = childrenByDomain.get(source) ?? new Set<string>();
|
|
@@ -209,7 +216,7 @@ export function resolveApplicationTopology(
|
|
|
209
216
|
const rootModules = modules.filter((module) => {
|
|
210
217
|
const domain = domainOf(module);
|
|
211
218
|
return (
|
|
212
|
-
!targetedByAnotherDomain.has(domain) && !
|
|
219
|
+
!targetedByAnotherDomain.has(domain) && !parentWorkspaceDomains.has(domain)
|
|
213
220
|
);
|
|
214
221
|
});
|
|
215
222
|
const rootDomains = rootModules.map(domainOf);
|
|
@@ -236,7 +243,7 @@ export function resolveApplicationTopology(
|
|
|
236
243
|
rootModules[0]!;
|
|
237
244
|
return {
|
|
238
245
|
rootDomains,
|
|
239
|
-
|
|
246
|
+
parentWorkspaceDomains: [...parentWorkspaceDomains],
|
|
240
247
|
homeDomain: domainOf(homeModule),
|
|
241
248
|
homeModule,
|
|
242
249
|
};
|
package/src/attested.ts
CHANGED
|
@@ -29,8 +29,10 @@ import { NomosSourceFrontier } from "./attested_core.js";
|
|
|
29
29
|
export {
|
|
30
30
|
trustSource,
|
|
31
31
|
trustParent,
|
|
32
|
+
trustAuthorizedSource,
|
|
32
33
|
PARENT_TRUST_SENTINEL,
|
|
33
34
|
foreignQuery,
|
|
35
|
+
attestedReadSubject,
|
|
34
36
|
isTrustSourceDecl,
|
|
35
37
|
trustPolicy,
|
|
36
38
|
isTrustPolicyDecl,
|
|
@@ -48,6 +50,7 @@ export {
|
|
|
48
50
|
type FromPayloadRef,
|
|
49
51
|
type ForeignReadEdge,
|
|
50
52
|
type ForeignQueryRef,
|
|
53
|
+
type AttestedReadSubjectRef,
|
|
51
54
|
} from "./attested_core.js";
|
|
52
55
|
|
|
53
56
|
/**
|
package/src/attested_core.ts
CHANGED
|
@@ -24,6 +24,30 @@ export interface ForeignQueryRef {
|
|
|
24
24
|
readonly __nomosForeignQuery: true;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Select the sovereign source workspace proven by one declared attested read as
|
|
29
|
+
* the subject of a directive's ordinary Zanzibar `.requires(...)` check.
|
|
30
|
+
*
|
|
31
|
+
* This is not a second authentication policy. It only chooses which already-
|
|
32
|
+
* verified subject the existing relation gate checks: the session principal by
|
|
33
|
+
* default, or the proven `workspace:<source address>` for the named foreign
|
|
34
|
+
* read. The attested-read gate separately binds that address to its trusted
|
|
35
|
+
* genesis before the relation check can run.
|
|
36
|
+
*/
|
|
37
|
+
export interface AttestedReadSubjectRef {
|
|
38
|
+
readonly queryId: string;
|
|
39
|
+
readonly __nomosAttestedReadSubject: true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function attestedReadSubject(
|
|
43
|
+
query: ForeignQueryRef | { readonly id: string },
|
|
44
|
+
): AttestedReadSubjectRef {
|
|
45
|
+
if (query.id.trim().length === 0) {
|
|
46
|
+
throw new Error("attestedReadSubject(): query id must not be empty");
|
|
47
|
+
}
|
|
48
|
+
return { queryId: query.id, __nomosAttestedReadSubject: true };
|
|
49
|
+
}
|
|
50
|
+
|
|
27
51
|
/** Name a query of the SOURCE workspace's law by id (see {@link ForeignQueryRef}). */
|
|
28
52
|
export function foreignQuery(id: string): ForeignQueryRef {
|
|
29
53
|
return { id, __nomosForeignQuery: true };
|
|
@@ -186,12 +210,14 @@ export interface TrustPolicyOptions {
|
|
|
186
210
|
* Lowered into the `nomosAttestedReadGate` era key's `policies` map. */
|
|
187
211
|
export interface TrustPolicyDecl {
|
|
188
212
|
readonly policyId: string;
|
|
213
|
+
/** A signed source attribution whose authority is decided by the directive's Zanzibar gate. */
|
|
214
|
+
readonly authorizationOnly?: boolean;
|
|
189
215
|
/** The resolved allow-list aggregate TYPE id. */
|
|
190
|
-
readonly allowListType
|
|
216
|
+
readonly allowListType?: string;
|
|
191
217
|
/** The resolved genesis field LABEL. */
|
|
192
|
-
readonly genesisField
|
|
218
|
+
readonly genesisField?: string;
|
|
193
219
|
/** The resolved keyHashes field LABEL. */
|
|
194
|
-
readonly keysField
|
|
220
|
+
readonly keysField?: string;
|
|
195
221
|
readonly maxAgeMs?: number;
|
|
196
222
|
readonly minSourceEpoch?: "birth" | number;
|
|
197
223
|
readonly monotone?: boolean;
|
|
@@ -199,6 +225,23 @@ export interface TrustPolicyDecl {
|
|
|
199
225
|
readonly __nomosTrustPolicy: true;
|
|
200
226
|
}
|
|
201
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Declare a payload-routed, signed source attribution whose authority is decided by the
|
|
230
|
+
* directive's ordinary Zanzibar requirement. Co-located custody verifies the exact read now;
|
|
231
|
+
* otherwise the signed source/frontier/result remains replayable evidence for later reconciliation.
|
|
232
|
+
* The compiler refuses this policy unless the directive derives its relation subject from the
|
|
233
|
+
* same attested read.
|
|
234
|
+
*/
|
|
235
|
+
export function trustAuthorizedSource(policyId: string): TrustPolicyDecl {
|
|
236
|
+
const decl: TrustPolicyDecl = {
|
|
237
|
+
policyId,
|
|
238
|
+
authorizationOnly: true,
|
|
239
|
+
__nomosTrustPolicy: true,
|
|
240
|
+
};
|
|
241
|
+
policyRegistry.set(policyId, decl);
|
|
242
|
+
return decl;
|
|
243
|
+
}
|
|
244
|
+
|
|
202
245
|
// The runtime policy registry — the dynamic read lane resolves a policy's monotone posture through
|
|
203
246
|
// the directive's readsFrom (which registers the queryId); this map lets the compile discovery + the
|
|
204
247
|
// validators resolve a decl by id. Keyed by policyId; later declaration wins.
|
|
@@ -53,14 +53,17 @@ import {
|
|
|
53
53
|
BirthAttestationLink,
|
|
54
54
|
birthAttestation,
|
|
55
55
|
seedBirthAttestation,
|
|
56
|
-
} from "./framework/
|
|
56
|
+
} from "./framework/receiving_group.js";
|
|
57
57
|
import { requireParentAttestedBirth } from "./births.js";
|
|
58
58
|
import {
|
|
59
59
|
SignerDelegation,
|
|
60
60
|
enrollDelegation,
|
|
61
|
+
enrollFirstDevice,
|
|
61
62
|
enrollSigner,
|
|
62
63
|
enrollSignerSelf,
|
|
63
64
|
enrollSignerSelfRequiresVerified,
|
|
65
|
+
enrollDelegationRetainsEvidence,
|
|
66
|
+
enrollFirstDeviceRetainsEvidence,
|
|
64
67
|
identityRelations,
|
|
65
68
|
signerDelegationByUser,
|
|
66
69
|
signerObject,
|
|
@@ -75,8 +78,10 @@ import {
|
|
|
75
78
|
import { refAs, workspaceInvariant } from "./framework/workspace_invariant.js";
|
|
76
79
|
import { isRelationTypeDecl, type RelationTypeDecl } from "./relation_schema.js";
|
|
77
80
|
|
|
78
|
-
/**
|
|
79
|
-
*
|
|
81
|
+
/** Child genesis may already inherit the founder's active device roster through model authority.
|
|
82
|
+
* Re-establishing that same active key must compose with those other devices. This door remains
|
|
83
|
+
* genesis-only and cannot add a different key to a nonempty roster or reactivate a revoked key.
|
|
84
|
+
* The v1 evaluator remains in the kernel for replay of previously installed law. */
|
|
80
85
|
const bornFounderSignerWriteOnce = workspaceInvariant("FounderSignerWriteOnce")
|
|
81
86
|
.on("enrollSigner")
|
|
82
87
|
.reads((ctx) => [
|
|
@@ -85,11 +90,15 @@ const bornFounderSignerWriteOnce = workspaceInvariant("FounderSignerWriteOnce")
|
|
|
85
90
|
"RelationTuple",
|
|
86
91
|
"pre:" + relationTupleInstanceId(signerObject(String(ctx.principal ?? "")), "signer"),
|
|
87
92
|
),
|
|
93
|
+
refAs("warrant", "GenesisWarrant", "pre:" + GENESIS_WARRANT_ID),
|
|
88
94
|
])
|
|
89
|
-
.assert(({ tuple }, ctx) => {
|
|
90
|
-
|
|
95
|
+
.assert(({ tuple, warrant }, ctx) => {
|
|
96
|
+
if ((warrant as { principal?: string } | undefined)?.principal) {
|
|
97
|
+
return { reject: "founding-signer-genesis-only" };
|
|
98
|
+
}
|
|
99
|
+
const subjects = (tuple as { subjects?: Record<string, { status?: string }> })?.subjects ?? {};
|
|
91
100
|
const want = "key:" + String((ctx?.intent ?? {}).keyHash ?? "");
|
|
92
|
-
return Object.keys(subjects).
|
|
101
|
+
return Object.keys(subjects).length === 0 || subjects[want]?.status === "active"
|
|
93
102
|
? { accept: true }
|
|
94
103
|
: { reject: "founding-signer-already-enrolled" };
|
|
95
104
|
});
|
|
@@ -99,7 +108,7 @@ const bornFounderSignerWriteOnce = workspaceInvariant("FounderSignerWriteOnce")
|
|
|
99
108
|
// folded tuple instead of booting a tenant report sandbox during every child genesis.
|
|
100
109
|
const nativeBornFounderSignerWriteOnce = {
|
|
101
110
|
...bornFounderSignerWriteOnce,
|
|
102
|
-
__nomosEvaluator: "founder-signer-write-once-
|
|
111
|
+
__nomosEvaluator: "founder-signer-write-once-v2" as const,
|
|
103
112
|
};
|
|
104
113
|
|
|
105
114
|
/**
|
|
@@ -303,6 +312,9 @@ export function withBirthMeterExports<M extends Record<string, unknown>>(mod: M)
|
|
|
303
312
|
// but never appear in TS/Dart/OpenAPI tenant surfaces.
|
|
304
313
|
internalize("__nomos_SignerDelegation", SignerDelegation);
|
|
305
314
|
internalize("__nomos_enrollDelegation", enrollDelegation);
|
|
315
|
+
internalize("__nomos_enrollFirstDevice", enrollFirstDevice);
|
|
316
|
+
internalize("__nomos_enrollDelegationRetainsEvidence", enrollDelegationRetainsEvidence);
|
|
317
|
+
internalize("__nomos_enrollFirstDeviceRetainsEvidence", enrollFirstDeviceRetainsEvidence);
|
|
306
318
|
internalize("__nomos_signerDelegationByUser", signerDelegationByUser);
|
|
307
319
|
reserve("__nomos_parentAttestedBirth", internal({
|
|
308
320
|
...requireParentAttestedBirth,
|
package/src/births.ts
CHANGED
|
@@ -55,6 +55,20 @@ export function workspaceRole<const Name extends string>(name: Name): Name & Wor
|
|
|
55
55
|
return name as Name & WorkspaceRole;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* THE FRAMEWORK'S OWN PARENT-WORKSPACE ROLES. These are constants of the receiving-group lifecycle,
|
|
60
|
+
* not tenant vocabulary: every born workspace seats {@link AUTH_PROVIDER_AUTHORITY} for its verified
|
|
61
|
+
* immediate parent at genesis (so the parent may advance the child's verifier epoch and repair its
|
|
62
|
+
* device authentication), and every birthing parent seats {@link AUTH_PROVIDER_EPOCH_CONSUMER} for
|
|
63
|
+
* the child it births (so the child may ask for the parent's current verifier epoch). A tenant
|
|
64
|
+
* declares neither; `birth(...)` and the receiving-group birth seat both by construction.
|
|
65
|
+
*/
|
|
66
|
+
/** The workspace whose signed provider material this workspace adopts (its verified birth parent). */
|
|
67
|
+
export const AUTH_PROVIDER_AUTHORITY = workspaceRole("authProviderAuthority");
|
|
68
|
+
/** Parent-owned permission for an immediate child to request the parent's current verifier epoch.
|
|
69
|
+
* Deliberately the inverse of {@link AUTH_PROVIDER_AUTHORITY}: requests flow up, epochs flow down. */
|
|
70
|
+
export const AUTH_PROVIDER_EPOCH_CONSUMER = workspaceRole("authProviderEpochConsumer");
|
|
71
|
+
|
|
58
72
|
/** Declare target-owned roles which a born workspace may grant to its verified immediate parent.
|
|
59
73
|
* The matching relation is necessarily on Nomos's canonical global `workspace` object and accepts
|
|
60
74
|
* only another nominal workspace subject. Keeping this shape behind the branded WorkspaceRole API
|
|
@@ -240,7 +254,12 @@ export function birth<F extends Record<string, Field>>(
|
|
|
240
254
|
"zero declares a leaf workspace and Nomos has no compiled fallback",
|
|
241
255
|
);
|
|
242
256
|
}
|
|
243
|
-
|
|
257
|
+
// The verified parent is ALWAYS this child's provider authority: the framework's child-authentication
|
|
258
|
+
// lane (verifier-epoch delivery + device repair) gates on it, so the framework seats it. A tenant that
|
|
259
|
+
// restates the constant is deduplicated, never doubled; a tenant adds only its own further roles.
|
|
260
|
+
const parentWorkspaceRoles = [
|
|
261
|
+
...new Set([AUTH_PROVIDER_AUTHORITY, ...(spec.parentWorkspace?.roles ?? [])]),
|
|
262
|
+
].sort();
|
|
244
263
|
type Payload = BusinessBirthPayload<F>;
|
|
245
264
|
const aggregateNoun = aggregate.id
|
|
246
265
|
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
@@ -298,8 +317,14 @@ declare const nomos: { sha256(input: string): string };
|
|
|
298
317
|
* minted-and-forgotten; it is a pure function of a key the caller already owns (a business id, an owner uid).
|
|
299
318
|
* The `` (unit separator) makes `(ns,key)` unambiguous. `nomos.sha256` returns lowercase hex.
|
|
300
319
|
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
320
|
+
* THE ONE PEER-SIDE MIRROR is `keyedBirthNameOf` in `peer-office/src/runtime/workspace_naming.ts`, which the
|
|
321
|
+
* office serves to every client through `ResolveWorkspaceNameRequest`. Clients ASK; they do not re-derive —
|
|
322
|
+
* a client-local copy of this function is a second implementation of a law fact, and the two drift silently.
|
|
323
|
+
* The vectors below are pinned there by `peer-office/test/workspace_naming.test.ts`:
|
|
324
|
+
*
|
|
325
|
+
* ("estate", "estate-abc123") -> estate-83662e729ba18cd04bde52c7a8d854594833d70e
|
|
326
|
+
* ("home", "user:ada") -> home-561af44c94b5b80824f1a9e8cfa1095105f3cb34
|
|
327
|
+
* ("catalogue", "cat-42") -> catalogue-f50bf3b9732dc36961b05b8e6503d96df5f3e88e
|
|
303
328
|
*/
|
|
304
329
|
export const WORKSPACE_NAME_SEP = "\u001f"; // unit separator disambiguates (namespace,key)
|
|
305
330
|
export function workspaceNameForKey(namespace: string, key: string): string {
|
|
@@ -368,7 +393,7 @@ export const birthInstance = ({
|
|
|
368
393
|
*
|
|
369
394
|
* `birth.singleton(...)` — a keyed birth whose key is a NATURAL single key (one home per user: key = owner).
|
|
370
395
|
* Sugar over {@link birthKeyed}: `birth.singleton({ keyedBy: owner, namespace: "home" })`. Same addressing
|
|
371
|
-
* story — the client
|
|
396
|
+
* story — the client asks the office for the name with `ResolveWorkspaceNameRequest.keyed`.
|
|
372
397
|
*/
|
|
373
398
|
export const birthSingleton = ({
|
|
374
399
|
keyedBy,
|