@githolon/dsl 0.108.7 → 0.110.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +80 -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 +214 -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 +268 -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 +23950 -15776
- 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 +550 -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_event_desk_close_test.dart +16 -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 +1276 -0
- package/src/codegen_call_usda.ts +49 -6
- package/src/codegen_dart.ts +83 -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 +2017 -1195
- 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
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
declare const PEER_CLASS: unique symbol;
|
|
2
|
+
|
|
3
|
+
/** A stable class of peer used by custody-placement declarations. */
|
|
4
|
+
export type PeerClass<Name extends string = string> = Name & {
|
|
5
|
+
readonly [PEER_CLASS]: true;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Whether this peer should keep custodied workspace state open in kernel memory.
|
|
10
|
+
* This is independent of durable/offline Git retention.
|
|
11
|
+
*/
|
|
12
|
+
export type KernelResidency = "warm" | "on-demand";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Whether this peer should retain durable Git custody independently of memory residency.
|
|
16
|
+
* `retain`, not `warm`, is the policy that makes existing custody survive restart/offline use.
|
|
17
|
+
*/
|
|
18
|
+
export type CustodyRetention = "retain" | "cache" | "none";
|
|
19
|
+
|
|
20
|
+
/** A named reception route selected by placement policy, never part of `NomosRef<T>`. */
|
|
21
|
+
export interface CustodyRemote<Name extends string = string> {
|
|
22
|
+
readonly __isCustodyRemote: true;
|
|
23
|
+
readonly name: Name;
|
|
24
|
+
readonly url: string;
|
|
25
|
+
readonly peer: string;
|
|
26
|
+
readonly priority: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface CustodyPlacementRule {
|
|
30
|
+
readonly peerClass: PeerClass;
|
|
31
|
+
readonly kernelResidency: KernelResidency;
|
|
32
|
+
readonly custodyRetention: CustodyRetention;
|
|
33
|
+
readonly remotes: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A domain-shipped placement option. This is not live workspace policy.
|
|
38
|
+
*
|
|
39
|
+
* A workspace adopts one declaration on its independent placement frontier;
|
|
40
|
+
* evolving main law never adopts or changes it implicitly. Generated clients
|
|
41
|
+
* address stable workspace identities; the peer runtime resolves this policy.
|
|
42
|
+
* Do not copy its remotes or retention choices into domain records or Nomos refs.
|
|
43
|
+
*/
|
|
44
|
+
export interface CustodyPlacementDeclaration<Id extends string = string> {
|
|
45
|
+
readonly __isCustodyPlacement: true;
|
|
46
|
+
readonly id: Id;
|
|
47
|
+
readonly remotes: readonly CustodyRemote[];
|
|
48
|
+
readonly rules: readonly CustodyPlacementRule[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const identifier = (kind: string, value: string): void => {
|
|
52
|
+
if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(value)) {
|
|
53
|
+
throw new Error(`${kind} '${value}' is not a stable Nomos identifier`);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function peerClass<const Name extends string>(name: Name): PeerClass<Name> {
|
|
58
|
+
identifier("peer class", name);
|
|
59
|
+
return name as PeerClass<Name>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function custodyRemote<const Name extends string>(
|
|
63
|
+
name: Name,
|
|
64
|
+
url: string,
|
|
65
|
+
options: { readonly peer: string; readonly priority?: number },
|
|
66
|
+
): CustodyRemote<Name> {
|
|
67
|
+
identifier("custody remote", name);
|
|
68
|
+
if (!options.peer.trim()) throw new Error(`custody remote '${name}' requires a peer identity`);
|
|
69
|
+
let parsed: URL;
|
|
70
|
+
try {
|
|
71
|
+
parsed = new URL(url);
|
|
72
|
+
} catch {
|
|
73
|
+
throw new Error(`custody remote '${name}' has invalid URL '${url}'`);
|
|
74
|
+
}
|
|
75
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
76
|
+
throw new Error(`custody remote '${name}' requires an HTTP(S) URL`);
|
|
77
|
+
}
|
|
78
|
+
const priority = options.priority ?? 0;
|
|
79
|
+
if (!Number.isSafeInteger(priority) || priority < 0) {
|
|
80
|
+
throw new Error(`custody remote '${name}' priority must be a non-negative integer`);
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
__isCustodyRemote: true,
|
|
84
|
+
name,
|
|
85
|
+
url: parsed.toString(),
|
|
86
|
+
peer: options.peer,
|
|
87
|
+
priority,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function custodyPlacementRule(
|
|
92
|
+
peer: PeerClass,
|
|
93
|
+
policy: {
|
|
94
|
+
readonly kernelResidency: KernelResidency;
|
|
95
|
+
readonly custodyRetention: CustodyRetention;
|
|
96
|
+
readonly remotes?: readonly CustodyRemote[];
|
|
97
|
+
},
|
|
98
|
+
): CustodyPlacementRule {
|
|
99
|
+
return Object.freeze({
|
|
100
|
+
peerClass: peer,
|
|
101
|
+
kernelResidency: policy.kernelResidency,
|
|
102
|
+
custodyRetention: policy.custodyRetention,
|
|
103
|
+
remotes: Object.freeze((policy.remotes ?? []).map((remote) => remote.name)),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function custodyPlacement<const Id extends string>(
|
|
108
|
+
id: Id,
|
|
109
|
+
policy: {
|
|
110
|
+
readonly remotes?: readonly CustodyRemote[];
|
|
111
|
+
readonly rules: readonly CustodyPlacementRule[];
|
|
112
|
+
},
|
|
113
|
+
): CustodyPlacementDeclaration<Id> {
|
|
114
|
+
identifier("custody placement", id);
|
|
115
|
+
const rules = policy.rules;
|
|
116
|
+
if (rules.length === 0) {
|
|
117
|
+
throw new Error(`custody placement '${id}' declares no peer rules`);
|
|
118
|
+
}
|
|
119
|
+
const remotes = [...(policy.remotes ?? [])];
|
|
120
|
+
const remoteNames = new Set<string>();
|
|
121
|
+
for (const remote of remotes) {
|
|
122
|
+
if (!remoteNames.add(remote.name)) {
|
|
123
|
+
throw new Error(`custody placement '${id}' repeats remote '${remote.name}'`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const seen = new Set<string>();
|
|
127
|
+
for (const rule of rules) {
|
|
128
|
+
if (seen.has(rule.peerClass)) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`custody placement '${id}' repeats peer class '${rule.peerClass}'`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
seen.add(rule.peerClass);
|
|
134
|
+
for (const remote of rule.remotes) {
|
|
135
|
+
if (!remoteNames.has(remote)) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`custody placement '${id}' rule for '${rule.peerClass}' references unknown remote '${remote}'`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return Object.freeze({
|
|
143
|
+
__isCustodyPlacement: true,
|
|
144
|
+
id,
|
|
145
|
+
remotes: Object.freeze(remotes),
|
|
146
|
+
rules: Object.freeze([...rules]),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function isCustodyPlacementDeclaration(
|
|
151
|
+
value: unknown,
|
|
152
|
+
): value is CustodyPlacementDeclaration {
|
|
153
|
+
return value !== null
|
|
154
|
+
&& typeof value === "object"
|
|
155
|
+
&& (value as { __isCustodyPlacement?: unknown }).__isCustodyPlacement === true;
|
|
156
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CustodyPlacementDeclaration,
|
|
3
|
+
} from "./custody_placement.js";
|
|
4
|
+
import { usdaString } from "./usda_text.js";
|
|
5
|
+
|
|
6
|
+
export interface DomainCustodyPlacement {
|
|
7
|
+
readonly domain: string;
|
|
8
|
+
readonly declaration: CustodyPlacementDeclaration;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const primName = (value: string): string =>
|
|
12
|
+
value.replace(/[^A-Za-z0-9_]/g, (character) =>
|
|
13
|
+
`_x${character.codePointAt(0)!.toString(16).padStart(2, "0")}_`
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
/** Emit independently adoptable placement declarations, never main law. */
|
|
17
|
+
export function custodyPlacementDeclarationsUsda(
|
|
18
|
+
declarations: readonly DomainCustodyPlacement[],
|
|
19
|
+
): string {
|
|
20
|
+
const ordered = [...declarations].sort((left, right) => {
|
|
21
|
+
const domain = left.domain.localeCompare(right.domain);
|
|
22
|
+
return domain !== 0
|
|
23
|
+
? domain
|
|
24
|
+
: left.declaration.id.localeCompare(right.declaration.id);
|
|
25
|
+
});
|
|
26
|
+
const identities = new Set<string>();
|
|
27
|
+
for (const { domain, declaration } of ordered) {
|
|
28
|
+
const identity = `${domain}/${declaration.id}`;
|
|
29
|
+
if (!identities.add(identity)) {
|
|
30
|
+
throw new Error(`custody placement declaration '${identity}' is repeated`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return [
|
|
35
|
+
"#usda 1.0",
|
|
36
|
+
"(",
|
|
37
|
+
' defaultPrim = "NomosPlacementDeclarations"',
|
|
38
|
+
" customLayerData = {",
|
|
39
|
+
' string "nomos:format" = "nomos.custody-placement-declarations.v1"',
|
|
40
|
+
" }",
|
|
41
|
+
")",
|
|
42
|
+
"",
|
|
43
|
+
'def Scope "NomosPlacementDeclarations"',
|
|
44
|
+
"{",
|
|
45
|
+
...ordered.flatMap(({ domain, declaration }) => [
|
|
46
|
+
` def Scope ${usdaString(`d_${primName(domain)}__${primName(declaration.id)}`)}`,
|
|
47
|
+
" {",
|
|
48
|
+
` custom string nomos:domain = ${usdaString(domain)}`,
|
|
49
|
+
` custom string nomos:declaration = ${usdaString(declaration.id)}`,
|
|
50
|
+
"",
|
|
51
|
+
' def Scope "Remotes"',
|
|
52
|
+
" {",
|
|
53
|
+
...[...declaration.remotes]
|
|
54
|
+
.sort((left, right) => left.name.localeCompare(right.name))
|
|
55
|
+
.flatMap((remote) => [
|
|
56
|
+
` def NomosCustodyRemote ${usdaString(`r_${primName(remote.name)}`)}`,
|
|
57
|
+
" {",
|
|
58
|
+
` custom string nomos:name = ${usdaString(remote.name)}`,
|
|
59
|
+
` custom string nomos:url = ${usdaString(remote.url)}`,
|
|
60
|
+
` custom string nomos:peer = ${usdaString(remote.peer)}`,
|
|
61
|
+
` custom int nomos:priority = ${remote.priority}`,
|
|
62
|
+
" }",
|
|
63
|
+
]),
|
|
64
|
+
" }",
|
|
65
|
+
"",
|
|
66
|
+
' def Scope "Rules"',
|
|
67
|
+
" {",
|
|
68
|
+
...[...declaration.rules]
|
|
69
|
+
.sort((left, right) => left.peerClass.localeCompare(right.peerClass))
|
|
70
|
+
.flatMap((rule, index) => [
|
|
71
|
+
` def Scope "r_${String(index).padStart(4, "0")}"`,
|
|
72
|
+
" {",
|
|
73
|
+
` custom token nomos:peerClass = ${usdaString(rule.peerClass)}`,
|
|
74
|
+
` custom token nomos:kernelResidency = ${usdaString(rule.kernelResidency)}`,
|
|
75
|
+
` custom token nomos:custodyRetention = ${usdaString(rule.custodyRetention)}`,
|
|
76
|
+
...(rule.remotes.length === 0
|
|
77
|
+
? []
|
|
78
|
+
: [
|
|
79
|
+
` rel nomos:remotes = [${rule.remotes
|
|
80
|
+
.map((remote) => `</NomosPlacementDeclarations/d_${primName(domain)}__${primName(declaration.id)}/Remotes/r_${primName(remote)}>`)
|
|
81
|
+
.join(", ")}]`,
|
|
82
|
+
]),
|
|
83
|
+
" }",
|
|
84
|
+
]),
|
|
85
|
+
" }",
|
|
86
|
+
" }",
|
|
87
|
+
]),
|
|
88
|
+
"}",
|
|
89
|
+
"",
|
|
90
|
+
].join("\n");
|
|
91
|
+
}
|
package/src/decl_shapes.ts
CHANGED
|
@@ -20,6 +20,9 @@ import type { QueryDecl } from "./query.js";
|
|
|
20
20
|
import type { SpatialDecl } from "./spatial.js";
|
|
21
21
|
import type { AnySum } from "./sum.js";
|
|
22
22
|
import type { AnyCount } from "./count.js";
|
|
23
|
+
import type { AnyExtremum } from "./extremum.js";
|
|
24
|
+
import type { AnyExists } from "./exists.js";
|
|
25
|
+
import type { OrderedReadDecl } from "./ordered_read.js";
|
|
23
26
|
import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
|
|
24
27
|
|
|
25
28
|
/** A merged domain-module exports bag (scanned by shape). */
|
|
@@ -79,7 +82,7 @@ export function isCountDecl(v: unknown): v is AnyCount {
|
|
|
79
82
|
!("field" in o) && // extremum (wire-descriptor shape)
|
|
80
83
|
!("valueField" in o) && // extremum (the ExtremumDecl/Extremum-builder mark — never a count)
|
|
81
84
|
!("sumField" in o) && // sum (the SumDecl/Sum-builder mark — never a count)
|
|
82
|
-
!("orderBy" in o) && // ordered read
|
|
85
|
+
!("orderBy" in o) && !("orderKey" in o) && // unfinished/finished ordered read
|
|
83
86
|
!("_existsMarker" in o) && // exists
|
|
84
87
|
typeof o.refField !== "string" && // combined
|
|
85
88
|
o.__isAggregateHandle !== true && // aggregate
|
|
@@ -89,7 +92,7 @@ export function isCountDecl(v: unknown): v is AnyCount {
|
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
/** An extremum decl/builder — `{id, of, valueField}` with `{kind:"min"|"max"}` (the #47 read). */
|
|
92
|
-
export function isExtremumDecl(v: unknown):
|
|
95
|
+
export function isExtremumDecl(v: unknown): v is AnyExtremum {
|
|
93
96
|
if (!v || typeof v !== "object") return false;
|
|
94
97
|
const o = v as Record<string, unknown>;
|
|
95
98
|
return (
|
|
@@ -100,6 +103,22 @@ export function isExtremumDecl(v: unknown): boolean {
|
|
|
100
103
|
);
|
|
101
104
|
}
|
|
102
105
|
|
|
106
|
+
/** Both total and grouped membership declarations carry the same explicit brand. */
|
|
107
|
+
export function isExistsDecl(v: unknown): v is AnyExists {
|
|
108
|
+
if (!v || typeof v !== "object") return false;
|
|
109
|
+
const o = v as Record<string, unknown>;
|
|
110
|
+
return typeof o.id === "string" && typeof o.of === "string" && o._existsMarker === true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Finished first/take declaration; an unfinished orderBy builder is not executable law. */
|
|
114
|
+
export function isOrderedReadDecl(v: unknown): v is OrderedReadDecl {
|
|
115
|
+
if (!v || typeof v !== "object") return false;
|
|
116
|
+
const o = v as Record<string, unknown>;
|
|
117
|
+
return typeof o.id === "string" && typeof o.of === "string"
|
|
118
|
+
&& typeof o.orderKey === "string" && typeof o.orderDesc === "boolean"
|
|
119
|
+
&& typeof o.limit === "number";
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
/**
|
|
104
123
|
* Scan merged exports for decls matching `match`: individual exports AND exported arrays, deduped
|
|
105
124
|
* by a function-blind JSON key (the SAME dedup `compile_package_main.ts` `discover` uses).
|
package/src/describe_model.ts
CHANGED
|
@@ -81,6 +81,7 @@ const mergePolicy = (driver: unknown): string => {
|
|
|
81
81
|
const d = driver as { kind?: unknown; inner?: unknown; principal?: unknown };
|
|
82
82
|
switch (d.kind) {
|
|
83
83
|
case "FirstWriterWins": return "the first concurrent change wins; a later informed edit may replace it";
|
|
84
|
+
case "FirstWriterCandidates": return "the first of the changes nobody had seen wins; a later informed edit settles it";
|
|
84
85
|
case "Lww": return "the latest recorded change wins";
|
|
85
86
|
case "LwwCausal": return "a change based on another wins; truly concurrent changes use a stable tie-break";
|
|
86
87
|
case "LwwBy": return `${String(d.principal ?? "the declared authority")} is the sole writer`;
|
package/src/directive.ts
CHANGED
|
@@ -23,6 +23,8 @@ import type { PlannedOp } from "./ops.js";
|
|
|
23
23
|
import type { Ports } from "./ctx.js";
|
|
24
24
|
import type { RelationDecl } from "./relation.js";
|
|
25
25
|
import type { QueryDecl } from "./query.js";
|
|
26
|
+
import type { AuthenticatedMember } from "./member_authentication.js";
|
|
27
|
+
import { enrolledDeviceAuthentication } from "./member_authentication.js";
|
|
26
28
|
import {
|
|
27
29
|
normalizeActivity,
|
|
28
30
|
type ActivityInput,
|
|
@@ -39,6 +41,7 @@ import {
|
|
|
39
41
|
type FromPayloadRef,
|
|
40
42
|
type TrustPolicyDecl,
|
|
41
43
|
type ForeignReadEdge,
|
|
44
|
+
type AttestedReadSubjectRef,
|
|
42
45
|
} from "./attested_core.js";
|
|
43
46
|
import {
|
|
44
47
|
buildPointGuard,
|
|
@@ -253,7 +256,9 @@ export interface BusinessSourceTrust {
|
|
|
253
256
|
readonly satisfiedByQueryArgs?: Readonly<Record<string, string>>;
|
|
254
257
|
}
|
|
255
258
|
|
|
256
|
-
export interface Directive<P = unknown> {
|
|
259
|
+
export interface Directive<P = unknown> extends AuthenticatedMember {
|
|
260
|
+
/** Durable consequences emitted through the same offer outbox as public intentions. */
|
|
261
|
+
readonly workspaceEffects?: readonly import("./intent.js").WorkspaceEffectStep<P, any>[];
|
|
257
262
|
readonly id: string;
|
|
258
263
|
readonly marker: ReferentialMarker;
|
|
259
264
|
readonly aggregateId: string;
|
|
@@ -274,6 +279,12 @@ export interface Directive<P = unknown> {
|
|
|
274
279
|
* two generated client shapes without changing the directive's replay law.
|
|
275
280
|
*/
|
|
276
281
|
readonly outputCardinality?: "many" | "optional";
|
|
282
|
+
/**
|
|
283
|
+
* Law-selected authentication proof for this exact directive. Omitted means
|
|
284
|
+
* the ordinary session posture (provider token plus enrolled device for a
|
|
285
|
+
* warranted human workspace). This is authentication only: the directive's
|
|
286
|
+
* independent `.requires(...)` authorization policy still has to pass.
|
|
287
|
+
*/
|
|
277
288
|
/**
|
|
278
289
|
* MULTI-OUTPUT DIRECTIVES: additional aggregates this directive declares it writes, beyond the primary
|
|
279
290
|
* marker target. Present iff the directive chained `.alsoEnsures/.alsoCreates/.alsoMutates/.alsoArchives`
|
|
@@ -360,6 +371,9 @@ export interface Directive<P = unknown> {
|
|
|
360
371
|
readonly recordType: string;
|
|
361
372
|
readonly idField: string;
|
|
362
373
|
};
|
|
374
|
+
/** Use the workspace identity proven by this declared foreign read as the
|
|
375
|
+
* Zanzibar subject. Absent means the ordinary session principal. */
|
|
376
|
+
readonly subjectFromAttestedRead?: string;
|
|
363
377
|
};
|
|
364
378
|
/**
|
|
365
379
|
* Admit this directive when it is the exact target call carried by a verified,
|
|
@@ -372,6 +386,16 @@ export interface Directive<P = unknown> {
|
|
|
372
386
|
/** Recovery-only workspace-effect door. The carried source must prove it is this workspace's
|
|
373
387
|
* exact K_root-rooted birth parent; no Zanzibar relation or host assertion substitutes for it. */
|
|
374
388
|
readonly acceptsVerifiedBirthParentRecoveryGate?: true;
|
|
389
|
+
/** Accept a claim made by a cryptographically verified source workspace. This proves the
|
|
390
|
+
* speaker, not a role in the recipient. Receiving law must scope the claim to that speaker. */
|
|
391
|
+
readonly acceptsVerifiedWorkspaceClaimGate?: true;
|
|
392
|
+
/**
|
|
393
|
+
* SOVEREIGN SELF-CERTIFICATION (identity target model D22). The founding signer tuple this directive
|
|
394
|
+
* writes (`identity:<scope>:<h>#signer@key:<h>`) is admitted with no prior signer of the principal iff
|
|
395
|
+
* the signing key's sha256 is `h`, the captured principal's subject. Lowered to
|
|
396
|
+
* `nomos:selfCertifyingPrincipal = "true"`; framework-only (`sovereignSelfCertification`).
|
|
397
|
+
*/
|
|
398
|
+
readonly selfCertifyingPrincipalGate?: true;
|
|
375
399
|
/**
|
|
376
400
|
* CROSS-CUSTODY ATTESTATION-AUTHORIZED (home_holons §3/§5). When `true`, this directive's authorization
|
|
377
401
|
* is a carried §3 SIGNED QUOTE (the asserter's pubkey + a signature over the edge), NOT an author block —
|
|
@@ -663,10 +687,20 @@ export interface RequirableDirective<P> extends Directive<P> {
|
|
|
663
687
|
opts?: {
|
|
664
688
|
object?: string;
|
|
665
689
|
objectFrom?: { recordType: string; idField: string };
|
|
690
|
+
subjectFrom?: AttestedReadSubjectRef;
|
|
666
691
|
}
|
|
667
692
|
): RequirableDirective<P>;
|
|
668
693
|
/** Declare this exact call shape as an admissible signed parent-workspace effect. */
|
|
669
694
|
acceptsWorkspaceEffect(): RequirableDirective<P>;
|
|
695
|
+
acceptsVerifiedWorkspaceClaim(): RequirableDirective<P>;
|
|
696
|
+
/**
|
|
697
|
+
* Authenticate this exact directive with an already-enrolled active device,
|
|
698
|
+
* without requiring a provider token. Use for operations which repair the
|
|
699
|
+
* provider verifier itself; authorization remains separately law-declared.
|
|
700
|
+
*/
|
|
701
|
+
authenticatesWithEnrolledDevice(): RequirableDirective<P>;
|
|
702
|
+
/** Framework-only: mark this directive as a sovereign principal's self-certification (D22). */
|
|
703
|
+
selfCertifyingPrincipal(): RequirableDirective<P>;
|
|
670
704
|
/**
|
|
671
705
|
* Declare this directive ATTESTATION-AUTHORIZED (home_holons §3/§5): its authorization is a carried §3
|
|
672
706
|
* signed quote rather than an author block — lowered into the `nomosAttestationGate` era key so the one
|
|
@@ -834,7 +868,10 @@ export interface RequirableDirective<P> extends Directive<P> {
|
|
|
834
868
|
|
|
835
869
|
/** Stage 1: id + a referential marker (which fixes the target aggregate). */
|
|
836
870
|
class DirectiveMarkerStep<Id extends string> {
|
|
837
|
-
|
|
871
|
+
private readonly id: Id;
|
|
872
|
+
constructor(id: Id) {
|
|
873
|
+
this.id = id;
|
|
874
|
+
}
|
|
838
875
|
/**
|
|
839
876
|
* `creates(Agg)` — Nomos MINTS the id (byte-identical to before this arg existed). For CREATE-ONCE at an
|
|
840
877
|
* APP-SUPPLIED stable id, chain `.payload(...).withId(p => p.id)` on the plan step (typed against the
|
|
@@ -1404,6 +1441,7 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
|
|
|
1404
1441
|
opts?: {
|
|
1405
1442
|
object?: string;
|
|
1406
1443
|
objectFrom?: { recordType: string; idField: string };
|
|
1444
|
+
subjectFrom?: AttestedReadSubjectRef;
|
|
1407
1445
|
}
|
|
1408
1446
|
): RequirableDirective<P> {
|
|
1409
1447
|
// THE ONE write-authz declaration (full-native Zanzibar, no mixed systems): the captured author
|
|
@@ -1420,12 +1458,31 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
|
|
|
1420
1458
|
...(opts?.objectFrom !== undefined
|
|
1421
1459
|
? { objectFrom: opts.objectFrom }
|
|
1422
1460
|
: {}),
|
|
1461
|
+
...(opts?.subjectFrom !== undefined
|
|
1462
|
+
? { subjectFromAttestedRead: opts.subjectFrom.queryId }
|
|
1463
|
+
: {}),
|
|
1423
1464
|
},
|
|
1424
1465
|
});
|
|
1425
1466
|
},
|
|
1426
1467
|
acceptsWorkspaceEffect(): RequirableDirective<P> {
|
|
1427
1468
|
return makeRequirable({ ...base, acceptsWorkspaceEffectGate: true });
|
|
1428
1469
|
},
|
|
1470
|
+
acceptsVerifiedWorkspaceClaim(): RequirableDirective<P> {
|
|
1471
|
+
return makeRequirable({
|
|
1472
|
+
...base,
|
|
1473
|
+
acceptsWorkspaceEffectGate: true,
|
|
1474
|
+
acceptsVerifiedWorkspaceClaimGate: true,
|
|
1475
|
+
});
|
|
1476
|
+
},
|
|
1477
|
+
authenticatesWithEnrolledDevice(): RequirableDirective<P> {
|
|
1478
|
+
return makeRequirable({
|
|
1479
|
+
...base,
|
|
1480
|
+
authentication: enrolledDeviceAuthentication(),
|
|
1481
|
+
});
|
|
1482
|
+
},
|
|
1483
|
+
selfCertifyingPrincipal(): RequirableDirective<P> {
|
|
1484
|
+
return makeRequirable({ ...base, selfCertifyingPrincipalGate: true });
|
|
1485
|
+
},
|
|
1429
1486
|
attestationAuthorized(owner: {
|
|
1430
1487
|
ownerObject: string;
|
|
1431
1488
|
ownerField: string;
|
package/src/drivers.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* PALETTE_ONLY mechanism + throw remain for any FUTURE driver added to this
|
|
15
15
|
* palette ahead of its kernel merge arm — never silently emit an unsupported wire driver.
|
|
16
16
|
*/
|
|
17
|
+
import { canonicalJson } from "./canonical_json.js";
|
|
17
18
|
import type { WireDriver } from "./wire.js";
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -24,6 +25,7 @@ import type { WireDriver } from "./wire.js";
|
|
|
24
25
|
export type KernelDriverKind =
|
|
25
26
|
| "Lww"
|
|
26
27
|
| "FirstWriterWins"
|
|
28
|
+
| "FirstWriterCandidates"
|
|
27
29
|
// ── EXPLICIT TIME-AUTHORITY Lww drivers (the "whose clock?" axis) ──
|
|
28
30
|
// Nomos has no servers, so "do we trust the clock?" is the WRONG question — the real
|
|
29
31
|
// one is WHOSE clock orders THIS field, and a dev assigns it per field. `Lww` trusts
|
|
@@ -61,6 +63,14 @@ export const Lww: Driver = { kind: "Lww" };
|
|
|
61
63
|
/** Nomos's ordinary scalar conflict policy: an informed later edit replaces the
|
|
62
64
|
* value; concurrent edits converge on the earliest writer. */
|
|
63
65
|
export const FirstWriterWins: Driver = { kind: "FirstWriterWins" };
|
|
66
|
+
/** The same policy as `FirstWriterWins`, decided from the SET of changes rather than the
|
|
67
|
+
* order they happened to arrive in: changes nobody had seen compete, the earliest of them is
|
|
68
|
+
* the value, and a change made with knowledge of the others settles it. Because arrival order
|
|
69
|
+
* cannot matter, work recorded offline joins a workspace without replaying its history.
|
|
70
|
+
* Opt in per field with `.merge(FirstWriterCandidates)`, or for every first-writer field of an
|
|
71
|
+
* aggregate with `{ firstWriter: "candidates" }`. It is a law change: roll it out as one.
|
|
72
|
+
* (architecture/path_independent_first_writer.md) */
|
|
73
|
+
export const FirstWriterCandidates: Driver = { kind: "FirstWriterCandidates" };
|
|
64
74
|
export const AddWins: Driver = { kind: "AddWins" };
|
|
65
75
|
export const Conflict: Driver = { kind: "Conflict" };
|
|
66
76
|
export const MapOf = (inner: Driver): Driver => ({ kind: "MapOf", inner });
|
|
@@ -163,11 +173,52 @@ export const Surfaced = (inner: Driver): Driver => {
|
|
|
163
173
|
// throws for it rather than emit a wire driver the kernel can't merge.
|
|
164
174
|
const PALETTE_ONLY: ReadonlySet<DriverKind> = new Set<DriverKind>([]);
|
|
165
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Is this wire driver a SINGLE-VALUE driver (D20)? Mirrors the kernel's
|
|
178
|
+
* `is_single_value_driver`: one visible value chosen from the field's stored observation
|
|
179
|
+
* antichain, so the driver is a pure reduction at projection time. Counters, sets, lists,
|
|
180
|
+
* maps, positions and `Conflict` are not.
|
|
181
|
+
*/
|
|
182
|
+
export function isSingleValueWireDriver(driver: unknown): boolean {
|
|
183
|
+
if (typeof driver === "string") {
|
|
184
|
+
return (
|
|
185
|
+
driver === "Lww" ||
|
|
186
|
+
driver === "LwwCausal" ||
|
|
187
|
+
driver === "FirstWriterWins" ||
|
|
188
|
+
driver === "FirstWriterCandidates"
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (driver === null || typeof driver !== "object") return false;
|
|
192
|
+
const d = driver as Record<string, unknown>;
|
|
193
|
+
if (typeof d.LwwBy === "string") return true;
|
|
194
|
+
if ("Surfaced" in d) return isSingleValueWireDriver(d.Surfaced);
|
|
195
|
+
if ("Attributed" in d) return isSingleValueWireDriver(d.Attributed);
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The stored VALUE SPACE of a wire driver — the `driver` slot of the field schema identity.
|
|
201
|
+
* Mirrors the kernel's `field_schema_value_space` byte-for-byte: every single-value driver
|
|
202
|
+
* shares one value space and is written as its representative `"Lww"` (so fields already
|
|
203
|
+
* declared `Lww` keep the identity they always had); any other driver is its own value space.
|
|
204
|
+
* Switching among single-value drivers in a later law is therefore not a retype.
|
|
205
|
+
*/
|
|
206
|
+
export function driverValueSpace(driver: unknown): unknown {
|
|
207
|
+
return isSingleValueWireDriver(driver) ? "Lww" : driver;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Do two wire drivers store the same value space (a driver switch is a plain law change)? */
|
|
211
|
+
export function driversShareValueSpace(a: unknown, b: unknown): boolean {
|
|
212
|
+
return canonicalJson(driverValueSpace(a)) === canonicalJson(driverValueSpace(b));
|
|
213
|
+
}
|
|
214
|
+
|
|
166
215
|
/** Encode one Driver to its kernel wire shape, or throw if not yet in the kernel. */
|
|
167
216
|
export function encodeDriver(d: Driver): WireDriver {
|
|
168
217
|
switch (d.kind) {
|
|
169
218
|
case "FirstWriterWins":
|
|
170
219
|
return "FirstWriterWins";
|
|
220
|
+
case "FirstWriterCandidates":
|
|
221
|
+
return "FirstWriterCandidates";
|
|
171
222
|
case "Lww":
|
|
172
223
|
return "Lww";
|
|
173
224
|
// ── EXPLICIT TIME-AUTHORITY Lww drivers (kernel `merge_field` arms) ──
|
package/src/engine_entry.ts
CHANGED
|
@@ -55,14 +55,24 @@ import { executeDirectiveToIntent } from "./wire_encode.js";
|
|
|
55
55
|
import { expandCapabilityExports, isCapabilityDecl } from "./capability_exports.js";
|
|
56
56
|
import { RelationTuple, __setDispatchContext } from "./framework/relations.js";
|
|
57
57
|
import { BIRTH_METER_AGGREGATES } from "./birth_meter.js";
|
|
58
|
-
import {
|
|
58
|
+
import {
|
|
59
|
+
AuthProvider as FrameworkAuthProvider,
|
|
60
|
+
AuthProviderCertificate as FrameworkAuthProviderCertificate,
|
|
61
|
+
AuthProviderKey as FrameworkAuthProviderKey,
|
|
62
|
+
adoptIdentityProviderWitness as frameworkAdoptIdentityProviderWitness,
|
|
63
|
+
setAuthProvider as frameworkSetAuthProvider,
|
|
64
|
+
} from "./framework/auth_provider_law.js";
|
|
59
65
|
import { namespacedAggregateIds, qualifyReadProjectionType, READ_PROJECTION_DELIMITER } from "./read_projection_namespace.js";
|
|
60
66
|
import { discoverRelationTypeDeclarations } from "./relation_schema.js";
|
|
61
67
|
import { synthesizePreconditionInvariants } from "./precondition.js";
|
|
62
68
|
import { synthesizeBirthQuotaInvariants } from "./birth_meter.js";
|
|
63
69
|
import { withBirthMeterExports } from "./birth_meter_ensure.js";
|
|
64
70
|
import { expandRoleExports } from "./role.js";
|
|
65
|
-
import {
|
|
71
|
+
import {
|
|
72
|
+
NomosSourceFrontier,
|
|
73
|
+
nomosSourceFrontierEnsure,
|
|
74
|
+
withAttestedReadExports,
|
|
75
|
+
} from "./attested.js";
|
|
66
76
|
import type { OpenApiDoc } from "./codegen_openapi.js";
|
|
67
77
|
import type { Directive } from "./directive.js";
|
|
68
78
|
import type { AggregateHandle, AggregateInvariantFn, AggregateInvariantVerdict } from "./aggregate.js";
|
|
@@ -83,6 +93,7 @@ import {
|
|
|
83
93
|
applicationLanguageOf,
|
|
84
94
|
assertApplicationLanguageCoversAuthoredDirectives,
|
|
85
95
|
executableDirectivesForLanguage,
|
|
96
|
+
publicOfferRoute,
|
|
86
97
|
remapWorkspaceInvariantsForLanguage,
|
|
87
98
|
} from "./intent.js";
|
|
88
99
|
|
|
@@ -400,16 +411,42 @@ function buildDomainSlice(mod: DomainModuleExports, domain: string): DomainSlice
|
|
|
400
411
|
if (declaresBirthHere || declaresPrivateHere) {
|
|
401
412
|
if (!aggs.has(FrameworkAuthProvider.id)) aggs.set(FrameworkAuthProvider.id, FrameworkAuthProvider);
|
|
402
413
|
if (!dirs.has(frameworkSetAuthProvider.id)) dirs.set(frameworkSetAuthProvider.id, frameworkSetAuthProvider as unknown as Directive<unknown>);
|
|
414
|
+
if (declaresPrivateHere) {
|
|
415
|
+
for (const aggregate of [
|
|
416
|
+
FrameworkAuthProviderKey,
|
|
417
|
+
FrameworkAuthProviderCertificate,
|
|
418
|
+
NomosSourceFrontier,
|
|
419
|
+
]) {
|
|
420
|
+
if (!aggs.has(aggregate.id)) aggs.set(aggregate.id, aggregate);
|
|
421
|
+
}
|
|
422
|
+
if (!dirs.has(frameworkAdoptIdentityProviderWitness.id)) {
|
|
423
|
+
dirs.set(
|
|
424
|
+
frameworkAdoptIdentityProviderWitness.id,
|
|
425
|
+
frameworkAdoptIdentityProviderWitness as unknown as Directive<unknown>,
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
if (!dirs.has(nomosSourceFrontierEnsure.id)) {
|
|
429
|
+
dirs.set(nomosSourceFrontierEnsure.id, nomosSourceFrontierEnsure as unknown as Directive<unknown>);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
403
432
|
}
|
|
404
433
|
}
|
|
405
|
-
for (const
|
|
434
|
+
for (const directive of dirs.values()) {
|
|
406
435
|
const agg = aggs.get(directive.aggregateId);
|
|
407
436
|
if (agg === undefined) {
|
|
408
437
|
// A directive targeting an aggregate not exported by its module is an
|
|
409
438
|
// authoring bug; surface it lazily (only if that directive is invoked).
|
|
410
439
|
continue;
|
|
411
440
|
}
|
|
412
|
-
|
|
441
|
+
const publicRoute = publicOfferRoute(directive);
|
|
442
|
+
const prior = registry.get(publicRoute);
|
|
443
|
+
if (prior !== undefined && prior.directive !== directive) {
|
|
444
|
+
throw new Error(
|
|
445
|
+
`engine bundle: public offer route '${publicRoute}' resolves to both ` +
|
|
446
|
+
`'${prior.directive.id}' and '${directive.id}' in domain '${domain}'`,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
registry.set(publicRoute, { directive, agg });
|
|
413
450
|
}
|
|
414
451
|
|
|
415
452
|
// ── aggregate type → derived / combined decls (fn bodies ship HERE, never the ledger) ──
|
|
@@ -780,7 +817,7 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
780
817
|
}
|
|
781
818
|
|
|
782
819
|
function planAggInvariant(job: {
|
|
783
|
-
intent?: { aggregateInvariant?: { of?: string } };
|
|
820
|
+
intent?: { aggregateInvariant?: { of?: string; previous?: Record<string, unknown> | null } };
|
|
784
821
|
priorState?: Record<string, unknown>;
|
|
785
822
|
}): string {
|
|
786
823
|
// WIRE SHAPE (the host oracle's contract, EXACT): `{ aggregateInvariant: { of: "<type>" } }`.
|
|
@@ -802,7 +839,7 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
802
839
|
return JSON.stringify({ accept: true } satisfies AggregateInvariantVerdict);
|
|
803
840
|
}
|
|
804
841
|
const snapshot = (job.priorState ?? {}) as Record<string, unknown>;
|
|
805
|
-
const verdict: AggregateInvariantVerdict = body(snapshot);
|
|
842
|
+
const verdict: AggregateInvariantVerdict = body(snapshot, job.intent?.aggregateInvariant?.previous);
|
|
806
843
|
return JSON.stringify(verdict);
|
|
807
844
|
}
|
|
808
845
|
|
|
@@ -1072,8 +1109,9 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
1072
1109
|
// and meter `Event`s directly instead of walking a second returned object graph. This is an
|
|
1073
1110
|
// execution ABI, not authority: the same values still pass the ordinary kernel gates, and old
|
|
1074
1111
|
// kernels/packages retain the returned-value lane below for era replay.
|
|
1075
|
-
const
|
|
1112
|
+
const nativePlanKernel = (globalThis as unknown as {
|
|
1076
1113
|
nomos?: {
|
|
1114
|
+
__workspaceEffectDependencies?: number;
|
|
1077
1115
|
__submitPlan?: (
|
|
1078
1116
|
events: WireEvent[],
|
|
1079
1117
|
strikes: string[],
|
|
@@ -1082,10 +1120,16 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
1082
1120
|
workspaceEffects: {
|
|
1083
1121
|
destination: { workspace: string } | { verifiedParent: true } | { verifiedSource: true };
|
|
1084
1122
|
targetCallUsda: Uint8Array;
|
|
1123
|
+
dependsOn?: readonly number[];
|
|
1085
1124
|
}[],
|
|
1086
1125
|
) => void;
|
|
1087
1126
|
};
|
|
1088
|
-
}).nomos
|
|
1127
|
+
}).nomos;
|
|
1128
|
+
if (wire.workspaceEffects?.some(effect => effect.dependsOn?.length) &&
|
|
1129
|
+
nativePlanKernel?.__workspaceEffectDependencies !== 1) {
|
|
1130
|
+
throw new Error("workspace effect dependencies require kernel support for authenticated predecessor judgments");
|
|
1131
|
+
}
|
|
1132
|
+
const submitNativePlan = nativePlanKernel?.__submitPlan;
|
|
1089
1133
|
if (typeof submitNativePlan === "function") {
|
|
1090
1134
|
submitNativePlan(
|
|
1091
1135
|
wire.events,
|