@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,275 @@
|
|
|
1
|
+
/** Coverage of declared reads, not authorization or production-read readiness.
|
|
2
|
+
* The input is the complete composed LawGraph, never tenant source-name switches.
|
|
3
|
+
*/
|
|
4
|
+
import type { LawGraph, LawReadNode, LawFieldPathRef } from "./law_graph.js";
|
|
5
|
+
import type { SqliteLayout, SqliteSlot, SqliteValue } from "./sqlite_layout.js";
|
|
6
|
+
type Nodes = ReadonlyMap<string, LawGraph["nodes"][number]>;
|
|
7
|
+
export interface SqliteQueryPlan {
|
|
8
|
+
sid: string;
|
|
9
|
+
name: string;
|
|
10
|
+
keys: { path: string[]; kind: "string" | "integer" | "boolean" }[];
|
|
11
|
+
index: string;
|
|
12
|
+
ddl: string;
|
|
13
|
+
sql: string;
|
|
14
|
+
}
|
|
15
|
+
const literal = (s: string) => `'${s.replaceAll("'", "''")}'`;
|
|
16
|
+
type Scalar = { sql: string; kind: "string" | "integer" | "boolean" };
|
|
17
|
+
// Expressions are made only from generated column ordinals and quoted literals.
|
|
18
|
+
// SQLite maintains expression indexes transactionally; no second key store.
|
|
19
|
+
export function scalarSlot(slot: SqliteSlot, tail: readonly string[]): Scalar {
|
|
20
|
+
if (slot.surfaced)
|
|
21
|
+
throw Error("Surfaced query keys need observed-value indexing");
|
|
22
|
+
const result = scalarValue(slot.value, tail);
|
|
23
|
+
return {
|
|
24
|
+
...result,
|
|
25
|
+
sql: `CASE WHEN c${slot.presence}=2 THEN ${result.sql} END`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function scalarValue(value: SqliteValue, tail: readonly string[]): Scalar {
|
|
29
|
+
if (value.kind === "object" && tail.length) {
|
|
30
|
+
const member = value.members?.find((m) => m.name === tail[0]);
|
|
31
|
+
if (!member) throw Error(`missing nested member ${tail[0]}`);
|
|
32
|
+
return scalarSlot(member, tail.slice(1));
|
|
33
|
+
}
|
|
34
|
+
if (value.kind === "union" && tail.length) {
|
|
35
|
+
const arms = value.variants!.flatMap((arm, i) => {
|
|
36
|
+
// The nominal sum encoder puts its tag in `type`; SQL stores the ordinal.
|
|
37
|
+
if (tail.length === 1 && tail[0] === "type")
|
|
38
|
+
return [{ i, sql: literal(arm.label), kind: "string" as const }];
|
|
39
|
+
if (!arm.value.members?.some((m) => m.name === tail[0])) {
|
|
40
|
+
if (
|
|
41
|
+
arm.value.members
|
|
42
|
+
?.find((m) => m.name === "value")
|
|
43
|
+
?.value.members?.some((m) => m.name === tail[0])
|
|
44
|
+
)
|
|
45
|
+
throw Error(
|
|
46
|
+
"named sum payload path differs from authored path; typed-path resolution required"
|
|
47
|
+
);
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return [{ i, ...scalarValue(arm.value, tail) }];
|
|
51
|
+
});
|
|
52
|
+
if (!arms.length) throw Error(`no sum arm has ${tail.join(".")}`);
|
|
53
|
+
if (arms.some((a) => a.kind !== arms[0]!.kind))
|
|
54
|
+
throw Error("query path has incompatible sum-arm scalar kinds");
|
|
55
|
+
return {
|
|
56
|
+
kind: arms[0]!.kind,
|
|
57
|
+
sql: `CASE c${value.column} ${arms
|
|
58
|
+
.map((a) => `WHEN ${a.i} THEN ${a.sql}`)
|
|
59
|
+
.join(" ")} END`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (tail.length)
|
|
63
|
+
throw Error(`indexed traversal through ${value.kind} is not implemented`);
|
|
64
|
+
if (
|
|
65
|
+
!["string", "integer", "boolean"].includes(value.kind) ||
|
|
66
|
+
value.column === undefined
|
|
67
|
+
)
|
|
68
|
+
throw Error(`query key ${value.kind} requires a separate index capability`);
|
|
69
|
+
return { kind: value.kind as Scalar["kind"], sql: `c${value.column}` };
|
|
70
|
+
}
|
|
71
|
+
export function planSqliteQueries(
|
|
72
|
+
nodes: Nodes,
|
|
73
|
+
aggregateId: string,
|
|
74
|
+
layout: Pick<SqliteLayout, "table" | "wireType" | "fields">
|
|
75
|
+
) {
|
|
76
|
+
const plans: SqliteQueryPlan[] = [],
|
|
77
|
+
refusals: { sid: string; reason: string }[] = [];
|
|
78
|
+
for (const read of [...nodes.values()].filter(
|
|
79
|
+
(n): n is LawReadNode =>
|
|
80
|
+
n.kind === "read" && n.readKind === "query" && n.of.id === aggregateId
|
|
81
|
+
)) {
|
|
82
|
+
if (read.readKind !== "query") continue;
|
|
83
|
+
try {
|
|
84
|
+
if (read.predicate) throw Error("filtered query is not implemented");
|
|
85
|
+
if (!/^[a-f0-9]+$/i.test(read.entity.sid))
|
|
86
|
+
throw Error("unsafe read identity");
|
|
87
|
+
if (!read.key.length) throw Error("empty query key");
|
|
88
|
+
if (read.key.length + 1 > 2000)
|
|
89
|
+
throw Error("query index exceeds 2000-column SQLite target");
|
|
90
|
+
const keys = read.key.map((k) => {
|
|
91
|
+
const path = k.authoredPath.split(".");
|
|
92
|
+
const field = layout.fields.find((f) => f.name === path[0]);
|
|
93
|
+
if (!field) throw Error(`unmapped key ${k.authoredPath}`);
|
|
94
|
+
return { path, ...scalarSlot(field, path.slice(1)) };
|
|
95
|
+
});
|
|
96
|
+
const type = layout.fields.find((f) => f.name === "__type")!;
|
|
97
|
+
const archive = layout.fields.find((f) => f.name === "__archived");
|
|
98
|
+
if (!archive) throw Error("archive metadata not mapped");
|
|
99
|
+
// COALESCE handles absent archive cells (SQL NULL is not FALSE).
|
|
100
|
+
const guard = `c${type.presence}=2 AND c${type.value.column}=${literal(
|
|
101
|
+
layout.wireType
|
|
102
|
+
)} AND COALESCE(c${archive.value.column},0)<>1`;
|
|
103
|
+
const index = `r_${read.entity.sid.toLowerCase()}`;
|
|
104
|
+
plans.push({
|
|
105
|
+
sid: read.entity.sid,
|
|
106
|
+
name: read.entity.label,
|
|
107
|
+
keys: keys.map(({ path, kind }) => ({ path, kind })),
|
|
108
|
+
index,
|
|
109
|
+
ddl: `CREATE INDEX ${index} ON ${layout.table}(${keys
|
|
110
|
+
.map((k) => k.sql)
|
|
111
|
+
.join(",")},id) WHERE ${guard};`,
|
|
112
|
+
sql: `SELECT id FROM ${
|
|
113
|
+
layout.table
|
|
114
|
+
} INDEXED BY ${index} WHERE ${guard} AND ${keys
|
|
115
|
+
.map((k, i) => `(${k.sql})=?${i + 1}`)
|
|
116
|
+
.join(" AND ")} AND id>?${keys.length + 1} ORDER BY id LIMIT ?${
|
|
117
|
+
keys.length + 2
|
|
118
|
+
}`,
|
|
119
|
+
});
|
|
120
|
+
} catch (error) {
|
|
121
|
+
refusals.push({ sid: read.entity.sid, reason: (error as Error).message });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { plans: plans.sort((a, b) => a.sid.localeCompare(b.sid)), refusals };
|
|
125
|
+
}
|
|
126
|
+
export function readFields(read: LawReadNode): readonly LawFieldPathRef[] {
|
|
127
|
+
switch (read.readKind) {
|
|
128
|
+
case "query":
|
|
129
|
+
return read.key;
|
|
130
|
+
case "count":
|
|
131
|
+
case "exists":
|
|
132
|
+
return read.groupBy ? [read.groupBy] : [];
|
|
133
|
+
case "sum":
|
|
134
|
+
case "min":
|
|
135
|
+
case "max":
|
|
136
|
+
return [read.value, ...(read.groupBy ? [read.groupBy] : [])];
|
|
137
|
+
case "ordered":
|
|
138
|
+
return [read.orderBy];
|
|
139
|
+
case "spatial":
|
|
140
|
+
return [read.geometry];
|
|
141
|
+
case "combined":
|
|
142
|
+
return [read.via];
|
|
143
|
+
case "temporalEnum":
|
|
144
|
+
return [read.source];
|
|
145
|
+
case "derived":
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function inspectSqliteReads(
|
|
150
|
+
nodes: Nodes,
|
|
151
|
+
layouts: readonly SqliteLayout[]
|
|
152
|
+
) {
|
|
153
|
+
const reads = [...nodes.values()]
|
|
154
|
+
.filter((n): n is LawReadNode => n.kind === "read")
|
|
155
|
+
.map((read) => {
|
|
156
|
+
const aggregate = nodes.get(read.of.id),
|
|
157
|
+
domain = nodes.get(read.domain.id);
|
|
158
|
+
if (aggregate?.kind !== "aggregate" || domain?.kind !== "domain")
|
|
159
|
+
throw Error("read owner missing from compiled graph");
|
|
160
|
+
const layout = layouts.find(
|
|
161
|
+
(p) => p.aggregateSid === aggregate.entity.sid
|
|
162
|
+
);
|
|
163
|
+
const fields = readFields(read).map((p) => {
|
|
164
|
+
const field = aggregate.fields
|
|
165
|
+
.map((f) => nodes.get(f.id))
|
|
166
|
+
.find((f) => f?.entity.label === p.authoredPath.split(".")[0]);
|
|
167
|
+
return {
|
|
168
|
+
path: p.authoredPath,
|
|
169
|
+
fieldId: p.field.id,
|
|
170
|
+
storage: field?.kind === "field" ? field.storageKind : "unknown",
|
|
171
|
+
drivers:
|
|
172
|
+
field?.kind === "field"
|
|
173
|
+
? field.mergeDrivers.map((d) => d.kind)
|
|
174
|
+
: [],
|
|
175
|
+
};
|
|
176
|
+
});
|
|
177
|
+
const spatial =
|
|
178
|
+
read.readKind === "spatial" &&
|
|
179
|
+
layout?.spatialIndexes.some((s) => s.sid === read.entity.sid);
|
|
180
|
+
const query = layout?.queryReads.some((q) => q.sid === read.entity.sid);
|
|
181
|
+
const count = layout?.countReads.some((q) => q.sid === read.entity.sid);
|
|
182
|
+
const computed = layout?.computedReads.some(
|
|
183
|
+
(q) => q.sid === read.entity.sid
|
|
184
|
+
);
|
|
185
|
+
const refusal =
|
|
186
|
+
layout?.queryRefusals.find((q) => q.sid === read.entity.sid) ??
|
|
187
|
+
layout?.countRefusals.find((q) => q.sid === read.entity.sid) ??
|
|
188
|
+
layout?.computedRefusals.find((q) => q.sid === read.entity.sid);
|
|
189
|
+
return {
|
|
190
|
+
sid: read.entity.sid,
|
|
191
|
+
name: read.entity.label,
|
|
192
|
+
domain: domain.entity.label,
|
|
193
|
+
kind: read.readKind,
|
|
194
|
+
aggregateSid: aggregate.entity.sid,
|
|
195
|
+
wireType: aggregate.wireType,
|
|
196
|
+
public: read.public,
|
|
197
|
+
contract: read.contract.id,
|
|
198
|
+
fields,
|
|
199
|
+
filtered: !!read.predicate,
|
|
200
|
+
status:
|
|
201
|
+
spatial || query || count || computed
|
|
202
|
+
? "component-implemented"
|
|
203
|
+
: "missing",
|
|
204
|
+
reason: !layout
|
|
205
|
+
? "aggregate layout unavailable"
|
|
206
|
+
: spatial || query || count || computed
|
|
207
|
+
? null
|
|
208
|
+
: refusal?.reason ?? `${read.readKind} read adapter not implemented`,
|
|
209
|
+
requirements: [
|
|
210
|
+
read.readKind,
|
|
211
|
+
...(fields.length > 1 ? ["compound"] : []),
|
|
212
|
+
...(fields.some((f) => f.path.includes(".")) ? ["nested-path"] : []),
|
|
213
|
+
...(fields.some((f) => f.storage === "set")
|
|
214
|
+
? ["set-membership"]
|
|
215
|
+
: []),
|
|
216
|
+
...(fields.some((f) => f.drivers.includes("Surfaced"))
|
|
217
|
+
? ["surfaced-observation"]
|
|
218
|
+
: []),
|
|
219
|
+
...(read.predicate ? ["predicate"] : []),
|
|
220
|
+
],
|
|
221
|
+
runtimeVerified: false,
|
|
222
|
+
};
|
|
223
|
+
})
|
|
224
|
+
.sort(
|
|
225
|
+
(a, b) =>
|
|
226
|
+
a.domain.localeCompare(b.domain) ||
|
|
227
|
+
a.name.localeCompare(b.name) ||
|
|
228
|
+
a.sid.localeCompare(b.sid)
|
|
229
|
+
);
|
|
230
|
+
const kinds = Object.fromEntries(
|
|
231
|
+
[...new Set(reads.map((r) => r.kind))].sort().map((kind) => {
|
|
232
|
+
const group = reads.filter((r) => r.kind === kind);
|
|
233
|
+
return [
|
|
234
|
+
kind,
|
|
235
|
+
{
|
|
236
|
+
total: group.length,
|
|
237
|
+
implemented: group.filter((r) => r.status === "component-implemented")
|
|
238
|
+
.length,
|
|
239
|
+
missing: group.filter((r) => r.status === "missing").length,
|
|
240
|
+
},
|
|
241
|
+
];
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
const foreignReads = [...nodes.values()]
|
|
245
|
+
.filter(
|
|
246
|
+
(n) => n.kind === "structural" && n.structuralKind === "foreign-read"
|
|
247
|
+
)
|
|
248
|
+
.map((n) => {
|
|
249
|
+
if (n.kind !== "structural" || n.structuralKind !== "foreign-read")
|
|
250
|
+
throw Error("unreachable");
|
|
251
|
+
return {
|
|
252
|
+
id: n.entity.id,
|
|
253
|
+
owner: n.owner.id,
|
|
254
|
+
query: n.query,
|
|
255
|
+
sourcePolicy: n.source.id,
|
|
256
|
+
requirements: [
|
|
257
|
+
"authenticated-source-frontier",
|
|
258
|
+
"source-policy",
|
|
259
|
+
"snapshot-binding",
|
|
260
|
+
],
|
|
261
|
+
runtimeVerified: false,
|
|
262
|
+
};
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
scope:
|
|
266
|
+
"declared read component coverage; not authorization, generated-client or runtime proof",
|
|
267
|
+
total: reads.length,
|
|
268
|
+
implemented: reads.filter((r) => r.status === "component-implemented")
|
|
269
|
+
.length,
|
|
270
|
+
missing: reads.filter((r) => r.status === "missing").length,
|
|
271
|
+
kinds,
|
|
272
|
+
reads,
|
|
273
|
+
foreignReads,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/** Component fixtures from authored descriptors, independently of the physical
|
|
2
|
+
* planner. Real wire encoder, synthetic values: NOT admitted tenant records.
|
|
3
|
+
* Keep this opt-in diagnostic outside compiler/law outputs and public barrels.
|
|
4
|
+
*/
|
|
5
|
+
import type {
|
|
6
|
+
Field,
|
|
7
|
+
ValueObjectDescriptor,
|
|
8
|
+
ValueObjectFieldDescriptor,
|
|
9
|
+
ValueObjectFieldMeta,
|
|
10
|
+
} from "./fields.js";
|
|
11
|
+
import type { DomainModule } from "./codegen_dart.js";
|
|
12
|
+
import { encodeNominalValueObject } from "./wire_encode.js";
|
|
13
|
+
import type { LawGraph } from "./law_graph.js";
|
|
14
|
+
|
|
15
|
+
function object(
|
|
16
|
+
d: ValueObjectDescriptor,
|
|
17
|
+
types: Map<string, ValueObjectDescriptor>,
|
|
18
|
+
n: number
|
|
19
|
+
): unknown {
|
|
20
|
+
if (d.geometry) {
|
|
21
|
+
const point = [1, 2.5];
|
|
22
|
+
return {
|
|
23
|
+
type: d.geometry,
|
|
24
|
+
coordinates:
|
|
25
|
+
d.geometry === "Point"
|
|
26
|
+
? point
|
|
27
|
+
: d.geometry === "Polygon"
|
|
28
|
+
? [[point, [2, 3], [3, 1], point]]
|
|
29
|
+
: [point, [2, 3]],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (d.union) {
|
|
33
|
+
const [label, arm] = Object.entries(d.union).sort(([a], [b]) =>
|
|
34
|
+
a.localeCompare(b)
|
|
35
|
+
)[Math.floor(n / 3) % Object.keys(d.union).length]!;
|
|
36
|
+
return "ref" in arm
|
|
37
|
+
? { type: label, value: object(types.get(arm.ref)!, types, n) }
|
|
38
|
+
: { type: label, ...members(arm.fields, types, n) };
|
|
39
|
+
}
|
|
40
|
+
return members(d.fields ?? {}, types, n);
|
|
41
|
+
}
|
|
42
|
+
function members(
|
|
43
|
+
fields: Readonly<Record<string, ValueObjectFieldDescriptor>>,
|
|
44
|
+
types: Map<string, ValueObjectDescriptor>,
|
|
45
|
+
n: number
|
|
46
|
+
) {
|
|
47
|
+
return Object.fromEntries(
|
|
48
|
+
Object.entries(fields).flatMap(([name, f]) =>
|
|
49
|
+
f.optional && n % 3 === 0 ? [] : [[name, member(f, types, n)]]
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function member(
|
|
54
|
+
f: ValueObjectFieldDescriptor,
|
|
55
|
+
types: Map<string, ValueObjectDescriptor>,
|
|
56
|
+
n: number
|
|
57
|
+
): unknown {
|
|
58
|
+
if (f.nullable && n % 3 === 1) return null;
|
|
59
|
+
switch (f.type) {
|
|
60
|
+
case "string":
|
|
61
|
+
return f.digest ? "a".repeat(64) : n % 3 === 0 ? "" : `sample-λ-${n}`;
|
|
62
|
+
case "enum":
|
|
63
|
+
return f.values[n % f.values.length];
|
|
64
|
+
case "literal":
|
|
65
|
+
return f.value;
|
|
66
|
+
case "number":
|
|
67
|
+
// This interchange is JSON; the native scalar fixture separately covers
|
|
68
|
+
// IEEE negative-zero bits without JSON.stringify normalising them to zero.
|
|
69
|
+
return f.int ? n : n % 2 === 0 ? 0 : 1.25;
|
|
70
|
+
case "boolean":
|
|
71
|
+
return n % 2 === 0;
|
|
72
|
+
case "array":
|
|
73
|
+
return n % 3 === 0
|
|
74
|
+
? []
|
|
75
|
+
: [member(f.items, types, n), member(f.items, types, n + 1)];
|
|
76
|
+
case "map":
|
|
77
|
+
return n % 3 === 0
|
|
78
|
+
? {}
|
|
79
|
+
: {
|
|
80
|
+
"": member(f.values, types, n),
|
|
81
|
+
"λ:2/key": member(f.values, types, n + 1),
|
|
82
|
+
};
|
|
83
|
+
case "object":
|
|
84
|
+
case "geometry":
|
|
85
|
+
return object(types.get(f.ref)!, types, n);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function nominal(meta: ValueObjectFieldMeta, n: number) {
|
|
89
|
+
const types = new Map(
|
|
90
|
+
[meta.descriptor, ...meta.dependencies].map((d) => [d.name, d])
|
|
91
|
+
);
|
|
92
|
+
return {
|
|
93
|
+
ValueObject: encodeNominalValueObject(
|
|
94
|
+
meta.descriptor,
|
|
95
|
+
object(meta.descriptor, types, n),
|
|
96
|
+
types
|
|
97
|
+
),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function value(f: Field, n: number): unknown {
|
|
101
|
+
if (f.nullSemantic && f.nullSemantic !== "forbid" && n % 3 === 1)
|
|
102
|
+
return { Json: null };
|
|
103
|
+
const ref = (type: string) => ({
|
|
104
|
+
workspace: "synthetic-workspace",
|
|
105
|
+
type,
|
|
106
|
+
id: `synthetic-${n}`,
|
|
107
|
+
});
|
|
108
|
+
if (f.nomosRef) return { NomosRef: ref(f.nomosRef.targetAggregateId) };
|
|
109
|
+
if (f.versionedForeignRef)
|
|
110
|
+
return {
|
|
111
|
+
VersionedNomosRef: {
|
|
112
|
+
pinned: ref(f.versionedForeignRef.targetAggregateId),
|
|
113
|
+
series: ref(f.versionedForeignRef.seriesAggregateId),
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
if (f.valueObject) return nominal(f.valueObject, n);
|
|
117
|
+
if (f.kind === "map") {
|
|
118
|
+
const leaf = f.mapValueVo
|
|
119
|
+
? nominal(f.mapValueVo, n)
|
|
120
|
+
: f.mapValueKind === "int"
|
|
121
|
+
? { Int: n }
|
|
122
|
+
: f.mapValueKind === "bool"
|
|
123
|
+
? { Bool: n % 2 === 0 }
|
|
124
|
+
: { Str: `entry-${n}` };
|
|
125
|
+
return { Map: n % 3 === 0 ? {} : { "": leaf, "λ:2/key": leaf } };
|
|
126
|
+
}
|
|
127
|
+
if (f.kind === "set") return { Set: n % 3 === 0 ? [] : ["alpha", "βeta"] };
|
|
128
|
+
if (f.kind === "int") return { Int: n };
|
|
129
|
+
if (f.kind === "bool") return { Bool: n % 2 === 0 };
|
|
130
|
+
if (["string", "enum", "ref"].includes(f.kind)) return { Str: `sample-${n}` };
|
|
131
|
+
throw new Error(`unsupported descriptor fixture kind ${f.kind}`);
|
|
132
|
+
}
|
|
133
|
+
export function sqliteDescriptorSamples(
|
|
134
|
+
modules: readonly DomainModule[],
|
|
135
|
+
graphs: ReadonlyMap<string, LawGraph>
|
|
136
|
+
) {
|
|
137
|
+
const seen = new Set<string>();
|
|
138
|
+
return modules.flatMap((mod) =>
|
|
139
|
+
mod.aggregates.flatMap((a) => {
|
|
140
|
+
// Shared framework handles may occur in multiple modules; physical binding
|
|
141
|
+
// is by the compiler's wireType + stable SID, supplied by the caller.
|
|
142
|
+
const node = graphs
|
|
143
|
+
.get(mod.name)!
|
|
144
|
+
.nodes.find((n) => n.kind === "aggregate" && n.entity.label === a.id);
|
|
145
|
+
if (node?.kind !== "aggregate")
|
|
146
|
+
throw new Error(`missing aggregate ${mod.name}.${a.id}`);
|
|
147
|
+
const key = node.entity.sid;
|
|
148
|
+
if (seen.has(key)) return [];
|
|
149
|
+
seen.add(key);
|
|
150
|
+
let arms = 1;
|
|
151
|
+
for (const f of Object.values(a.fields))
|
|
152
|
+
for (const meta of [f.valueObject, f.mapValueVo])
|
|
153
|
+
if (meta)
|
|
154
|
+
for (const d of [meta.descriptor, ...meta.dependencies])
|
|
155
|
+
arms = Math.max(arms, Object.keys(d.union ?? {}).length);
|
|
156
|
+
const labels = new Set(
|
|
157
|
+
node.fields.map(
|
|
158
|
+
(r) =>
|
|
159
|
+
graphs.get(mod.name)!.nodes.find((n) => n.entity.id === r.id)!
|
|
160
|
+
.entity.label
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
const base = {
|
|
164
|
+
aggregate: a.id,
|
|
165
|
+
sid: key,
|
|
166
|
+
wireType: node.wireType,
|
|
167
|
+
scope:
|
|
168
|
+
"synthetic descriptor values through the production nominal wire encoder; not admitted domain data",
|
|
169
|
+
};
|
|
170
|
+
try {
|
|
171
|
+
const samples = Array.from({ length: Math.max(3, arms * 3) }, (_, n) =>
|
|
172
|
+
Object.fromEntries(
|
|
173
|
+
Object.entries(a.fields)
|
|
174
|
+
.filter(([name]) => labels.has(name))
|
|
175
|
+
.map(([name, f]) => [name, value(f, n)])
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
return [{ ...base, samples }];
|
|
179
|
+
} catch (error) {
|
|
180
|
+
// An unsupported fixture must not erase the planner's useful diagnostics.
|
|
181
|
+
return [{ ...base, samples: [], samplingError: String(error) }];
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
@@ -13,7 +13,7 @@ export interface StableIdentityAggregateInput {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Compatibility
|
|
16
|
+
* Compatibility mapping for W4.1. The existing shape-aware continuity pass proposes
|
|
17
17
|
* carries; the generalized registry owns the final SIDs and durable tombstones. Later
|
|
18
18
|
* W4 work replaces those proposals with typed-graph/previous-USDA evidence.
|
|
19
19
|
*/
|
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { DomainModule } from "./codegen_dart.js";
|
|
4
4
|
import { canonicalJson } from "./canonical_json.js";
|
|
5
|
-
import { encodeDriver } from "./drivers.js";
|
|
5
|
+
import { driversShareValueSpace, driverValueSpace, encodeDriver } from "./drivers.js";
|
|
6
6
|
import type { Field } from "./fields.js";
|
|
7
7
|
import {
|
|
8
8
|
mintAggregateSid,
|
|
@@ -126,7 +126,16 @@ function fieldValueContractDetails(field: Field): { contract: string; shape: unk
|
|
|
126
126
|
return { contract, shape: contractShape };
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Stable identity of one field contract — byte-identical to the kernel's
|
|
131
|
+
* `field_schema_identity` (pinned by the golden in `stable_ids_for_module.test.ts` and
|
|
132
|
+
* `kernel/tests/field_schema_identity.rs`). The `driver` slot carries the driver's stored
|
|
133
|
+
* VALUE SPACE (`driverValueSpace`), not the driver: switching among single-value drivers
|
|
134
|
+
* (Lww, LwwCausal, LwwBy, FirstWriterWins, FirstWriterCandidates, Surfaced/Attributed of
|
|
135
|
+
* those) keeps the identity, because D20 stores the observation antichain and the driver is
|
|
136
|
+
* a projection-time reduction. The value kind and contract stay in the identity (a retype).
|
|
137
|
+
*/
|
|
138
|
+
export function fieldSchemaIdentity(
|
|
130
139
|
aggregateSid: string,
|
|
131
140
|
fieldSid: string,
|
|
132
141
|
kind: string,
|
|
@@ -141,7 +150,7 @@ function fieldSchemaIdentity(
|
|
|
141
150
|
field: fieldSid,
|
|
142
151
|
kind,
|
|
143
152
|
valueContract,
|
|
144
|
-
driver,
|
|
153
|
+
driver: driverValueSpace(driver),
|
|
145
154
|
}),
|
|
146
155
|
"utf8",
|
|
147
156
|
)
|
|
@@ -214,7 +223,10 @@ function fieldEvolutionRules(
|
|
|
214
223
|
prior?.schema !== undefined &&
|
|
215
224
|
prior.schema !== targetSchema &&
|
|
216
225
|
prior.shape !== undefined &&
|
|
217
|
-
|
|
226
|
+
// Same stored value space (a single-value driver switch is free under D20): the prior
|
|
227
|
+
// schema was minted under an older preimage, so its stamped observations still route.
|
|
228
|
+
prior.driver !== undefined &&
|
|
229
|
+
driversShareValueSpace(prior.driver, driver) &&
|
|
218
230
|
safeAutomaticWidening(prior.shape, target.shape) &&
|
|
219
231
|
!bySource.has(prior.schema)
|
|
220
232
|
) {
|
package/src/test_call_usda.ts
CHANGED
|
@@ -24,12 +24,12 @@ function callUsdaForTestIdentity(
|
|
|
24
24
|
? { ...aggregate, audience: { kind: "public" as const } }
|
|
25
25
|
: aggregate),
|
|
26
26
|
valueObjects: collectValueObjectDescriptors(candidate.aggregates),
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
:
|
|
32
|
-
|
|
27
|
+
// Keep object identity for every directive this fixture does not change: a business intent's
|
|
28
|
+
// `.directs` step holds the original directive, and the law graph treats a copy as a second declaration.
|
|
29
|
+
directives: candidate.directives.map((directive) =>
|
|
30
|
+
(directive as { birthsChild?: boolean }).birthsChild === true
|
|
31
|
+
? { ...directive, declaredQueryReads: [] }
|
|
32
|
+
: directive),
|
|
33
33
|
});
|
|
34
34
|
const byName = new Map(
|
|
35
35
|
[module, ...closureModules].map((candidate) => [candidate.name, normalize(candidate)]),
|
|
@@ -16,6 +16,7 @@ interface RelationshipTarget {
|
|
|
16
16
|
readonly asset: string;
|
|
17
17
|
readonly line: number;
|
|
18
18
|
readonly path: string;
|
|
19
|
+
readonly relationship?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
const PRIM_DECLARATION = /^(\s*)(?:def|over)(?:\s+[A-Za-z_][A-Za-z0-9_:]*)?\s+"([^"]+)"\s*$/;
|
|
@@ -27,7 +28,10 @@ const RELATIONSHIP_TARGET = /<([^>]+)>/g;
|
|
|
27
28
|
* This intentionally checks only absolute `/Nomos` targets. Asset paths, external scene references
|
|
28
29
|
* and ordinary USD relationships retain normal OpenUSD semantics; Nomos law identities do not.
|
|
29
30
|
*/
|
|
30
|
-
export function assertUsdaRelationshipIntegrity(
|
|
31
|
+
export function assertUsdaRelationshipIntegrity(
|
|
32
|
+
assets: readonly UsdaRelationshipAsset[],
|
|
33
|
+
options: { readonly allowMissingRelationships?: ReadonlySet<string> } = {},
|
|
34
|
+
): void {
|
|
31
35
|
const prims = new Set<string>();
|
|
32
36
|
const targets: RelationshipTarget[] = [];
|
|
33
37
|
|
|
@@ -48,13 +52,26 @@ export function assertUsdaRelationshipIntegrity(assets: readonly UsdaRelationshi
|
|
|
48
52
|
for (const match of line.matchAll(RELATIONSHIP_TARGET)) {
|
|
49
53
|
const path = match[1]!;
|
|
50
54
|
if (path === "/Nomos" || path.startsWith("/Nomos/")) {
|
|
51
|
-
|
|
55
|
+
const relationship = /\brel\s+([A-Za-z_][A-Za-z0-9_:]*)\s*=/.exec(line)?.[1];
|
|
56
|
+
targets.push({
|
|
57
|
+
asset: asset.logicalPath,
|
|
58
|
+
line: offset + 1,
|
|
59
|
+
path,
|
|
60
|
+
...(relationship === undefined ? {} : { relationship }),
|
|
61
|
+
});
|
|
52
62
|
}
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
66
|
|
|
57
|
-
const missing = targets.filter(
|
|
67
|
+
const missing = targets.filter(
|
|
68
|
+
(target) =>
|
|
69
|
+
!prims.has(target.path) &&
|
|
70
|
+
!(
|
|
71
|
+
target.relationship !== undefined &&
|
|
72
|
+
options.allowMissingRelationships?.has(target.relationship)
|
|
73
|
+
),
|
|
74
|
+
);
|
|
58
75
|
if (missing.length === 0) return;
|
|
59
76
|
const examples = missing.slice(0, 8).map((target) =>
|
|
60
77
|
`${target.asset}:${target.line} targets missing prim <${target.path}>`).join("\n ");
|
package/src/usda_text.ts
CHANGED
|
@@ -3,7 +3,27 @@
|
|
|
3
3
|
|
|
4
4
|
/** Escape a string for a double-quoted USDA string literal. */
|
|
5
5
|
export function usdaString(value: string): string {
|
|
6
|
-
|
|
6
|
+
let encoded = '"';
|
|
7
|
+
for (const character of value) {
|
|
8
|
+
switch (character) {
|
|
9
|
+
case '"': encoded += '\\"'; break;
|
|
10
|
+
case "\\": encoded += "\\\\"; break;
|
|
11
|
+
case "\n": encoded += "\\n"; break;
|
|
12
|
+
case "\r": encoded += "\\r"; break;
|
|
13
|
+
case "\t": encoded += "\\t"; break;
|
|
14
|
+
case "\b": encoded += "\\b"; break;
|
|
15
|
+
case "\f": encoded += "\\f"; break;
|
|
16
|
+
default: {
|
|
17
|
+
const codePoint = character.codePointAt(0)!;
|
|
18
|
+
if (codePoint < 0x20 || codePoint === 0x7f) {
|
|
19
|
+
encoded += `\\u${codePoint.toString(16).padStart(4, "0")}`;
|
|
20
|
+
} else {
|
|
21
|
+
encoded += character;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return `${encoded}"`;
|
|
7
27
|
}
|
|
8
28
|
|
|
9
29
|
/** Emit a USDA `string[]` literal. */
|