From 6f70c80ec9c17ebe9553252e120f7f1ed7b85fce Mon Sep 17 00:00:00 2001 From: James Ross Date: Thu, 16 Jul 2026 07:52:58 -0700 Subject: [PATCH 1/6] Declare provider package components --- .../echo-wesley-gen/src/provider_semantics.rs | 116 ++++++++++++++++++ .../tests/provider_semantic_source.rs | 95 +++++++++++++- .../echo-provider-semantics-v1.json | 16 ++- 3 files changed, 224 insertions(+), 3 deletions(-) diff --git a/crates/echo-wesley-gen/src/provider_semantics.rs b/crates/echo-wesley-gen/src/provider_semantics.rs index 8cd50153..858f808d 100644 --- a/crates/echo-wesley-gen/src/provider_semantics.rs +++ b/crates/echo-wesley-gen/src/provider_semantics.rs @@ -702,6 +702,32 @@ pub struct PackageManifestProjectionDeclaration { pub provider_abi: String, /// Digest-bound provider resource coordinate selected during assembly. pub provider_coordinate: String, + /// Exact executable components bound by the package-root manifest. + pub components: Vec, +} + +/// One source-owned executable component declaration for provider packaging. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct ProviderComponentDeclaration { + /// Unique provider-manifest role. + pub role: String, + /// Frozen target-provider component class. + pub kind: ProviderComponentKind, + /// Stable component resource coordinate before its exact digest is known. + pub coordinate: String, + /// Exact frozen WIT world implemented by the component. + pub contract: String, +} + +/// Executable component classes admitted by the first provider package. +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum ProviderComponentKind { + /// Deterministic Edict semantic-to-Target-IR lowerer. + Lowerer, + /// Independent Target-IR semantic verifier. + Verifier, } /// Source identity bound by one generated authority-facts document. @@ -921,6 +947,10 @@ pub enum ProviderSemanticSourceErrorKind { SelfReferentialManifestInventory, /// The package-root manifest projection selected the wrong v1 identity. ProviderManifestProjectionMismatch, + /// A provider component selected the wrong role, coordinate, or WIT world. + ProviderComponentProjectionMismatch, + /// The package omitted or duplicated a required provider component class. + ProviderComponentClosureMismatch, /// An authority-facts artifact selected an incompatible source projection. AuthorityFactProjectionMismatch, /// A lawpack or target-profile projection was incomplete or contradictory. @@ -984,6 +1014,8 @@ impl ProviderSemanticSourceErrorKind { Self::ArtifactContractOwnerMismatch => "artifact-contract-owner-mismatch", Self::SelfReferentialManifestInventory => "self-referential-manifest-inventory", Self::ProviderManifestProjectionMismatch => "provider-manifest-projection-mismatch", + Self::ProviderComponentProjectionMismatch => "provider-component-projection-mismatch", + Self::ProviderComponentClosureMismatch => "provider-component-closure-mismatch", Self::AuthorityFactProjectionMismatch => "authority-fact-projection-mismatch", Self::ArtifactClosureMismatch => "artifact-closure-mismatch", Self::GenerationProvenanceContractMismatch => "generation-provenance-contract-mismatch", @@ -1196,6 +1228,10 @@ fn normalize_source(source: &mut ProviderSemanticSourceV1) { source .generated_artifacts .sort_by(|left, right| left.role.cmp(&right.role)); + source + .package_manifest + .components + .sort_by(|left, right| left.role.cmp(&right.role)); source .invocation_inputs .sort_by(|left, right| left.role.cmp(&right.role)); @@ -1282,6 +1318,10 @@ fn validate_identities( "packageManifest.providerCoordinate", &source.package_manifest.provider_coordinate, )); + for component in &source.package_manifest.components { + validate_component_identity(component)?; + coordinates.push(("packageManifest.components", &component.coordinate)); + } coordinates.sort_by(|left, right| left.1.cmp(right.1).then(left.0.cmp(right.0))); if let Some(window) = coordinates .windows(2) @@ -1298,6 +1338,14 @@ fn validate_identities( "generatedArtifacts.role", source.generated_artifacts.iter().map(|item| &item.role), )?; + ensure_unique_keys( + "packageManifest.components.role", + source + .package_manifest + .components + .iter() + .map(|item| &item.role), + )?; ensure_unique_keys( "artifactResources.role", source.artifact_resources.iter().map(|item| &item.role), @@ -1314,6 +1362,13 @@ fn validate_identities( .iter() .map(|item| &item.role) .collect::>(); + package_roles.extend( + source + .package_manifest + .components + .iter() + .map(|item| &item.role), + ); package_roles.push(&source.package_manifest.role); ensure_unique_keys("packageRoles", package_roles.into_iter())?; ensure_unique_keys( @@ -1439,6 +1494,17 @@ fn validate_package_manifest_identity( ) } +fn validate_component_identity( + component: &ProviderComponentDeclaration, +) -> Result<(), ProviderSemanticSourceError> { + require_nonempty("packageManifest.components.role", &component.role)?; + require_nonempty( + "packageManifest.components.coordinate", + &component.coordinate, + )?; + require_nonempty("packageManifest.components.contract", &component.contract) +} + fn collect_fact_identities<'a, T: HasIdentity>( family: &'static str, facts: &'a [T], @@ -2750,6 +2816,56 @@ fn validate_generated_artifact_contracts( &source.package_manifest.provider_coordinate, )); } + for (kind, label) in [ + (ProviderComponentKind::Lowerer, "lowerer"), + (ProviderComponentKind::Verifier, "verifier"), + ] { + let actual = source + .package_manifest + .components + .iter() + .filter(|component| component.kind == kind) + .count(); + if actual != 1 { + return Err(ProviderSemanticSourceError::new( + ProviderSemanticSourceErrorKind::ProviderComponentClosureMismatch, + "packageManifest.components", + if actual == 0 { + label.to_owned() + } else { + format!("{label}:{actual}") + }, + )); + } + } + for component in &source.package_manifest.components { + let (expected_role, expected_coordinate, expected_contract) = match component.kind { + ProviderComponentKind::Lowerer => ( + "lowerer.echo-dpo", + "echo.dpo.lowerer/component@1", + "edict:target-provider/lowerer@1.0.0", + ), + ProviderComponentKind::Verifier => ( + "verifier.echo-dpo", + "echo.dpo.verifier/component@1", + "edict:target-provider/verifier@1.0.0", + ), + }; + let mismatch = [ + (component.role.as_str(), expected_role), + (component.coordinate.as_str(), expected_coordinate), + (component.contract.as_str(), expected_contract), + ] + .into_iter() + .find_map(|(actual, expected)| (actual != expected).then_some(actual)); + if let Some(reference) = mismatch { + return Err(ProviderSemanticSourceError::new( + ProviderSemanticSourceErrorKind::ProviderComponentProjectionMismatch, + &component.role, + reference, + )); + } + } for (kind, expected_count) in [ (GeneratedArtifactKind::Lawpack, 1), (GeneratedArtifactKind::TargetProfile, 1), diff --git a/crates/echo-wesley-gen/tests/provider_semantic_source.rs b/crates/echo-wesley-gen/tests/provider_semantic_source.rs index 69c2e982..2d69038f 100644 --- a/crates/echo-wesley-gen/tests/provider_semantic_source.rs +++ b/crates/echo-wesley-gen/tests/provider_semantic_source.rs @@ -7,8 +7,8 @@ use echo_wesley_gen::provider_semantics::{ parse_provider_semantic_source_v1, ApertureRequirementDeclaration, ArtifactResourceProvision, AuthorityClass, AuthorityFactSourceKind, AuthoritySourceKind, BoundaryKind, CoreStringCanonicalization, EffectKindHint, ExecutionClass, GeneratedArtifactKind, - InvocationInputKind, InvocationOutputKind, OpticKind, ProviderSemanticSourceErrorKind, - SemanticTypeShape, ECHO_PROVIDER_SEMANTIC_SOURCE_API_V1, + InvocationInputKind, InvocationOutputKind, OpticKind, ProviderComponentKind, + ProviderSemanticSourceErrorKind, SemanticTypeShape, ECHO_PROVIDER_SEMANTIC_SOURCE_API_V1, }; use serde_json::{json, Value}; @@ -55,6 +55,35 @@ fn checked_echo_provider_semantic_source_validates() { assert_eq!(source.api_version, ECHO_PROVIDER_SEMANTIC_SOURCE_API_V1); assert_eq!(source.coordinate, "echo.semantic-schema@1"); + assert_eq!( + source + .package_manifest + .components + .iter() + .map(|component| { + ( + component.role.as_str(), + component.kind, + component.coordinate.as_str(), + component.contract.as_str(), + ) + }) + .collect::>(), + vec![ + ( + "lowerer.echo-dpo", + ProviderComponentKind::Lowerer, + "echo.dpo.lowerer/component@1", + "edict:target-provider/lowerer@1.0.0", + ), + ( + "verifier.echo-dpo", + ProviderComponentKind::Verifier, + "echo.dpo.verifier/component@1", + "edict:target-provider/verifier@1.0.0", + ), + ] + ); assert_eq!(source.operations.len(), 1); assert_eq!(source.operations[0].identity.coordinate, "a.b@1.t"); assert_eq!(source.operations[0].effect, "target.replace"); @@ -654,6 +683,7 @@ fn set_like_source_reordering_preserves_validated_semantics() { "/targetProfileProjection/acceptedCoreAbis", "/targetProfileProjection/generatedArtifactProfileRoles", "/targetProfileProjection/acceptedLawpackAdapterAbis", + "/packageManifest/components", ] { reordered .pointer_mut(pointer) @@ -1721,6 +1751,67 @@ fn generated_artifact_and_output_contracts_are_exact() { ); } +#[test] +fn package_component_declarations_fail_closed() { + assert_failure_tuple( + |source| { + source["packageManifest"]["components"] + .as_array_mut() + .expect("package components") + .remove(0); + }, + ( + ProviderSemanticSourceErrorKind::ProviderComponentClosureMismatch, + "packageManifest.components", + "lowerer", + ), + ); + assert_failure_tuple( + |source| { + source["packageManifest"]["components"][0]["contract"] = + Value::String("edict:target-provider/verifier@1.0.0".to_owned()); + }, + ( + ProviderSemanticSourceErrorKind::ProviderComponentProjectionMismatch, + "lowerer.echo-dpo", + "edict:target-provider/verifier@1.0.0", + ), + ); + assert_failure_tuple( + |source| { + source["packageManifest"]["components"][1]["kind"] = + Value::String("lowerer".to_owned()); + }, + ( + ProviderSemanticSourceErrorKind::ProviderComponentClosureMismatch, + "packageManifest.components", + "lowerer:2", + ), + ); + assert_failure_tuple( + |source| { + source["packageManifest"]["components"][1]["role"] = + Value::String("lowerer.echo-dpo".to_owned()); + }, + ( + ProviderSemanticSourceErrorKind::DuplicateKey, + "packageManifest.components.role", + "lowerer.echo-dpo", + ), + ); + assert_failure_tuple( + |source| { + source["packageManifest"]["components"][1]["coordinate"] = + Value::String("echo.dpo.lowerer/component@1".to_owned()); + }, + ( + ProviderSemanticSourceErrorKind::DuplicateCoordinate, + "packageManifest.components", + "echo.dpo.lowerer/component@1", + ), + ); +} + #[test] fn invocation_inputs_and_outputs_require_declared_schema_roles_and_domains() { assert_failure_tuple( diff --git a/schemas/edict-provider/echo-provider-semantics-v1.json b/schemas/edict-provider/echo-provider-semantics-v1.json index 0f9c3433..717e7eee 100644 --- a/schemas/edict-provider/echo-provider-semantics-v1.json +++ b/schemas/edict-provider/echo-provider-semantics-v1.json @@ -468,7 +468,21 @@ "coordinate": "echo.edict-provider-manifest@1", "schemaContract": "edict.provider-manifest/v1", "providerAbi": "edict:target-provider@1.0.0", - "providerCoordinate": "echo.edict-provider@1" + "providerCoordinate": "echo.edict-provider@1", + "components": [ + { + "role": "lowerer.echo-dpo", + "kind": "lowerer", + "coordinate": "echo.dpo.lowerer/component@1", + "contract": "edict:target-provider/lowerer@1.0.0" + }, + { + "role": "verifier.echo-dpo", + "kind": "verifier", + "coordinate": "echo.dpo.verifier/component@1", + "contract": "edict:target-provider/verifier@1.0.0" + } + ] }, "invocationInputs": [ { From cdccd6bc2ce6ebb90de6a1ef96e3285fa4a40284 Mon Sep 17 00:00:00 2001 From: James Ross Date: Thu, 16 Jul 2026 08:29:38 -0700 Subject: [PATCH 2/6] Construct digest-locked provider package --- CHANGELOG.md | 11 + crates/echo-wesley-gen/README.md | 15 + crates/echo-wesley-gen/src/lib.rs | 3 + crates/echo-wesley-gen/src/provider_corpus.rs | 2 +- .../echo-wesley-gen/src/provider_package.rs | 1770 +++++++++++++++++ .../echo-wesley-gen/tests/provider_package.rs | 647 ++++++ .../application-contract-hosting.md | 13 + schemas/edict-provider/README.md | 11 + .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- 10 files changed, 2473 insertions(+), 3 deletions(-) create mode 100644 crates/echo-wesley-gen/src/provider_package.rs create mode 100644 crates/echo-wesley-gen/tests/provider_package.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 03dae4a8..840d5bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ ### Added +- `echo-wesley-gen` now purely assembles and digest-admits the first complete + Echo Edict provider distribution from the verified 22-file generated corpus + and explicit lowerer/verifier bytes. The derived provider manifest carries ten + exact routes and nine schema bindings but never inventories itself. A + versioned canonical-CBOR package root binds those semantics plus raw hashes of + all 24 non-manifest members, while the exact 25-file inventory, deterministic + JSON rendering, mixed raw/domain-framed digest laws, packaged Wesley + provenance/review, component bounds, and an external expected provider pin + all fail closed through structured errors. This is package-occurrence + authentication only; Edict schema/component preflight and Echo runtime + installation remain separate authority crossings. - Echo now provides the exact `edict:target-provider/lowerer@1.0.0` Component Model implementation for the first checked provider closure. The pure lowerer accepts only explicit digest-bound Core, target-profile, diff --git a/crates/echo-wesley-gen/README.md b/crates/echo-wesley-gen/README.md index bdb45b60..11d73be2 100644 --- a/crates/echo-wesley-gen/README.md +++ b/crates/echo-wesley-gen/README.md @@ -112,6 +112,21 @@ semantic/settings/contract inputs already bound by Wesley and every generated output, preventing a circular generator identity. This is source/dependency-lock identity, not an executable-build or supply-chain attestation. +`provider_package` purely assembles the 22 generated files and two explicit +provider components into one 24-member, non-self-referential package closure, +then derives the separate `edict.provider-manifest/v1` JSON file. The Echo-owned +package root is a domain-framed canonical-CBOR value over the exact manifest +routes, nine schema bindings, and raw SHA-256 of every non-manifest member. +Canonical-CBOR artifact routes retain their Edict domain-framed identities; +CDDL, Wesley evidence JSON, components, and every physical member retain raw +exact-byte identities. Digest admission requires exact deterministic manifest +JSON, one shared semantic-source/generator reference proven against the packaged +Wesley provenance and review, the exact sorted 25-file inventory, and an +external caller pin. The resulting proof authenticates package occurrence only. +Edict schema-registry construction and component contract preflight remain +separate required crossings before guest execution, and Echo runtime admission +remains later still. + The dedicated `echo-edict-provider-artifacts` binary is the explicit filesystem boundary. The caller-supplied `--out` path is resolved once under ambient filesystem authority; its final corpus-root entry is opened or created without diff --git a/crates/echo-wesley-gen/src/lib.rs b/crates/echo-wesley-gen/src/lib.rs index cff73a6c..08966790 100644 --- a/crates/echo-wesley-gen/src/lib.rs +++ b/crates/echo-wesley-gen/src/lib.rs @@ -36,6 +36,9 @@ pub mod provider_review; /// Exact generator source identity and checked provider artifact corpus. pub mod provider_corpus; +/// Deterministic digest-locked Echo Edict provider package. +pub mod provider_package; + /// Imported Wesley runtime optic artifact ready for Echo registration. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportedRuntimeOpticArtifact { diff --git a/crates/echo-wesley-gen/src/provider_corpus.rs b/crates/echo-wesley-gen/src/provider_corpus.rs index 86e3c215..2bb82234 100644 --- a/crates/echo-wesley-gen/src/provider_corpus.rs +++ b/crates/echo-wesley-gen/src/provider_corpus.rs @@ -689,7 +689,7 @@ fn validate_source_path(path: &str) -> Result<(), ProviderArtifactCorpusError> { Ok(()) } -fn validate_corpus_path(path: &str) -> Result<(), ProviderArtifactCorpusError> { +pub(crate) fn validate_corpus_path(path: &str) -> Result<(), ProviderArtifactCorpusError> { if path.len() > MAX_CORPUS_PATH_BYTES { return Err(ProviderArtifactCorpusError::new( ProviderArtifactCorpusErrorKind::CorpusPathInvalid, diff --git a/crates/echo-wesley-gen/src/provider_package.rs b/crates/echo-wesley-gen/src/provider_package.rs new file mode 100644 index 00000000..d7f1178a --- /dev/null +++ b/crates/echo-wesley-gen/src/provider_package.rs @@ -0,0 +1,1770 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +//! Pure assembly and admission of the digest-locked Echo Edict provider package. +//! +//! The Edict provider manifest is a typed JSON interchange envelope, not an +//! Edict canonical-CBOR artifact. Echo therefore owns its exact deterministic +//! JSON rendering and a separate, non-self-referential package identity. The +//! package identity binds the manifest semantics plus the raw exact-byte +//! identity of every non-manifest member. It does not install a provider or +//! grant Echo runtime authority. + +use std::fmt; + +use echo_edict_canonical::{ + decode_canonical_cbor_v1, digest_canonical_value_v1, encode_canonical_cbor_v1, CanonicalValueV1, +}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use wesley_core::{ + GenerationArtifactReferenceV1, GenerationContractError, GenerationContractErrorKind, + GenerationProvenanceManifestV1, GenerationReviewV1, +}; + +use crate::provider_artifacts::{ + GeneratedProviderSchemaV1, ProviderPrimaryArtifactsV1, SchemaValidatedCanonicalProviderOutputV1, +}; +use crate::provider_corpus::{render_provider_artifact_corpus_v1, validate_corpus_path}; +use crate::provider_generation::ProviderGenerationInputV1; +use crate::provider_provenance::{ProviderGenerationProvenanceV1, ProviderGeneratorMaterialV1}; +use crate::provider_review::ProviderGenerationReviewV1; +use crate::provider_semantics::{ + ArtifactSchemaFormat, GeneratedArtifactDeclaration, GeneratedArtifactKind, + ProviderComponentDeclaration, ProviderComponentKind, +}; + +/// Domain framing the Echo-owned package-closure identity. +pub const ECHO_PROVIDER_PACKAGE_CLOSURE_DOMAIN_V1: &str = "echo.edict-provider-package-closure/v1"; +/// Exact deterministic JSON rendering contract for the Edict manifest. +pub const ECHO_PROVIDER_MANIFEST_ENCODING_V1: &str = "echo.provider-manifest.pretty-json/v1"; +/// Logical package path of the derived provider manifest. +pub const ECHO_PROVIDER_MANIFEST_PATH_V1: &str = "provider-manifest.echo.json"; + +const PROVIDER_MANIFEST_API_V1: &str = "edict.provider-manifest/v1"; +const PROVIDER_ABI_V1: &str = "edict:target-provider@1.0.0"; +const PROVIDER_COORDINATE_V1: &str = "echo.edict-provider@1"; +const PROVIDER_MANIFEST_ROLE_V1: &str = "provider-manifest.echo"; +const PROVIDER_MANIFEST_COORDINATE_V1: &str = "echo.edict-provider-manifest@1"; +const SEMANTIC_SOURCE_COORDINATE_V1: &str = "echo.semantic-schema@1"; +const GENERATOR_COORDINATE_V1: &str = "echo-wesley-gen.provider-artifact-generator@1"; +const EXPECTED_ARTIFACT_COUNT: usize = 10; +const EXPECTED_SCHEMA_BINDING_COUNT: usize = 9; +const EXPECTED_MEMBER_COUNT: usize = 24; +const EXPECTED_FILE_COUNT: usize = 25; +const MAX_COMPONENT_BYTES: usize = 16 * 1024 * 1024; +const MAX_PACKAGE_BYTES: usize = 64 * 1024 * 1024; +const MAX_MANIFEST_BYTES: usize = 1024 * 1024; +const MAX_EVIDENCE_BYTES: usize = 4 * 1024 * 1024; +const MAX_DIAGNOSTIC_BYTES: usize = 256; + +const EXPECTED_PACKAGE_PATHS: [&str; EXPECTED_FILE_COUNT] = [ + "components/lowerer.echo-dpo.component.wasm", + "components/verifier.echo-dpo.component.wasm", + "generated/evidence/provenance.provider-generation.json", + "generated/evidence/review.provider-generation.json", + "generated/primary/authority-facts.echo-dpo.cbor", + "generated/primary/authority-facts.echo-lawpack.cbor", + "generated/primary/generated-artifact-profile.echo-dpo-registration.cbor", + "generated/primary/lawpack.echo-dpo.cbor", + "generated/primary/schema.echo-provider-artifacts.cddl", + "generated/primary/target-profile.echo-dpo.cbor", + "generated/resources/resource.conformance-corpus.cbor", + "generated/resources/resource.lawpack-compatibility.cbor", + "generated/resources/resource.lawpack-exports.cbor", + "generated/resources/resource.lawpack-target-adapter.cbor", + "generated/resources/resource.lawpack-verifier.cbor", + "generated/resources/resource.target-bundle-profile.cbor", + "generated/resources/resource.target-cost-algebra.cbor", + "generated/resources/resource.target-footprint-algebra.cbor", + "generated/resources/resource.target-intrinsics.cbor", + "generated/resources/resource.target-ir.cbor", + "generated/resources/resource.target-lowerer-contract.cbor", + "generated/resources/resource.target-obstruction-taxonomy.cbor", + "generated/resources/resource.target-operation-profiles.cbor", + "generated/resources/resource.target-verifier-contract.cbor", + ECHO_PROVIDER_MANIFEST_PATH_V1, +]; + +/// Stable failures returned by provider-package assembly and admission. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ProviderPackageErrorKind { + /// Explicit component material was empty, oversized, or named an invalid role. + ComponentInvalid, + /// A source-declared component had no exact supplied bytes. + ComponentMissing, + /// A component role was supplied more than once. + ComponentDuplicate, + /// Supplied component material did not belong to the source-owned closure. + ComponentUnexpected, + /// The verified generated corpus could not be reproduced from exact inputs. + GeneratedCorpusInvalid, + /// A generated artifact did not match its source declaration. + ArtifactMismatch, + /// A required generated artifact was absent. + ArtifactMissing, + /// A package path was unsafe or outside the fixed v1 inventory. + PackagePathInvalid, + /// The complete explicit package exceeded the fixed v1 byte bound. + PackageSizeExceeded, + /// A required package member was absent. + PackageMemberMissing, + /// A package member path was repeated. + PackageMemberDuplicate, + /// A package contained a member outside the exact v1 closure. + PackageMemberUnexpected, + /// Supplied package files were not in strict path order. + PackageMemberOutOfOrder, + /// The manifest was not strict JSON matching the Echo v1 mirror. + ManifestMalformed, + /// The manifest bytes were an alternate rendering of the typed value. + ManifestNoncanonical, + /// The manifest selected a wrong API, ABI, role, coordinate, or closure. + ManifestContractMismatch, + /// A routed artifact's bytes did not reproduce its manifest digest. + ArtifactDigestMismatch, + /// A routed artifact used an incompatible provenance envelope. + ArtifactSourceMismatch, + /// Packaged Wesley provenance disagreed with generated routes or primary bytes. + GenerationProvenanceMismatch, + /// Packaged Wesley review disagreed with the canonical provenance projection. + GenerationReviewMismatch, + /// The manifest schema-domain closure differed from the exact source contract. + SchemaBindingMismatch, + /// A digest review string was not strict lowercase SHA-256. + DigestInvalid, + /// The canonical package-closure value could not be encoded or hashed. + PackageIdentityFailed, + /// The manifest provider identity, computed closure, and caller pin disagreed. + ProviderIdentityMismatch, + /// Deterministic manifest serialization failed. + ManifestSerializationFailed, +} + +impl ProviderPackageErrorKind { + const fn label(self) -> &'static str { + match self { + Self::ComponentInvalid => "component-invalid", + Self::ComponentMissing => "component-missing", + Self::ComponentDuplicate => "component-duplicate", + Self::ComponentUnexpected => "component-unexpected", + Self::GeneratedCorpusInvalid => "generated-corpus-invalid", + Self::ArtifactMismatch => "artifact-mismatch", + Self::ArtifactMissing => "artifact-missing", + Self::PackagePathInvalid => "package-path-invalid", + Self::PackageSizeExceeded => "package-size-exceeded", + Self::PackageMemberMissing => "package-member-missing", + Self::PackageMemberDuplicate => "package-member-duplicate", + Self::PackageMemberUnexpected => "package-member-unexpected", + Self::PackageMemberOutOfOrder => "package-member-out-of-order", + Self::ManifestMalformed => "manifest-malformed", + Self::ManifestNoncanonical => "manifest-noncanonical", + Self::ManifestContractMismatch => "manifest-contract-mismatch", + Self::ArtifactDigestMismatch => "artifact-digest-mismatch", + Self::ArtifactSourceMismatch => "artifact-source-mismatch", + Self::GenerationProvenanceMismatch => "generation-provenance-mismatch", + Self::GenerationReviewMismatch => "generation-review-mismatch", + Self::SchemaBindingMismatch => "schema-binding-mismatch", + Self::DigestInvalid => "digest-invalid", + Self::PackageIdentityFailed => "package-identity-failed", + Self::ProviderIdentityMismatch => "provider-identity-mismatch", + Self::ManifestSerializationFailed => "manifest-serialization-failed", + } + } +} + +/// Structured provider-package failure. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderPackageError { + kind: ProviderPackageErrorKind, + subject: String, + reference: String, + wesley_contract_kind: Option, +} + +impl ProviderPackageError { + /// Returns the stable failure category. + #[must_use] + pub const fn kind(&self) -> ProviderPackageErrorKind { + self.kind + } + + /// Returns the member, role, or contract being validated. + #[must_use] + pub fn subject(&self) -> &str { + &self.subject + } + + /// Returns the conflicting or rejected identity. + #[must_use] + pub fn reference(&self) -> &str { + &self.reference + } + + /// Returns the typed Wesley cause for provenance or review rejection. + #[must_use] + pub const fn wesley_contract_kind(&self) -> Option { + self.wesley_contract_kind + } + + fn new( + kind: ProviderPackageErrorKind, + subject: impl Into, + reference: impl Into, + ) -> Self { + Self { + kind, + subject: bounded_diagnostic(subject.into()), + reference: bounded_diagnostic(reference.into()), + wesley_contract_kind: None, + } + } + + fn wesley(mut self, error: &GenerationContractError) -> Self { + self.wesley_contract_kind = Some(error.kind); + self + } +} + +impl fmt::Display for ProviderPackageError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + formatter, + "provider package {}: {} -> {}", + self.kind.label(), + self.subject, + self.reference + ) + } +} + +impl std::error::Error for ProviderPackageError {} + +/// Required digest-locked resource reference in the generated Edict manifest. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProviderManifestResourceRefV1 { + /// Stable owner-defined resource coordinate. + pub coordinate: String, + /// Strict lowercase SHA-256 review rendering. + pub digest: String, +} + +/// Artifact kinds mirrored from Edict's `edict.provider-manifest/v1` envelope. +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum ProviderManifestArtifactKindV1 { + /// Canonical Edict lawpack manifest. + Lawpack, + /// Canonical target-profile manifest. + TargetProfile, + /// Canonical authority-facts document. + AuthorityFacts, + /// Provider manifest artifact; excluded from this manifest's own inventory. + ProviderManifest, + /// Non-authoritative generation review JSON. + ReviewArtifact, + /// Echo generated-artifact profile. + GeneratedArtifactProfile, + /// Wesley generation-provenance JSON. + GenerationProvenance, + /// Self-contained generated CDDL schema. + ArtifactSchema, + /// Target-provider lowerer component. + Lowerer, + /// Target-provider verifier component. + Verifier, +} + +impl ProviderManifestArtifactKindV1 { + const fn as_str(self) -> &'static str { + match self { + Self::Lawpack => "lawpack", + Self::TargetProfile => "targetProfile", + Self::AuthorityFacts => "authorityFacts", + Self::ProviderManifest => "providerManifest", + Self::ReviewArtifact => "reviewArtifact", + Self::GeneratedArtifactProfile => "generatedArtifactProfile", + Self::GenerationProvenance => "generationProvenance", + Self::ArtifactSchema => "artifactSchema", + Self::Lowerer => "lowerer", + Self::Verifier => "verifier", + } + } +} + +/// Provenance envelope for one manifest artifact route. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(tag = "kind", rename_all = "camelCase", deny_unknown_fields)] +pub enum ProviderManifestArtifactSourceV1 { + /// Generated metadata bound to exact authored source and generator identities. + Generated { + /// Raw exact-byte semantic-source reference. + #[serde(rename = "semanticSource")] + semantic_source: ProviderManifestResourceRefV1, + /// Raw exact-byte generator source-bundle reference. + generator: ProviderManifestResourceRefV1, + }, + /// Executable component bound to its own exact raw bytes. + Component { + /// Resource-identical component reference. + component: ProviderManifestResourceRefV1, + }, +} + +/// One deterministic artifact route in the Edict provider manifest. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct ProviderManifestArtifactV1 { + /// Unique package-local role. + pub role: String, + /// Generic Edict artifact class. + pub artifact_kind: ProviderManifestArtifactKindV1, + /// Digest-locked semantic or exact-byte artifact identity. + pub resource: ProviderManifestResourceRefV1, + /// Generated or component provenance route. + pub source: ProviderManifestArtifactSourceV1, +} + +/// Schema formats accepted by the v1 Edict host. +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum ProviderManifestSchemaFormatV1 { + /// Self-contained generated CDDL. + SelfContainedCddlV1, +} + +impl ProviderManifestSchemaFormatV1 { + const fn as_str(self) -> &'static str { + match self { + Self::SelfContainedCddlV1 => "selfContainedCddlV1", + } + } +} + +/// One immutable domain-to-schema binding in the Edict provider manifest. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct ProviderManifestSchemaBindingV1 { + /// Canonical artifact domain. + pub domain: String, + /// Manifest role containing the self-contained schema. + pub schema_role: String, + /// Frozen schema format. + pub format: ProviderManifestSchemaFormatV1, + /// Exact CDDL root rule. + pub root_rule: String, +} + +/// Deterministically serialized mirror of Edict's provider-manifest v1 value. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct ProviderManifestV1 { + /// Exact Edict manifest API version. + pub api_version: String, + /// Exact frozen target-provider component ABI. + pub provider_abi: String, + /// Echo-owned non-self-referential provider package identity. + pub provider: ProviderManifestResourceRefV1, + /// Ten exact generated/component artifact routes. + pub artifacts: Vec, + /// Nine exact immutable schema-domain bindings. + pub schema_bindings: Vec, +} + +/// Explicit exact bytes for one source-declared provider component. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderPackageComponentMaterialV1 { + role: String, + bytes: Vec, +} + +impl ProviderPackageComponentMaterialV1 { + /// Constructs bounded component material without path or registry discovery. + /// + /// # Errors + /// + /// Returns a stable error for an empty/oversized byte string or empty role. + pub fn new(role: impl Into, bytes: &[u8]) -> Result { + let role = role.into(); + if role.is_empty() || bytes.is_empty() || bytes.len() > MAX_COMPONENT_BYTES { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ComponentInvalid, + role, + bytes.len().to_string(), + )); + } + Ok(Self { + role, + bytes: bytes.to_vec(), + }) + } + + /// Returns the source-declared manifest role. + #[must_use] + pub fn role(&self) -> &str { + &self.role + } + + /// Returns the exact component bytes. + #[must_use] + pub fn bytes(&self) -> &[u8] { + &self.bytes + } +} + +/// One exact logical file in a provider package. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderPackageFileV1 { + relative_path: String, + bytes: Vec, +} + +impl ProviderPackageFileV1 { + /// Constructs a package file with a safe relative POSIX path. + /// + /// # Errors + /// + /// Returns a stable error for paths outside the bounded corpus grammar. + pub fn new( + relative_path: impl Into, + bytes: &[u8], + ) -> Result { + let relative_path = relative_path.into(); + validate_corpus_path(&relative_path).map_err(|error| { + ProviderPackageError::new( + ProviderPackageErrorKind::PackagePathInvalid, + relative_path.clone(), + error.reference(), + ) + })?; + Ok(Self { + relative_path, + bytes: bytes.to_vec(), + }) + } + + /// Returns the slash-normalized logical package path. + #[must_use] + pub fn relative_path(&self) -> &str { + &self.relative_path + } + + /// Returns the exact file bytes. + #[must_use] + pub fn bytes(&self) -> &[u8] { + &self.bytes + } +} + +/// One non-manifest physical member bound into the provider closure. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderPackageMemberV1 { + file: ProviderPackageFileV1, + raw_digest: String, +} + +impl ProviderPackageMemberV1 { + /// Returns the member's logical package path. + #[must_use] + pub fn relative_path(&self) -> &str { + self.file.relative_path() + } + + /// Returns the member's exact bytes. + #[must_use] + pub fn bytes(&self) -> &[u8] { + self.file.bytes() + } + + /// Returns raw SHA-256 of the exact package occurrence. + #[must_use] + pub fn raw_digest(&self) -> &str { + &self.raw_digest + } + + fn new(file: ProviderPackageFileV1) -> Self { + let raw_digest = raw_sha256(file.bytes()); + Self { file, raw_digest } + } +} + +/// Complete deterministic package materials assembled from exact inputs. +/// +/// This value proves package construction only. It is not Edict schema or +/// component compatibility proof and is not Echo runtime authority. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ProviderPackageV1 { + manifest: ProviderManifestV1, + manifest_bytes: Vec, + manifest_content_reference: GenerationArtifactReferenceV1, + closure_bytes: Vec, + members: Vec, + files: Vec, +} + +impl ProviderPackageV1 { + /// Returns the typed provider manifest. + #[must_use] + pub const fn manifest(&self) -> &ProviderManifestV1 { + &self.manifest + } + + /// Returns exact deterministic pretty-JSON manifest bytes. + #[must_use] + pub fn manifest_bytes(&self) -> &[u8] { + &self.manifest_bytes + } + + /// Returns the externally pinnable package-closure identity. + #[must_use] + pub const fn provider_reference(&self) -> &ProviderManifestResourceRefV1 { + &self.manifest.provider + } + + /// Returns raw exact-byte identity of the derived manifest occurrence. + #[must_use] + pub const fn manifest_content_reference(&self) -> &GenerationArtifactReferenceV1 { + &self.manifest_content_reference + } + + /// Returns the exact canonical-CBOR package-closure preimage value bytes. + #[must_use] + pub fn closure_bytes(&self) -> &[u8] { + &self.closure_bytes + } + + /// Returns all 24 non-manifest members in exact path order. + #[must_use] + pub fn members(&self) -> &[ProviderPackageMemberV1] { + &self.members + } + + /// Returns all 25 package files in exact path order. + #[must_use] + pub fn files(&self) -> &[ProviderPackageFileV1] { + &self.files + } +} + +/// Opaque proof that explicit package bytes match their caller-pinned digest root. +/// +/// This proof authenticates inventory, manifest routing, packaged Wesley +/// evidence, and exact bytes. Edict schema construction and component preflight +/// remain separate required crossings before guest execution. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DigestAdmittedProviderPackageV1 { + manifest: ProviderManifestV1, + provider_reference: ProviderManifestResourceRefV1, + files: Vec, +} + +impl DigestAdmittedProviderPackageV1 { + /// Returns the exact manifest admitted by the package boundary. + #[must_use] + pub const fn manifest(&self) -> &ProviderManifestV1 { + &self.manifest + } + + /// Returns the caller-pinned, recomputed provider package identity. + #[must_use] + pub const fn provider_reference(&self) -> &ProviderManifestResourceRefV1 { + &self.provider_reference + } + + /// Returns the admitted exact file closure retained in memory. + #[must_use] + pub fn files(&self) -> &[ProviderPackageFileV1] { + &self.files + } +} + +/// Assembles the deterministic package from verified generated values and exact components. +/// +/// This function is pure. It performs no filesystem, registry, environment, +/// process, clock, network, component execution, or Echo runtime admission. +/// +/// # Errors +/// +/// Returns a structured error when provenance, review, generated artifacts, +/// source-owned component declarations, member inventory, serialization, or +/// package identity disagree. +pub fn assemble_provider_package_v1( + input: &ProviderGenerationInputV1, + primary: &ProviderPrimaryArtifactsV1, + generator: &ProviderGeneratorMaterialV1, + provenance: &ProviderGenerationProvenanceV1, + review: &ProviderGenerationReviewV1, + mut components: Vec, +) -> Result { + let corpus = render_provider_artifact_corpus_v1(input, primary, generator, provenance, review) + .map_err(|error| { + ProviderPackageError::new( + ProviderPackageErrorKind::GeneratedCorpusInvalid, + error.subject(), + error.reference(), + ) + })?; + let source = input.semantic_source().source(); + let package_declaration = &source.package_manifest; + if package_declaration.role != PROVIDER_MANIFEST_ROLE_V1 + || package_declaration.coordinate != PROVIDER_MANIFEST_COORDINATE_V1 + || package_declaration.schema_contract != PROVIDER_MANIFEST_API_V1 + || package_declaration.provider_abi != PROVIDER_ABI_V1 + || package_declaration.provider_coordinate != PROVIDER_COORDINATE_V1 + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ManifestContractMismatch, + &package_declaration.role, + &package_declaration.coordinate, + )); + } + + let semantic_source = input + .source_artifacts() + .iter() + .find(|artifact| artifact.coordinate == source.coordinate) + .ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactMissing, + "semanticSource", + &source.coordinate, + ) + })? + .reference(); + let generated_source = ProviderManifestArtifactSourceV1::Generated { + semantic_source: manifest_ref(&semantic_source.coordinate, &semantic_source.digest), + generator: manifest_ref( + &generator.identity().coordinate, + &generator.identity().digest, + ), + }; + + let mut artifacts = Vec::with_capacity(EXPECTED_ARTIFACT_COUNT); + for declaration in &source.generated_artifacts { + artifacts.push(generated_manifest_artifact( + declaration, + primary, + provenance, + review, + &generated_source, + )?); + } + + components.sort_by(|left, right| left.role.as_bytes().cmp(right.role.as_bytes())); + if let Some(pair) = components + .windows(2) + .find(|pair| pair[0].role == pair[1].role) + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ComponentDuplicate, + &pair[0].role, + &pair[1].role, + )); + } + let mut component_members = Vec::with_capacity(package_declaration.components.len()); + for declaration in &package_declaration.components { + let material = components + .iter() + .find(|material| material.role == declaration.role) + .ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::ComponentMissing, + &declaration.role, + &declaration.coordinate, + ) + })?; + let resource = manifest_ref(&declaration.coordinate, &raw_sha256(&material.bytes)); + artifacts.push(component_manifest_artifact(declaration, resource.clone())); + component_members.push(ProviderPackageMemberV1::new(ProviderPackageFileV1::new( + format!("components/{}.component.wasm", declaration.role), + &material.bytes, + )?)); + } + if let Some(material) = components.iter().find(|material| { + !package_declaration + .components + .iter() + .any(|declaration| declaration.role == material.role) + }) { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ComponentUnexpected, + &material.role, + "packageManifest.components", + )); + } + artifacts.sort_by(|left, right| left.role.as_bytes().cmp(right.role.as_bytes())); + + let schema_bindings = source + .schema_bindings + .iter() + .map(|binding| ProviderManifestSchemaBindingV1 { + domain: binding.domain.clone(), + schema_role: binding.schema_role.clone(), + format: match binding.format { + ArtifactSchemaFormat::SelfContainedCddlV1 => { + ProviderManifestSchemaFormatV1::SelfContainedCddlV1 + } + }, + root_rule: binding.root_rule.clone(), + }) + .collect::>(); + + let mut members = corpus + .files() + .iter() + .map(|file| { + ProviderPackageFileV1::new(format!("generated/{}", file.relative_path()), file.bytes()) + .map(ProviderPackageMemberV1::new) + }) + .collect::, _>>()?; + members.extend(component_members); + members.sort_by(|left, right| { + left.relative_path() + .as_bytes() + .cmp(right.relative_path().as_bytes()) + }); + validate_member_count_and_order(&members)?; + + let provider_digest = package_closure_digest(&artifacts, &schema_bindings, &members)?; + let manifest = ProviderManifestV1 { + api_version: PROVIDER_MANIFEST_API_V1.to_owned(), + provider_abi: PROVIDER_ABI_V1.to_owned(), + provider: manifest_ref(PROVIDER_COORDINATE_V1, &provider_digest), + artifacts, + schema_bindings, + }; + let manifest_bytes = render_manifest(&manifest)?; + let manifest_content_reference = + GenerationArtifactReferenceV1::for_bytes(PROVIDER_MANIFEST_COORDINATE_V1, &manifest_bytes) + .map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::ManifestSerializationFailed, + PROVIDER_MANIFEST_COORDINATE_V1, + "wesley-content-reference", + ) + })?; + let closure_value = + package_closure_value(&manifest.artifacts, &manifest.schema_bindings, &members)?; + let closure_bytes = encode_canonical_cbor_v1(&closure_value).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::PackageIdentityFailed, + ECHO_PROVIDER_PACKAGE_CLOSURE_DOMAIN_V1, + "canonical-cbor", + ) + })?; + let mut files = members + .iter() + .map(|member| member.file.clone()) + .collect::>(); + files.push(ProviderPackageFileV1::new( + ECHO_PROVIDER_MANIFEST_PATH_V1, + &manifest_bytes, + )?); + files.sort_by(|left, right| { + left.relative_path + .as_bytes() + .cmp(right.relative_path.as_bytes()) + }); + validate_file_inventory(&files)?; + validate_total_package_size(&files)?; + + Ok(ProviderPackageV1 { + manifest, + manifest_bytes, + manifest_content_reference, + closure_bytes, + members, + files, + }) +} + +/// Digest-admits an explicit in-memory package against a caller-supplied identity. +/// +/// The boundary requires the exact v1 file inventory and rendering, reproduces +/// every routed artifact identity, binds every non-manifest member into the +/// package root, and returns no partial package on failure. It performs no I/O, +/// does not replace Edict schema/component preflight, and grants no Echo runtime +/// authority. +/// +/// # Errors +/// +/// Returns a structured error for malformed or alternate manifest bytes, +/// missing/duplicate/unexpected/out-of-order files, wrong artifact bytes or +/// provenance, schema-closure disagreement, or provider-root disagreement. +pub fn admit_provider_package_v1( + files: Vec, + expected_provider: &ProviderManifestResourceRefV1, +) -> Result { + validate_file_inventory(&files)?; + validate_total_package_size(&files)?; + let manifest_file = file_by_path(&files, ECHO_PROVIDER_MANIFEST_PATH_V1)?; + validate_member_size(manifest_file, MAX_MANIFEST_BYTES)?; + let manifest: ProviderManifestV1 = + serde_json::from_slice(manifest_file.bytes()).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::ManifestMalformed, + ECHO_PROVIDER_MANIFEST_PATH_V1, + ECHO_PROVIDER_MANIFEST_ENCODING_V1, + ) + })?; + if render_manifest(&manifest)? != manifest_file.bytes() { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ManifestNoncanonical, + ECHO_PROVIDER_MANIFEST_PATH_V1, + raw_sha256(manifest_file.bytes()), + )); + } + validate_expected_provider(&manifest.provider, expected_provider)?; + validate_manifest_contract(&manifest, &files)?; + + let members = files + .iter() + .filter(|file| file.relative_path != ECHO_PROVIDER_MANIFEST_PATH_V1) + .cloned() + .map(ProviderPackageMemberV1::new) + .collect::>(); + validate_member_count_and_order(&members)?; + let computed = manifest_ref( + PROVIDER_COORDINATE_V1, + &package_closure_digest(&manifest.artifacts, &manifest.schema_bindings, &members)?, + ); + if manifest.provider != computed || expected_provider != &computed { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ProviderIdentityMismatch, + PROVIDER_COORDINATE_V1, + computed.digest, + )); + } + + Ok(DigestAdmittedProviderPackageV1 { + manifest, + provider_reference: computed, + files, + }) +} + +fn generated_manifest_artifact( + declaration: &GeneratedArtifactDeclaration, + primary: &ProviderPrimaryArtifactsV1, + provenance: &ProviderGenerationProvenanceV1, + review: &ProviderGenerationReviewV1, + source: &ProviderManifestArtifactSourceV1, +) -> Result { + let (artifact_kind, resource) = match declaration.kind { + GeneratedArtifactKind::Lawpack => ( + ProviderManifestArtifactKindV1::Lawpack, + canonical_artifact_ref(declaration, primary)?, + ), + GeneratedArtifactKind::TargetProfile => ( + ProviderManifestArtifactKindV1::TargetProfile, + canonical_artifact_ref(declaration, primary)?, + ), + GeneratedArtifactKind::AuthorityFacts => ( + ProviderManifestArtifactKindV1::AuthorityFacts, + canonical_artifact_ref(declaration, primary)?, + ), + GeneratedArtifactKind::ProviderManifest => { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ManifestContractMismatch, + &declaration.role, + &declaration.coordinate, + )); + } + GeneratedArtifactKind::ReviewArtifact => { + require_declared_json( + declaration, + review.role(), + review.coordinate(), + review.schema_contract(), + )?; + ( + ProviderManifestArtifactKindV1::ReviewArtifact, + manifest_ref(review.coordinate(), &review.content_reference().digest), + ) + } + GeneratedArtifactKind::GeneratedArtifactProfile => ( + ProviderManifestArtifactKindV1::GeneratedArtifactProfile, + canonical_artifact_ref(declaration, primary)?, + ), + GeneratedArtifactKind::GenerationProvenance => { + require_declared_json( + declaration, + provenance.role(), + provenance.coordinate(), + provenance.schema_contract(), + )?; + ( + ProviderManifestArtifactKindV1::GenerationProvenance, + manifest_ref( + provenance.coordinate(), + &provenance.content_reference().digest, + ), + ) + } + GeneratedArtifactKind::ArtifactSchema => { + require_declared_schema(declaration, primary.schema())?; + ( + ProviderManifestArtifactKindV1::ArtifactSchema, + manifest_ref( + primary.schema().coordinate(), + &primary.schema().content_reference().digest, + ), + ) + } + }; + Ok(ProviderManifestArtifactV1 { + role: declaration.role.clone(), + artifact_kind, + resource, + source: source.clone(), + }) +} + +fn canonical_artifact_ref( + declaration: &GeneratedArtifactDeclaration, + primary: &ProviderPrimaryArtifactsV1, +) -> Result { + let artifact = primary.artifact(&declaration.role).ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactMissing, + &declaration.role, + &declaration.coordinate, + ) + })?; + require_declared_canonical(declaration, artifact)?; + Ok(manifest_ref( + artifact.coordinate(), + artifact.domain_framed_digest(), + )) +} + +fn require_declared_canonical( + declaration: &GeneratedArtifactDeclaration, + artifact: &SchemaValidatedCanonicalProviderOutputV1, +) -> Result<(), ProviderPackageError> { + if declaration.role != artifact.role() + || declaration.coordinate != artifact.coordinate() + || declaration.schema_contract != artifact.schema_contract() + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactMismatch, + &declaration.role, + artifact.coordinate(), + )); + } + Ok(()) +} + +fn require_declared_schema( + declaration: &GeneratedArtifactDeclaration, + schema: &GeneratedProviderSchemaV1, +) -> Result<(), ProviderPackageError> { + if declaration.role != schema.role() || declaration.coordinate != schema.coordinate() { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactMismatch, + &declaration.role, + schema.coordinate(), + )); + } + Ok(()) +} + +fn require_declared_json( + declaration: &GeneratedArtifactDeclaration, + role: &str, + coordinate: &str, + schema_contract: &str, +) -> Result<(), ProviderPackageError> { + if declaration.role != role + || declaration.coordinate != coordinate + || declaration.schema_contract != schema_contract + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactMismatch, + &declaration.role, + coordinate, + )); + } + Ok(()) +} + +fn component_manifest_artifact( + declaration: &ProviderComponentDeclaration, + resource: ProviderManifestResourceRefV1, +) -> ProviderManifestArtifactV1 { + ProviderManifestArtifactV1 { + role: declaration.role.clone(), + artifact_kind: match declaration.kind { + ProviderComponentKind::Lowerer => ProviderManifestArtifactKindV1::Lowerer, + ProviderComponentKind::Verifier => ProviderManifestArtifactKindV1::Verifier, + }, + resource: resource.clone(), + source: ProviderManifestArtifactSourceV1::Component { + component: resource, + }, + } +} + +fn validate_manifest_contract( + manifest: &ProviderManifestV1, + files: &[ProviderPackageFileV1], +) -> Result<(), ProviderPackageError> { + if manifest.api_version != PROVIDER_MANIFEST_API_V1 + || manifest.provider_abi != PROVIDER_ABI_V1 + || manifest.provider.coordinate != PROVIDER_COORDINATE_V1 + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ManifestContractMismatch, + &manifest.api_version, + &manifest.provider_abi, + )); + } + strict_digest_bytes(&manifest.provider.digest)?; + let specs = artifact_specs(); + if manifest.artifacts.len() != specs.len() { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ManifestContractMismatch, + "artifacts", + manifest.artifacts.len().to_string(), + )); + } + for (artifact, spec) in manifest.artifacts.iter().zip(specs) { + if artifact.role != spec.role + || artifact.artifact_kind != spec.artifact_kind + || artifact.resource.coordinate != spec.coordinate + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ManifestContractMismatch, + &artifact.role, + &artifact.resource.coordinate, + )); + } + strict_digest_bytes(&artifact.resource.digest)?; + validate_artifact_source(artifact, spec.component)?; + let file = file_by_path(files, spec.path)?; + if spec.component && (file.bytes().is_empty() || file.bytes().len() > MAX_COMPONENT_BYTES) { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ComponentInvalid, + spec.role, + file.bytes().len().to_string(), + )); + } + let actual_digest = match spec.digest_domain { + Some(domain) => { + let value = decode_canonical_cbor_v1(file.bytes()).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactDigestMismatch, + spec.role, + "canonical-cbor", + ) + })?; + digest_canonical_value_v1(domain, &value).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactDigestMismatch, + spec.role, + domain, + ) + })? + } + None => raw_sha256(file.bytes()), + }; + if artifact.resource.digest != actual_digest { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactDigestMismatch, + spec.role, + actual_digest, + )); + } + } + validate_generated_source_closure(&manifest.artifacts)?; + validate_generation_evidence(manifest, files)?; + validate_schema_bindings(&manifest.schema_bindings) +} + +fn validate_expected_provider( + manifest_provider: &ProviderManifestResourceRefV1, + expected_provider: &ProviderManifestResourceRefV1, +) -> Result<(), ProviderPackageError> { + strict_digest_bytes(&manifest_provider.digest)?; + strict_digest_bytes(&expected_provider.digest)?; + if expected_provider.coordinate != PROVIDER_COORDINATE_V1 + || manifest_provider != expected_provider + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ProviderIdentityMismatch, + &expected_provider.coordinate, + &expected_provider.digest, + )); + } + Ok(()) +} + +fn validate_generation_evidence( + manifest: &ProviderManifestV1, + files: &[ProviderPackageFileV1], +) -> Result<(), ProviderPackageError> { + let provenance_file = file_by_path( + files, + "generated/evidence/provenance.provider-generation.json", + )?; + validate_member_size(provenance_file, MAX_EVIDENCE_BYTES)?; + let provenance: GenerationProvenanceManifestV1 = + serde_json::from_slice(provenance_file.bytes()).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "provenance.provider-generation", + "wesley-generation-provenance-json/v1", + ) + })?; + let canonical_provenance = provenance.canonical_bytes().map_err(|error| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "provenance.provider-generation", + "wesley-generation-provenance-contract/v1", + ) + .wesley(&error) + })?; + if canonical_provenance != provenance_file.bytes() { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "provenance.provider-generation", + "noncanonical-json", + )); + } + + let (manifest_source, manifest_generator) = manifest + .artifacts + .iter() + .find_map(|artifact| match &artifact.source { + ProviderManifestArtifactSourceV1::Generated { + semantic_source, + generator, + } => Some((semantic_source, generator)), + ProviderManifestArtifactSourceV1::Component { .. } => None, + }) + .ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "artifacts", + "generated-source-missing", + ) + })?; + if provenance.generator.coordinate != manifest_generator.coordinate + || provenance.generator.digest != manifest_generator.digest + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "generator", + &provenance.generator.digest, + )); + } + let provenance_source = provenance + .source_artifacts + .iter() + .find(|reference| reference.coordinate == SEMANTIC_SOURCE_COORDINATE_V1) + .ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "sourceArtifacts", + SEMANTIC_SOURCE_COORDINATE_V1, + ) + })?; + if provenance_source.coordinate != manifest_source.coordinate + || provenance_source.digest != manifest_source.digest + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + SEMANTIC_SOURCE_COORDINATE_V1, + &provenance_source.digest, + )); + } + let expected_emitted = expected_emitted_references(files)?; + if provenance.emitted_artifacts != expected_emitted { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "emittedArtifacts", + provenance.emitted_artifacts.len().to_string(), + )); + } + + let review_file = file_by_path(files, "generated/evidence/review.provider-generation.json")?; + validate_member_size(review_file, MAX_EVIDENCE_BYTES)?; + let review: GenerationReviewV1 = + serde_json::from_slice(review_file.bytes()).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationReviewMismatch, + "review.provider-generation", + "wesley-generation-review-json/v1", + ) + })?; + let canonical_review = review.canonical_bytes().map_err(|error| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationReviewMismatch, + "review.provider-generation", + "wesley-generation-review-contract/v1", + ) + .wesley(&error) + })?; + if canonical_review != review_file.bytes() + || review.authoritative() + || review.generation_input_digest != provenance.generation_input_digest + || review.generator != provenance.generator + || review.source_artifacts != provenance.source_artifacts + || review.emitted_artifacts != provenance.emitted_artifacts + || review.projection_roles != expected_projection_roles() + || review.provenance_manifest_digest + != provenance.digest().map_err(|error| { + ProviderPackageError::new( + ProviderPackageErrorKind::GenerationProvenanceMismatch, + "provenance.provider-generation", + "wesley-provenance-digest/v1", + ) + .wesley(&error) + })? + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::GenerationReviewMismatch, + "review.provider-generation", + "provenance-projection", + )); + } + Ok(()) +} + +fn expected_emitted_references( + files: &[ProviderPackageFileV1], +) -> Result, ProviderPackageError> { + let mut references = artifact_specs() + .into_iter() + .filter(|spec| { + !spec.component + && !matches!( + spec.artifact_kind, + ProviderManifestArtifactKindV1::GenerationProvenance + | ProviderManifestArtifactKindV1::ReviewArtifact + ) + }) + .map(|spec| { + let file = file_by_path(files, spec.path)?; + Ok(GenerationArtifactReferenceV1 { + coordinate: spec.coordinate.to_owned(), + digest: raw_sha256(file.bytes()), + }) + }) + .collect::, ProviderPackageError>>()?; + references.sort_by(|left, right| left.coordinate.cmp(&right.coordinate)); + Ok(references) +} + +fn expected_projection_roles() -> Vec { + [ + "authority-facts.echo-dpo", + "authority-facts.echo-lawpack", + "generated-artifact-profile.echo-dpo-registration", + "lawpack.echo-dpo", + "schema.echo-provider-artifacts", + "target-profile.echo-dpo", + ] + .into_iter() + .map(str::to_owned) + .collect() +} + +fn validate_generated_source_closure( + artifacts: &[ProviderManifestArtifactV1], +) -> Result<(), ProviderPackageError> { + let expected = artifacts + .iter() + .find_map(|artifact| match &artifact.source { + ProviderManifestArtifactSourceV1::Generated { + semantic_source, + generator, + } => Some((semantic_source, generator)), + ProviderManifestArtifactSourceV1::Component { .. } => None, + }); + let Some((expected_source, expected_generator)) = expected else { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactSourceMismatch, + "artifacts", + "generated-source-missing", + )); + }; + for artifact in artifacts { + if let ProviderManifestArtifactSourceV1::Generated { + semantic_source, + generator, + } = &artifact.source + { + if semantic_source != expected_source || generator != expected_generator { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactSourceMismatch, + &artifact.role, + &semantic_source.digest, + )); + } + } + } + Ok(()) +} + +fn validate_artifact_source( + artifact: &ProviderManifestArtifactV1, + component: bool, +) -> Result<(), ProviderPackageError> { + match (&artifact.source, component) { + (ProviderManifestArtifactSourceV1::Component { component }, true) + if component == &artifact.resource => + { + Ok(()) + } + ( + ProviderManifestArtifactSourceV1::Generated { + semantic_source, + generator, + }, + false, + ) if semantic_source.coordinate == SEMANTIC_SOURCE_COORDINATE_V1 + && generator.coordinate == GENERATOR_COORDINATE_V1 => + { + strict_digest_bytes(&semantic_source.digest)?; + strict_digest_bytes(&generator.digest)?; + Ok(()) + } + _ => Err(ProviderPackageError::new( + ProviderPackageErrorKind::ArtifactSourceMismatch, + &artifact.role, + artifact.resource.coordinate.clone(), + )), + } +} + +fn validate_schema_bindings( + bindings: &[ProviderManifestSchemaBindingV1], +) -> Result<(), ProviderPackageError> { + let expected = schema_binding_specs(); + if bindings.len() != expected.len() { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::SchemaBindingMismatch, + "schemaBindings", + bindings.len().to_string(), + )); + } + for (binding, (domain, root_rule)) in bindings.iter().zip(expected) { + if binding.domain != domain + || binding.schema_role != "schema.echo-provider-artifacts" + || binding.format != ProviderManifestSchemaFormatV1::SelfContainedCddlV1 + || binding.root_rule != root_rule + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::SchemaBindingMismatch, + &binding.domain, + &binding.root_rule, + )); + } + } + Ok(()) +} + +fn package_closure_digest( + artifacts: &[ProviderManifestArtifactV1], + schema_bindings: &[ProviderManifestSchemaBindingV1], + members: &[ProviderPackageMemberV1], +) -> Result { + let value = package_closure_value(artifacts, schema_bindings, members)?; + digest_canonical_value_v1(ECHO_PROVIDER_PACKAGE_CLOSURE_DOMAIN_V1, &value).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::PackageIdentityFailed, + ECHO_PROVIDER_PACKAGE_CLOSURE_DOMAIN_V1, + "canonical-cbor", + ) + }) +} + +fn package_closure_value( + artifacts: &[ProviderManifestArtifactV1], + schema_bindings: &[ProviderManifestSchemaBindingV1], + members: &[ProviderPackageMemberV1], +) -> Result { + let artifact_values = artifacts + .iter() + .map(|artifact| { + Ok(CanonicalValueV1::Array(vec![ + text(&artifact.role), + text(artifact.artifact_kind.as_str()), + text(&artifact.resource.coordinate), + CanonicalValueV1::Bytes(strict_digest_bytes(&artifact.resource.digest)?), + source_value(&artifact.source)?, + ])) + }) + .collect::, ProviderPackageError>>()?; + let binding_values = schema_bindings + .iter() + .map(|binding| { + CanonicalValueV1::Array(vec![ + text(&binding.domain), + text(&binding.schema_role), + text(binding.format.as_str()), + text(&binding.root_rule), + ]) + }) + .collect(); + let member_values = members + .iter() + .map(|member| { + Ok(CanonicalValueV1::Array(vec![ + text(member.relative_path()), + CanonicalValueV1::Bytes(strict_digest_bytes(&member.raw_digest)?), + ])) + }) + .collect::, ProviderPackageError>>()?; + Ok(CanonicalValueV1::Array(vec![ + text(PROVIDER_MANIFEST_ROLE_V1), + text(PROVIDER_MANIFEST_COORDINATE_V1), + text(ECHO_PROVIDER_MANIFEST_ENCODING_V1), + text(PROVIDER_MANIFEST_API_V1), + text(PROVIDER_ABI_V1), + text(PROVIDER_COORDINATE_V1), + CanonicalValueV1::Array(artifact_values), + CanonicalValueV1::Array(binding_values), + CanonicalValueV1::Array(member_values), + ])) +} + +fn source_value( + source: &ProviderManifestArtifactSourceV1, +) -> Result { + match source { + ProviderManifestArtifactSourceV1::Generated { + semantic_source, + generator, + } => Ok(CanonicalValueV1::Array(vec![ + text("generated"), + text(&semantic_source.coordinate), + CanonicalValueV1::Bytes(strict_digest_bytes(&semantic_source.digest)?), + text(&generator.coordinate), + CanonicalValueV1::Bytes(strict_digest_bytes(&generator.digest)?), + ])), + ProviderManifestArtifactSourceV1::Component { component } => { + Ok(CanonicalValueV1::Array(vec![ + text("component"), + text(&component.coordinate), + CanonicalValueV1::Bytes(strict_digest_bytes(&component.digest)?), + ])) + } + } +} + +fn validate_member_count_and_order( + members: &[ProviderPackageMemberV1], +) -> Result<(), ProviderPackageError> { + if members.len() != EXPECTED_MEMBER_COUNT { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberMissing, + "package-members", + members.len().to_string(), + )); + } + for pair in members.windows(2) { + match pair[0] + .relative_path() + .as_bytes() + .cmp(pair[1].relative_path().as_bytes()) + { + std::cmp::Ordering::Less => {} + std::cmp::Ordering::Equal => { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberDuplicate, + pair[0].relative_path(), + pair[1].relative_path(), + )); + } + std::cmp::Ordering::Greater => { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberOutOfOrder, + pair[0].relative_path(), + pair[1].relative_path(), + )); + } + } + } + Ok(()) +} + +fn validate_file_inventory(files: &[ProviderPackageFileV1]) -> Result<(), ProviderPackageError> { + for pair in files.windows(2) { + match pair[0] + .relative_path + .as_bytes() + .cmp(pair[1].relative_path.as_bytes()) + { + std::cmp::Ordering::Less => {} + std::cmp::Ordering::Equal => { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberDuplicate, + &pair[0].relative_path, + &pair[1].relative_path, + )); + } + std::cmp::Ordering::Greater => { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberOutOfOrder, + &pair[0].relative_path, + &pair[1].relative_path, + )); + } + } + } + if let Some(file) = files + .iter() + .find(|file| !EXPECTED_PACKAGE_PATHS.contains(&file.relative_path.as_str())) + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberUnexpected, + &file.relative_path, + "provider-package/v1", + )); + } + if let Some(path) = EXPECTED_PACKAGE_PATHS + .iter() + .find(|path| !files.iter().any(|file| file.relative_path == **path)) + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberMissing, + *path, + "provider-package/v1", + )); + } + if files.len() != EXPECTED_FILE_COUNT { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberDuplicate, + "provider-package/v1", + files.len().to_string(), + )); + } + Ok(()) +} + +fn validate_total_package_size( + files: &[ProviderPackageFileV1], +) -> Result<(), ProviderPackageError> { + let total_bytes = files.iter().try_fold(0_usize, |total, file| { + total.checked_add(file.bytes.len()).ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::PackageSizeExceeded, + "provider-package/v1", + "byte-length-overflow", + ) + }) + })?; + if total_bytes > MAX_PACKAGE_BYTES { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageSizeExceeded, + "provider-package/v1", + total_bytes.to_string(), + )); + } + Ok(()) +} + +fn validate_member_size( + file: &ProviderPackageFileV1, + maximum: usize, +) -> Result<(), ProviderPackageError> { + if file.bytes().len() > maximum { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::PackageSizeExceeded, + file.relative_path(), + file.bytes().len().to_string(), + )); + } + Ok(()) +} + +fn file_by_path<'a>( + files: &'a [ProviderPackageFileV1], + path: &str, +) -> Result<&'a ProviderPackageFileV1, ProviderPackageError> { + files + .iter() + .find(|file| file.relative_path == path) + .ok_or_else(|| { + ProviderPackageError::new( + ProviderPackageErrorKind::PackageMemberMissing, + path, + "provider-package/v1", + ) + }) +} + +fn render_manifest(manifest: &ProviderManifestV1) -> Result, ProviderPackageError> { + let mut bytes = serde_json::to_vec_pretty(manifest).map_err(|_error| { + ProviderPackageError::new( + ProviderPackageErrorKind::ManifestSerializationFailed, + PROVIDER_MANIFEST_COORDINATE_V1, + ECHO_PROVIDER_MANIFEST_ENCODING_V1, + ) + })?; + bytes.push(b'\n'); + Ok(bytes) +} + +fn manifest_ref(coordinate: &str, digest: &str) -> ProviderManifestResourceRefV1 { + ProviderManifestResourceRefV1 { + coordinate: coordinate.to_owned(), + digest: digest.to_owned(), + } +} + +fn raw_sha256(bytes: &[u8]) -> String { + format!("sha256:{}", hex::encode(Sha256::digest(bytes))) +} + +fn strict_digest_bytes(digest: &str) -> Result, ProviderPackageError> { + let Some(hex_digest) = digest.strip_prefix("sha256:") else { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::DigestInvalid, + "sha256", + digest, + )); + }; + if hex_digest.len() != 64 + || !hex_digest + .as_bytes() + .iter() + .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(byte)) + { + return Err(ProviderPackageError::new( + ProviderPackageErrorKind::DigestInvalid, + "sha256", + digest, + )); + } + hex::decode(hex_digest).map_err(|_error| { + ProviderPackageError::new(ProviderPackageErrorKind::DigestInvalid, "sha256", digest) + }) +} + +fn text(value: &str) -> CanonicalValueV1 { + CanonicalValueV1::Text(value.to_owned()) +} + +fn bounded_diagnostic(mut value: String) -> String { + if value.len() <= MAX_DIAGNOSTIC_BYTES { + return value; + } + let mut end = MAX_DIAGNOSTIC_BYTES; + while !value.is_char_boundary(end) { + end -= 1; + } + value.truncate(end); + value +} + +#[derive(Clone, Copy)] +struct ArtifactSpec { + role: &'static str, + artifact_kind: ProviderManifestArtifactKindV1, + coordinate: &'static str, + path: &'static str, + digest_domain: Option<&'static str>, + component: bool, +} + +fn artifact_specs() -> [ArtifactSpec; EXPECTED_ARTIFACT_COUNT] { + [ + ArtifactSpec { + role: "authority-facts.echo-dpo", + artifact_kind: ProviderManifestArtifactKindV1::AuthorityFacts, + coordinate: "echo.dpo-authority-facts@1", + path: "generated/primary/authority-facts.echo-dpo.cbor", + digest_domain: Some("edict.authority-facts/v1"), + component: false, + }, + ArtifactSpec { + role: "authority-facts.echo-lawpack", + artifact_kind: ProviderManifestArtifactKindV1::AuthorityFacts, + coordinate: "echo.dpo-lawpack-authority-facts@1", + path: "generated/primary/authority-facts.echo-lawpack.cbor", + digest_domain: Some("edict.authority-facts/v1"), + component: false, + }, + ArtifactSpec { + role: "generated-artifact-profile.echo-dpo-registration", + artifact_kind: ProviderManifestArtifactKindV1::GeneratedArtifactProfile, + coordinate: "echo.dpo.registration/v1", + path: "generated/primary/generated-artifact-profile.echo-dpo-registration.cbor", + digest_domain: Some("echo.generated-artifact-profile/v1"), + component: false, + }, + ArtifactSpec { + role: "lawpack.echo-dpo", + artifact_kind: ProviderManifestArtifactKindV1::Lawpack, + coordinate: "echo.dpo-lawpack@1", + path: "generated/primary/lawpack.echo-dpo.cbor", + digest_domain: Some("edict.lawpack/v1"), + component: false, + }, + ArtifactSpec { + role: "lowerer.echo-dpo", + artifact_kind: ProviderManifestArtifactKindV1::Lowerer, + coordinate: "echo.dpo.lowerer/component@1", + path: "components/lowerer.echo-dpo.component.wasm", + digest_domain: None, + component: true, + }, + ArtifactSpec { + role: "provenance.provider-generation", + artifact_kind: ProviderManifestArtifactKindV1::GenerationProvenance, + coordinate: "echo.edict-provider-generation-provenance@1", + path: "generated/evidence/provenance.provider-generation.json", + digest_domain: None, + component: false, + }, + ArtifactSpec { + role: "review.provider-generation", + artifact_kind: ProviderManifestArtifactKindV1::ReviewArtifact, + coordinate: "echo.edict-provider-generation-review@1", + path: "generated/evidence/review.provider-generation.json", + digest_domain: None, + component: false, + }, + ArtifactSpec { + role: "schema.echo-provider-artifacts", + artifact_kind: ProviderManifestArtifactKindV1::ArtifactSchema, + coordinate: "echo.provider-artifacts.cddl@1", + path: "generated/primary/schema.echo-provider-artifacts.cddl", + digest_domain: None, + component: false, + }, + ArtifactSpec { + role: "target-profile.echo-dpo", + artifact_kind: ProviderManifestArtifactKindV1::TargetProfile, + coordinate: "echo.dpo@1", + path: "generated/primary/target-profile.echo-dpo.cbor", + digest_domain: Some("edict.target-profile/v1"), + component: false, + }, + ArtifactSpec { + role: "verifier.echo-dpo", + artifact_kind: ProviderManifestArtifactKindV1::Verifier, + coordinate: "echo.dpo.verifier/component@1", + path: "components/verifier.echo-dpo.component.wasm", + digest_domain: None, + component: true, + }, + ] +} + +fn schema_binding_specs() -> [(&'static str, &'static str); EXPECTED_SCHEMA_BINDING_COUNT] { + [ + ("echo.generated-artifact/v1", "generated-artifact"), + ("echo.review-payload/v1", "review-payload"), + ("echo.verifier-report/v1", "verifier-report"), + ("edict.authority-facts/v1", "authority-facts"), + ("edict.core.module/v1", "core-module"), + ("edict.lawpack/v1", "lawpack-manifest"), + ("edict.lowering-requirements/v1", "lowering-requirements"), + ("edict.target-ir.artifact/v1", "target-ir-artifact"), + ("edict.target-profile/v1", "target-profile-manifest"), + ] +} diff --git a/crates/echo-wesley-gen/tests/provider_package.rs b/crates/echo-wesley-gen/tests/provider_package.rs new file mode 100644 index 00000000..4c6be31e --- /dev/null +++ b/crates/echo-wesley-gen/tests/provider_package.rs @@ -0,0 +1,647 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::expect_used, clippy::panic)] +//! Deterministic, digest-locked Echo Edict provider package. + +use echo_wesley_gen::provider_artifacts::{ + generate_provider_primary_artifacts_v1, ProviderPrimaryArtifactsV1, +}; +use echo_wesley_gen::provider_contract_pack::{ + admit_provider_contract_pack_v1, AdmittedProviderContractPackV1, +}; +use echo_wesley_gen::provider_corpus::checked_provider_generator_source_bundle_v1; +use echo_wesley_gen::provider_generation::{ + build_provider_generation_input_v1, ProviderGenerationInputV1, +}; +use echo_wesley_gen::provider_package::{ + admit_provider_package_v1, assemble_provider_package_v1, ProviderManifestArtifactKindV1, + ProviderManifestArtifactSourceV1, ProviderManifestResourceRefV1, + ProviderPackageComponentMaterialV1, ProviderPackageErrorKind, ProviderPackageFileV1, + ProviderPackageV1, ECHO_PROVIDER_MANIFEST_PATH_V1, +}; +use echo_wesley_gen::provider_provenance::{ + generate_provider_generation_provenance_v1, ProviderGenerationProvenanceV1, + ProviderGeneratorMaterialV1, +}; +use echo_wesley_gen::provider_review::{ + generate_provider_generation_review_v1, ProviderGenerationReviewV1, +}; +use wesley_core::{compute_generation_artifact_digest_v1, GenerationContractErrorKind}; + +const SOURCE: &[u8] = + include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = + include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const CONTRACT_CDDL: &[u8] = + include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); +const CONTRACT_MANIFEST: &[u8] = + include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); +const LOWERER: &[u8] = + include_bytes!("../../../schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm"); +const VERIFIER: &[u8] = include_bytes!( + "../../../schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm" +); + +fn admitted_pack() -> AdmittedProviderContractPackV1 { + admit_provider_contract_pack_v1(CONTRACT_CDDL, CONTRACT_MANIFEST) + .expect("checked Edict provider contract pack is admitted") +} + +fn generate() -> ( + ProviderGenerationInputV1, + ProviderPrimaryArtifactsV1, + ProviderGeneratorMaterialV1, + ProviderGenerationProvenanceV1, + ProviderGenerationReviewV1, +) { + let pack = admitted_pack(); + let input = build_provider_generation_input_v1(SOURCE, &pack, SETTINGS) + .expect("checked provider generation input builds"); + let primary = generate_provider_primary_artifacts_v1(&input, &pack) + .expect("checked primary provider artifacts generate"); + let generator = checked_provider_generator_source_bundle_v1() + .expect("checked generator source bundle builds") + .generator_material() + .expect("checked generator material builds"); + let provenance = generate_provider_generation_provenance_v1(&input, &primary, &generator) + .expect("checked provider provenance generates"); + let review = generate_provider_generation_review_v1(&input, &provenance) + .expect("checked provider review generates"); + (input, primary, generator, provenance, review) +} + +fn components(reverse: bool) -> Vec { + let mut components = vec![ + ProviderPackageComponentMaterialV1::new("lowerer.echo-dpo", LOWERER) + .expect("lowerer material is bounded"), + ProviderPackageComponentMaterialV1::new("verifier.echo-dpo", VERIFIER) + .expect("verifier material is bounded"), + ]; + if reverse { + components.reverse(); + } + components +} + +fn assemble(reverse_components: bool) -> ProviderPackageV1 { + let (input, primary, generator, provenance, review) = generate(); + assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + components(reverse_components), + ) + .expect("checked provider package assembles") +} + +fn replace_manifest( + package: &ProviderPackageV1, + mutate: impl FnOnce(&mut echo_wesley_gen::provider_package::ProviderManifestV1), +) -> Vec { + let mut manifest = package.manifest().clone(); + mutate(&mut manifest); + let mut bytes = serde_json::to_vec_pretty(&manifest).expect("mutated manifest serializes"); + bytes.push(b'\n'); + let mut files = package.files().to_vec(); + let index = files + .iter() + .position(|file| file.relative_path() == ECHO_PROVIDER_MANIFEST_PATH_V1) + .expect("manifest file exists"); + files[index] = ProviderPackageFileV1::new(ECHO_PROVIDER_MANIFEST_PATH_V1, &bytes) + .expect("manifest path is valid"); + files +} + +#[test] +fn checked_materials_assemble_one_digest_locked_provider_package() { + let package = assemble(false); + let reordered = assemble(true); + + assert_eq!(package, reordered); + assert_eq!(package.members().len(), 24); + assert_eq!(package.files().len(), 25); + assert_eq!(package.manifest().artifacts.len(), 10); + assert_eq!(package.manifest().schema_bindings.len(), 9); + assert_eq!( + package + .manifest() + .artifacts + .iter() + .map(|artifact| artifact.role.as_str()) + .collect::>(), + vec![ + "authority-facts.echo-dpo", + "authority-facts.echo-lawpack", + "generated-artifact-profile.echo-dpo-registration", + "lawpack.echo-dpo", + "lowerer.echo-dpo", + "provenance.provider-generation", + "review.provider-generation", + "schema.echo-provider-artifacts", + "target-profile.echo-dpo", + "verifier.echo-dpo", + ] + ); + assert!( + package + .manifest() + .artifacts + .iter() + .all(|artifact| artifact.artifact_kind + != ProviderManifestArtifactKindV1::ProviderManifest) + ); + assert!(package + .members() + .iter() + .all(|member| member.relative_path() != ECHO_PROVIDER_MANIFEST_PATH_V1)); + assert_eq!( + package + .files() + .iter() + .filter(|file| file.relative_path() == ECHO_PROVIDER_MANIFEST_PATH_V1) + .count(), + 1 + ); + assert!(package.manifest_bytes().ends_with(b"\n")); + assert_eq!(package.provider_reference(), &package.manifest().provider); + assert_ne!( + package.provider_reference().digest, + package.manifest_content_reference().digest + ); + assert!(package + .files() + .windows(2) + .all(|pair| pair[0].relative_path().as_bytes() < pair[1].relative_path().as_bytes())); + + let admitted = + admit_provider_package_v1(package.files().to_vec(), package.provider_reference()) + .expect("exact package admits against its external identity"); + assert_eq!(admitted.provider_reference(), package.provider_reference()); + assert_eq!(admitted.manifest(), package.manifest()); +} + +#[test] +fn manifest_routes_preserve_semantic_and_exact_byte_digest_classes() { + let (input, primary, generator, provenance, review) = generate(); + let package = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + components(false), + ) + .expect("checked provider package assembles"); + + for output in primary.artifacts() { + let route = package + .manifest() + .artifacts + .iter() + .find(|artifact| artifact.role == output.role()) + .expect("canonical output has a manifest route"); + assert_eq!(route.resource.digest, output.domain_framed_digest()); + assert_ne!(route.resource.digest, output.content_reference().digest); + let member = package + .members() + .iter() + .find(|member| member.relative_path().contains(output.role())) + .expect("canonical output has a physical member"); + assert_eq!(member.bytes(), output.canonical_bytes()); + assert_ne!(member.raw_digest(), route.resource.digest); + } + + let schema = package + .manifest() + .artifacts + .iter() + .find(|artifact| artifact.artifact_kind == ProviderManifestArtifactKindV1::ArtifactSchema) + .expect("schema route exists"); + assert_eq!( + schema.resource.digest, + primary.schema().content_reference().digest + ); + let provenance_route = package + .manifest() + .artifacts + .iter() + .find(|artifact| { + artifact.artifact_kind == ProviderManifestArtifactKindV1::GenerationProvenance + }) + .expect("provenance route exists"); + assert_eq!( + provenance_route.resource.digest, + provenance.content_reference().digest + ); + let review_route = package + .manifest() + .artifacts + .iter() + .find(|artifact| artifact.artifact_kind == ProviderManifestArtifactKindV1::ReviewArtifact) + .expect("review route exists"); + assert_eq!( + review_route.resource.digest, + review.content_reference().digest + ); +} + +#[test] +fn generated_routes_require_one_exact_source_and_generator_reference() { + let package = assemble(false); + let files = replace_manifest(&package, |manifest| { + let source = match &mut manifest.artifacts[0].source { + ProviderManifestArtifactSourceV1::Generated { + semantic_source, .. + } => semantic_source, + ProviderManifestArtifactSourceV1::Component { .. } => { + panic!("first artifact is generated") + } + }; + source.digest = + "sha256:0000000000000000000000000000000000000000000000000000000000000000".to_owned(); + }); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("generated routes cannot disagree on exact source identity"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ArtifactSourceMismatch + ); +} + +#[test] +fn agreeing_generated_routes_must_match_packaged_wesley_provenance() { + let package = assemble(false); + let files = replace_manifest(&package, |manifest| { + for artifact in &mut manifest.artifacts { + if let ProviderManifestArtifactSourceV1::Generated { + semantic_source, .. + } = &mut artifact.source + { + semantic_source.digest = + "sha256:0000000000000000000000000000000000000000000000000000000000000000" + .to_owned(); + } + } + }); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("agreeing fake routes cannot replace packaged provenance"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::GenerationProvenanceMismatch + ); +} + +#[test] +fn packaged_wesley_evidence_preserves_the_typed_contract_failure() { + let package = assemble(false); + let provenance_path = "generated/evidence/provenance.provider-generation.json"; + let provenance_file = package + .files() + .iter() + .find(|file| file.relative_path() == provenance_path) + .expect("provenance file exists"); + let mut provenance: serde_json::Value = + serde_json::from_slice(provenance_file.bytes()).expect("provenance is JSON"); + provenance["contractVersions"]["inputSchema"] = + serde_json::Value::String("wesley.wrong/v1".to_owned()); + let changed_bytes = serde_json::to_vec(&provenance).expect("changed provenance serializes"); + let changed_digest = compute_generation_artifact_digest_v1(&changed_bytes); + let mut files = replace_manifest(&package, |manifest| { + manifest + .artifacts + .iter_mut() + .find(|artifact| { + artifact.artifact_kind == ProviderManifestArtifactKindV1::GenerationProvenance + }) + .expect("provenance route exists") + .resource + .digest = changed_digest; + }); + let index = files + .iter() + .position(|file| file.relative_path() == provenance_path) + .expect("provenance file exists"); + files[index] = ProviderPackageFileV1::new(provenance_path, &changed_bytes) + .expect("provenance path is valid"); + + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("wrong Wesley contract version must fail before package use"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::GenerationProvenanceMismatch + ); + assert_eq!( + error.wesley_contract_kind(), + Some(GenerationContractErrorKind::ContractVersionMismatch) + ); +} + +#[test] +fn valid_looking_raw_digest_cannot_replace_a_canonical_artifact_identity() { + let (input, primary, generator, provenance, review) = generate(); + let package = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + components(false), + ) + .expect("checked provider package assembles"); + let raw_lawpack_digest = primary + .artifact("lawpack.echo-dpo") + .expect("lawpack exists") + .content_reference() + .digest + .clone(); + let files = replace_manifest(&package, |manifest| { + manifest + .artifacts + .iter_mut() + .find(|artifact| artifact.role == "lawpack.echo-dpo") + .expect("lawpack route exists") + .resource + .digest = raw_lawpack_digest; + }); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("raw byte identity cannot impersonate the Edict semantic identity"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ArtifactDigestMismatch + ); +} + +#[test] +fn opaque_component_bytes_move_the_digest_root_without_proving_host_readiness() { + let baseline = assemble(false); + let (input, primary, generator, provenance, review) = generate(); + let mut changed_lowerer = LOWERER.to_vec(); + changed_lowerer[0] ^= 1; + let changed = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + vec![ + ProviderPackageComponentMaterialV1::new("lowerer.echo-dpo", &changed_lowerer) + .expect("changed lowerer remains bounded explicit material"), + ProviderPackageComponentMaterialV1::new("verifier.echo-dpo", VERIFIER) + .expect("verifier remains bounded explicit material"), + ], + ) + .expect("coherently changed package assembles a different identity"); + assert_ne!(changed.provider_reference(), baseline.provider_reference()); + let error = admit_provider_package_v1(changed.files().to_vec(), baseline.provider_reference()) + .expect_err("coherent internal rebinding cannot cross the caller's old pin"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ProviderIdentityMismatch + ); +} + +#[test] +fn package_admission_rejects_manifest_member_and_expected_root_tampering() { + let package = assemble(false); + + let mut alternate_manifest = package.files().to_vec(); + let manifest_index = alternate_manifest + .iter() + .position(|file| file.relative_path() == ECHO_PROVIDER_MANIFEST_PATH_V1) + .expect("manifest file exists"); + let mut alternate_bytes = alternate_manifest[manifest_index].bytes().to_vec(); + alternate_bytes.push(b'\n'); + alternate_manifest[manifest_index] = + ProviderPackageFileV1::new(ECHO_PROVIDER_MANIFEST_PATH_V1, &alternate_bytes) + .expect("manifest path is valid"); + let error = admit_provider_package_v1(alternate_manifest, package.provider_reference()) + .expect_err("alternate JSON occurrence must fail exact rendering"); + assert_eq!(error.kind(), ProviderPackageErrorKind::ManifestNoncanonical); + + let mut resource_tamper = package.files().to_vec(); + let resource_index = resource_tamper + .iter() + .position(|file| file.relative_path() == "generated/resources/resource.target-ir.cbor") + .expect("generated resource exists"); + let mut tampered_bytes = resource_tamper[resource_index].bytes().to_vec(); + tampered_bytes[0] ^= 1; + resource_tamper[resource_index] = ProviderPackageFileV1::new( + "generated/resources/resource.target-ir.cbor", + &tampered_bytes, + ) + .expect("resource path is valid"); + let error = admit_provider_package_v1(resource_tamper, package.provider_reference()) + .expect_err("unrouted resource tamper must move the pinned package root"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ProviderIdentityMismatch + ); + + let mut component_tamper = package.files().to_vec(); + let lowerer_index = component_tamper + .iter() + .position(|file| file.relative_path() == "components/lowerer.echo-dpo.component.wasm") + .expect("lowerer component exists"); + let mut tampered_bytes = component_tamper[lowerer_index].bytes().to_vec(); + tampered_bytes[0] ^= 1; + component_tamper[lowerer_index] = ProviderPackageFileV1::new( + "components/lowerer.echo-dpo.component.wasm", + &tampered_bytes, + ) + .expect("component path is valid"); + let error = admit_provider_package_v1(component_tamper, package.provider_reference()) + .expect_err("routed component tamper must fail its exact manifest identity"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ArtifactDigestMismatch + ); + + let wrong_expected = ProviderManifestResourceRefV1 { + coordinate: package.provider_reference().coordinate.clone(), + digest: "sha256:0000000000000000000000000000000000000000000000000000000000000000" + .to_owned(), + }; + let error = admit_provider_package_v1(package.files().to_vec(), &wrong_expected) + .expect_err("internally coherent package cannot replace caller identity"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ProviderIdentityMismatch + ); +} + +#[test] +fn component_material_closure_fails_without_discovery_or_winner_selection() { + let (input, primary, generator, provenance, review) = generate(); + let error = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + vec![ + ProviderPackageComponentMaterialV1::new("verifier.echo-dpo", VERIFIER) + .expect("verifier material is bounded"), + ], + ) + .expect_err("missing lowerer bytes must fail closed"); + assert_eq!(error.kind(), ProviderPackageErrorKind::ComponentMissing); + assert_eq!(error.subject(), "lowerer.echo-dpo"); + + let error = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + vec![ + ProviderPackageComponentMaterialV1::new("lowerer.echo-dpo", LOWERER) + .expect("lowerer material is bounded"), + ProviderPackageComponentMaterialV1::new("lowerer.echo-dpo", VERIFIER) + .expect("conflicting duplicate remains explicit material"), + ProviderPackageComponentMaterialV1::new("verifier.echo-dpo", VERIFIER) + .expect("verifier material is bounded"), + ], + ) + .expect_err("conflicting duplicate roles must not select a winner"); + assert_eq!(error.kind(), ProviderPackageErrorKind::ComponentDuplicate); + assert_eq!(error.subject(), "lowerer.echo-dpo"); + + let mut with_unexpected = components(false); + with_unexpected.push( + ProviderPackageComponentMaterialV1::new("component.unexpected", b"explicit") + .expect("unexpected material remains bounded"), + ); + let error = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + with_unexpected, + ) + .expect_err("unexpected component material must not be ignored"); + assert_eq!(error.kind(), ProviderPackageErrorKind::ComponentUnexpected); + assert_eq!(error.subject(), "component.unexpected"); +} + +#[test] +fn raw_admission_preserves_component_material_bounds() { + let package = assemble(false); + let empty_digest = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + let mut files = replace_manifest(&package, |manifest| { + let lowerer = manifest + .artifacts + .iter_mut() + .find(|artifact| artifact.role == "lowerer.echo-dpo") + .expect("lowerer route exists"); + lowerer.resource.digest = empty_digest.to_owned(); + match &mut lowerer.source { + ProviderManifestArtifactSourceV1::Component { component } => { + component.digest = empty_digest.to_owned(); + } + ProviderManifestArtifactSourceV1::Generated { .. } => { + panic!("lowerer has component provenance") + } + } + }); + let lowerer_index = files + .iter() + .position(|file| file.relative_path() == "components/lowerer.echo-dpo.component.wasm") + .expect("lowerer file exists"); + files[lowerer_index] = + ProviderPackageFileV1::new("components/lowerer.echo-dpo.component.wasm", b"") + .expect("empty bytes do not change the safe path"); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("raw admission cannot bypass the component byte bound"); + assert_eq!(error.kind(), ProviderPackageErrorKind::ComponentInvalid); +} + +#[test] +fn package_file_inventory_requires_exact_unique_path_order() { + let package = assemble(false); + + let mut reversed = package.files().to_vec(); + reversed.reverse(); + let error = admit_provider_package_v1(reversed, package.provider_reference()) + .expect_err("admission must not normalize supplied file order"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::PackageMemberOutOfOrder + ); + + let mut missing = package.files().to_vec(); + missing.remove(0); + let error = admit_provider_package_v1(missing, package.provider_reference()) + .expect_err("missing package member must fail closed"); + assert_eq!(error.kind(), ProviderPackageErrorKind::PackageMemberMissing); + + let mut duplicate = package.files().to_vec(); + duplicate.push(duplicate[0].clone()); + duplicate.sort_by(|left, right| left.relative_path().cmp(right.relative_path())); + let error = admit_provider_package_v1(duplicate, package.provider_reference()) + .expect_err("identical duplicate member remains ambiguous"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::PackageMemberDuplicate + ); + + let mut unexpected = package.files().to_vec(); + unexpected[0] = ProviderPackageFileV1::new("components/unknown.component.wasm", b"unknown") + .expect("unexpected path is syntactically safe"); + unexpected.sort_by(|left, right| left.relative_path().cmp(right.relative_path())); + let error = admit_provider_package_v1(unexpected, package.provider_reference()) + .expect_err("safe but undeclared member must fail closed"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::PackageMemberUnexpected + ); +} + +#[test] +fn manifest_contract_source_and_schema_mutations_fail_before_root_comparison() { + let package = assemble(false); + + let files = replace_manifest(&package, |manifest| { + manifest.schema_bindings[0].root_rule = "wrong-root".to_owned(); + }); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("wrong existing schema route must fail as a schema disagreement"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::SchemaBindingMismatch + ); + + let generated_source = package + .manifest() + .artifacts + .iter() + .find_map(|artifact| match &artifact.source { + ProviderManifestArtifactSourceV1::Generated { .. } => Some(artifact.source.clone()), + ProviderManifestArtifactSourceV1::Component { .. } => None, + }) + .expect("generated source exists"); + let files = replace_manifest(&package, |manifest| { + manifest + .artifacts + .iter_mut() + .find(|artifact| artifact.role == "lowerer.echo-dpo") + .expect("lowerer route exists") + .source = generated_source; + }); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("component role cannot use generated provenance"); + assert_eq!( + error.kind(), + ProviderPackageErrorKind::ArtifactSourceMismatch + ); + + let files = replace_manifest(&package, |manifest| { + manifest.provider.digest = + "SHA256:0000000000000000000000000000000000000000000000000000000000000000".to_owned(); + }); + let error = admit_provider_package_v1(files, package.provider_reference()) + .expect_err("digest textual aliases must not be normalized"); + assert_eq!(error.kind(), ProviderPackageErrorKind::DigestInvalid); +} diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index 945d7355..6df97d34 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -186,6 +186,19 @@ owning root in that authenticated CDDL. Passing both checks attests provider artifact shape only. It does not make authority-facts runtime Echo authority, install a package, admit an operation, or authorize a runtime consequence. +The #655 package identity is an Echo-owned, versioned canonical-CBOR closure, +not a hash of the completed JSON manifest. It binds the manifest role and +coordinate, exact API and provider ABI, ten sorted semantic/component routes, +nine sorted schema bindings, and raw exact-byte hashes for all 24 non-manifest +members. The derived manifest carries that root and has its own independent raw +content identity. Canonical-CBOR routes preserve their Edict domain-framed +artifact digests while the package member table preserves raw occurrences, so +neither proposition impersonates the other. Admission requires the caller's +external provider pin and exact-reproduces packaged Wesley provenance/review. +That boundary still proves only the distribution occurrence: the Edict-owned +schema registry and component host must separately admit roots, bytes, +attestations, imports, exports, and WIT types before guest execution. + The target-profile lowerer and verifier resources are generated declarative contract documents. They do not select executable implementations. The package manifest separately binds the exact provider-owned components and their frozen diff --git a/schemas/edict-provider/README.md b/schemas/edict-provider/README.md index 829f3fb8..7eca4b4d 100644 --- a/schemas/edict-provider/README.md +++ b/schemas/edict-provider/README.md @@ -188,5 +188,16 @@ them with the generated semantic artifacts, and generates the package-root listed inside its own artifact inventory. Runtime `reviewPayload` invocation output is distinct from #652's build-time `reviewArtifact`. +The package closure contains the 22 generated files plus the exact lowerer and +verifier components. Its Echo-owned provider digest binds the typed manifest +routes, the nine domain-to-root bindings, and raw SHA-256 of all 24 physical +members without hashing the derived manifest into itself. The five routed +canonical-CBOR artifacts use their Edict domain-framed identities in the +manifest, while CDDL, Wesley JSON evidence, and components use raw exact-byte +identities. Pure digest admission also rebinds the generated routes to the +packaged provenance/review and requires an external expected provider +reference. This is package-occurrence evidence, not Edict component or schema +compatibility proof and not Echo runtime installation or authority. + All generated files are derived artifacts. Their digests and review renderings must never be copied back into this file as authored semantic facts. diff --git a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json index 9bdeefb2..6e2d5405 100644 --- a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:326024c55f16dfedfc887b11c24b6f6b596b08ae6b1abcc3a7269dc7728d9730","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:5325aca06a7b00900e8be3ecd3e420138cc1ff94cf615b5be4552fdfb9392447","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:656a68b126669a629643302d679712626a90dbd7a38b521932630a141fe426ac"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:22c293f0b0809335cdfb307ed5912f2a7e9d0a5ae140a63e46cd2d4619cbd1a7","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json index 3bbaeaf3..5c296669 100644 --- a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:326024c55f16dfedfc887b11c24b6f6b596b08ae6b1abcc3a7269dc7728d9730","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:5325aca06a7b00900e8be3ecd3e420138cc1ff94cf615b5be4552fdfb9392447","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:a76347f1e54e22b21c4298fab750e83ea7611b7a37f889d78434c53cf4527cb1","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:656a68b126669a629643302d679712626a90dbd7a38b521932630a141fe426ac"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:22c293f0b0809335cdfb307ed5912f2a7e9d0a5ae140a63e46cd2d4619cbd1a7","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:14503aa28ab96c07c93cec00d98b87ff0109c7ad45431c3baf259d502bae4ae1","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file From 594f99737cfb9309e73d55d80a308d433de50a48 Mon Sep 17 00:00:00 2001 From: James Ross Date: Thu, 16 Jul 2026 09:02:29 -0700 Subject: [PATCH 3/6] Publish digest-locked provider package --- .gitattributes | 5 + .github/workflows/ci.yml | 2 + CHANGELOG.md | 9 +- crates/echo-wesley-gen/README.md | 20 + .../src/bin/echo-edict-provider-artifacts.rs | 554 +--------- .../src/bin/echo-edict-provider-package.rs | 144 +++ crates/echo-wesley-gen/src/lib.rs | 3 + crates/echo-wesley-gen/src/provider_corpus.rs | 176 +++- .../echo-wesley-gen/src/provider_corpus_fs.rs | 833 +++++++++++++++ .../tests/provider_artifact_corpus.rs | 3 +- .../echo-wesley-gen/tests/provider_package.rs | 21 +- .../tests/provider_package_corpus.rs | 246 +++++ det-policy.yaml | 4 + .../application-contract-hosting.md | 8 + schemas/edict-provider/README.md | 7 + .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- schemas/edict-provider/package/README.md | 36 + .../lowerer.echo-dpo.component.wasm | Bin 0 -> 130679 bytes .../verifier.echo-dpo.component.wasm | Bin 0 -> 188736 bytes .../provenance.provider-generation.json | 1 + .../evidence/review.provider-generation.json | 1 + .../primary/authority-facts.echo-dpo.cbor | 1 + .../primary/authority-facts.echo-lawpack.cbor | Bin 0 -> 243 bytes ...rtifact-profile.echo-dpo-registration.cbor | 1 + .../generated/primary/lawpack.echo-dpo.cbor | Bin 0 -> 799 bytes .../schema.echo-provider-artifacts.cddl | 969 ++++++++++++++++++ .../primary/target-profile.echo-dpo.cbor | Bin 0 -> 1733 bytes .../resource.conformance-corpus.cbor | 1 + .../resource.lawpack-compatibility.cbor | 1 + .../resources/resource.lawpack-exports.cbor | 1 + .../resource.lawpack-target-adapter.cbor | 1 + .../resources/resource.lawpack-verifier.cbor | 1 + .../resource.target-bundle-profile.cbor | 1 + .../resource.target-cost-algebra.cbor | 1 + .../resource.target-footprint-algebra.cbor | 1 + .../resources/resource.target-intrinsics.cbor | 1 + .../resources/resource.target-ir.cbor | 1 + .../resource.target-lowerer-contract.cbor | 1 + .../resource.target-obstruction-taxonomy.cbor | 1 + .../resource.target-operation-profiles.cbor | 1 + .../resource.target-verifier-contract.cbor | 1 + .../package/v1/provider-manifest.echo.json | 248 +++++ scripts/tests/classify_changes.test.cjs | 4 + 44 files changed, 2757 insertions(+), 557 deletions(-) create mode 100644 crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs create mode 100644 crates/echo-wesley-gen/src/provider_corpus_fs.rs create mode 100644 crates/echo-wesley-gen/tests/provider_package_corpus.rs create mode 100644 schemas/edict-provider/package/README.md create mode 100644 schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm create mode 100644 schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm create mode 100644 schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json create mode 100644 schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json create mode 100644 schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor create mode 100644 schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor create mode 100644 schemas/edict-provider/package/v1/generated/primary/generated-artifact-profile.echo-dpo-registration.cbor create mode 100644 schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor create mode 100644 schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl create mode 100644 schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-ir.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor create mode 100644 schemas/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor create mode 100644 schemas/edict-provider/package/v1/provider-manifest.echo.json diff --git a/.gitattributes b/.gitattributes index 86883b05..8114b509 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,8 @@ AGENTS.md merge=union # Preserve exact checked provider corpus bytes across checkout configurations. schemas/edict-provider/generated/v1/** -text schemas/edict-provider/generated/v1/**/*.cbor binary + +# Preserve the exact digest-locked provider distribution across checkouts. +schemas/edict-provider/package/v1/** -text +schemas/edict-provider/package/v1/**/*.cbor binary +schemas/edict-provider/package/v1/**/*.wasm binary diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5da49394..ba5da273 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -177,6 +177,8 @@ jobs: . - name: cargo test (workspace sans warp-core) run: cargo test --workspace --exclude warp-core + - name: checked Edict provider package is current + run: cargo +1.90.0 run --locked -p echo-wesley-gen --bin echo-edict-provider-package -- --check - name: package publishable Edict canonical leaf run: cargo package -p echo-edict-canonical --locked diff --git a/CHANGELOG.md b/CHANGELOG.md index 840d5bef..8706cfca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,14 @@ provenance/review, component bounds, and an external expected provider pin all fail closed through structured errors. This is package-occurrence authentication only; Edict schema/component preflight and Echo runtime - installation remain separate authority crossings. + installation remain separate authority crossings. A dedicated publisher now + checks that all 22 generated members exactly reproduce the checked #652 + corpus before writing the two components and derived manifest as a + self-contained 25-file distribution. Its capability-oriented filesystem + boundary refuses invalid expected inventories before resolving the root, + bounds actual-tree enumeration and expected-byte reads, never opens an + unexpected regular file, and makes `--check` report sorted drift without + creating, deleting, or rewriting package material. - Echo now provides the exact `edict:target-provider/lowerer@1.0.0` Component Model implementation for the first checked provider closure. The pure lowerer accepts only explicit digest-bound Core, target-profile, diff --git a/crates/echo-wesley-gen/README.md b/crates/echo-wesley-gen/README.md index 11d73be2..75e4e263 100644 --- a/crates/echo-wesley-gen/README.md +++ b/crates/echo-wesley-gen/README.md @@ -127,6 +127,18 @@ Edict schema-registry construction and component contract preflight remain separate required crossings before guest execution, and Echo runtime admission remains later still. +`echo-edict-provider-package` is the explicit publication boundary for that +distribution. Before any filesystem action it proves that the package's 22 +`generated/` members are the exact checked #652 corpus, then writes the two +checked components and derived manifest through the same no-follow, +unexpected-entry-refusing filesystem boundary used by the artifact corpus. The +checked 25-file result lives under `schemas/edict-provider/package/v1/`. +`--check` reports sorted missing, changed, or unexpected package members and +never repairs or creates them. The shared boundary validates a strictly sorted, +unique expected inventory before resolving the root, caps that inventory at 256 +files and 64 MiB, caps an actual scan at 1,024 entries, and never opens or reads +an unexpected regular file. + The dedicated `echo-edict-provider-artifacts` binary is the explicit filesystem boundary. The caller-supplied `--out` path is resolved once under ambient filesystem authority; its final corpus-root entry is opened or created without @@ -166,6 +178,14 @@ cargo +1.90.0 run --locked -p echo-wesley-gen \ # Report checked-corpus drift without rewriting anything cargo +1.90.0 run --locked -p echo-wesley-gen \ --bin echo-edict-provider-artifacts -- --check + +# Publish the self-contained digest-locked provider package +cargo +1.90.0 run --locked -p echo-wesley-gen \ + --bin echo-edict-provider-package -- + +# Report package drift without rewriting anything +cargo +1.90.0 run --locked -p echo-wesley-gen \ + --bin echo-edict-provider-package -- --check ``` ## Notes diff --git a/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs b/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs index 1bfd0a80..4c1af810 100644 --- a/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs +++ b/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs @@ -3,27 +3,19 @@ #![allow(clippy::print_stdout, clippy::print_stderr)] //! Generates or checks Echo's deterministic Edict provider artifact corpus. -use anyhow::{anyhow, bail, Context, Result}; -use cap_fs_ext::{FollowSymlinks, OpenOptionsFollowExt, OpenOptionsMaybeDirExt}; -use cap_std::{ - ambient_authority, - fs::{Dir, File, OpenOptions}, -}; +use anyhow::{bail, Result}; use clap::Parser; use echo_wesley_gen::provider_artifacts::generate_provider_primary_artifacts_v1; use echo_wesley_gen::provider_contract_pack::admit_provider_contract_pack_v1; use echo_wesley_gen::provider_corpus::{ checked_provider_generator_source_bundle_v1, diff_provider_artifact_corpus_v1, - render_provider_artifact_corpus_v1, ProviderArtifactCorpusFileV1, + render_provider_artifact_corpus_v1, }; +use echo_wesley_gen::provider_corpus_fs::{read_actual_corpus, write_corpus}; use echo_wesley_gen::provider_generation::build_provider_generation_input_v1; use echo_wesley_gen::provider_provenance::generate_provider_generation_provenance_v1; use echo_wesley_gen::provider_review::generate_provider_generation_review_v1; -use std::collections::{BTreeMap, BTreeSet}; -use std::ffi::{OsStr, OsString}; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicU64, Ordering}; +use std::path::PathBuf; const SOURCE: &[u8] = include_bytes!("../../../../schemas/edict-provider/echo-provider-semantics-v1.json"); @@ -33,13 +25,6 @@ const CONTRACT_CDDL: &[u8] = include_bytes!("../../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = include_bytes!("../../../../schemas/edict-provider/contracts/v1/manifest.json"); -const NON_REGULAR_ENTRY_BYTES: &[u8] = b"echo.provider-artifact-corpus.non-regular/v1"; -const OVERSIZED_ENTRY_BYTES: &[u8] = b"echo.provider-artifact-corpus.oversized/v1"; -const MAX_ACTUAL_CORPUS_FILE_BYTES: usize = 32 * 1024 * 1024; -const MAX_ACTUAL_CORPUS_FILE_BYTES_U64: u64 = 32 * 1024 * 1024; -const MAX_TEMP_FILE_ATTEMPTS: usize = 1_024; - -static NEXT_TEMP_FILE: AtomicU64 = AtomicU64::new(0); #[derive(Parser)] #[command( @@ -93,534 +78,3 @@ fn main() -> Result<()> { ); Ok(()) } - -fn read_actual_corpus( - root: &Path, - expected: &[ProviderArtifactCorpusFileV1], -) -> Result> { - let Some(root_directory) = open_corpus_root(root, false)? else { - return Ok(Vec::new()); - }; - - read_actual_corpus_from_directory(&root_directory, expected) -} - -fn read_actual_corpus_from_directory( - root: &Dir, - expected: &[ProviderArtifactCorpusFileV1], -) -> Result> { - let expected_directories = expected_directories(expected); - let mut actual = Vec::new(); - read_actual_directory(root, "", &expected_directories, &mut actual)?; - Ok(actual) -} - -fn expected_directories(expected: &[ProviderArtifactCorpusFileV1]) -> BTreeSet { - let mut directories = BTreeSet::new(); - for file in expected { - let components = file.relative_path().split('/').collect::>(); - for end in 1..components.len() { - directories.insert(components[..end].join("/")); - } - } - directories -} - -fn read_actual_directory( - directory: &Dir, - relative_directory: &str, - expected_directories: &BTreeSet, - actual: &mut Vec, -) -> Result<()> { - let mut entries = directory - .entries() - .with_context(|| format!("failed to read corpus directory {relative_directory}"))? - .collect::>>() - .with_context(|| format!("failed to enumerate corpus directory {relative_directory}"))?; - entries.sort_by_key(cap_std::fs::DirEntry::file_name); - - for entry in entries { - let raw_file_name = entry.file_name(); - let diagnostic_path = Path::new(relative_directory).join(&raw_file_name); - let file_name = utf8_file_name(raw_file_name.clone(), &diagnostic_path)?; - let relative_path = if relative_directory.is_empty() { - file_name - } else { - format!("{relative_directory}/{file_name}") - }; - let file_type = entry - .file_type() - .with_context(|| format!("failed to inspect corpus entry {relative_path}"))?; - - if file_type.is_file() { - let file = open_file_nofollow(directory, &raw_file_name) - .with_context(|| format!("failed to open corpus file {relative_path}"))?; - let metadata = file - .metadata() - .with_context(|| format!("failed to inspect corpus file {relative_path}"))?; - if !metadata.is_file() { - actual.push(ProviderArtifactCorpusFileV1::new( - relative_path, - NON_REGULAR_ENTRY_BYTES, - )?); - } else if metadata.len() > MAX_ACTUAL_CORPUS_FILE_BYTES_U64 { - actual.push(ProviderArtifactCorpusFileV1::new( - relative_path, - OVERSIZED_ENTRY_BYTES, - )?); - } else { - let mut bytes = Vec::new(); - file.take(MAX_ACTUAL_CORPUS_FILE_BYTES_U64 + 1) - .read_to_end(&mut bytes) - .with_context(|| format!("failed to read corpus file {relative_path}"))?; - let exact_bytes = if bytes.len() > MAX_ACTUAL_CORPUS_FILE_BYTES { - OVERSIZED_ENTRY_BYTES - } else { - &bytes - }; - actual.push(ProviderArtifactCorpusFileV1::new( - relative_path, - exact_bytes, - )?); - } - } else if file_type.is_dir() && expected_directories.contains(&relative_path) { - let child = open_dir_nofollow(directory, &raw_file_name) - .with_context(|| format!("failed to open corpus directory {relative_path}"))?; - read_actual_directory(&child, &relative_path, expected_directories, actual)?; - } else { - actual.push(ProviderArtifactCorpusFileV1::new( - relative_path, - NON_REGULAR_ENTRY_BYTES, - )?); - } - } - Ok(()) -} - -fn utf8_file_name(file_name: OsString, path: &Path) -> Result { - file_name.into_string().map_err(|name| { - anyhow!( - "corpus entry name is not UTF-8 at {}: {}", - path.display(), - name.to_string_lossy() - ) - }) -} - -fn open_corpus_root(root: &Path, create: bool) -> Result> { - let absolute = std::path::absolute(root) - .with_context(|| format!("failed to resolve corpus root {}", root.display()))?; - let Some(name) = absolute.file_name() else { - return Dir::open_ambient_dir(&absolute, ambient_authority()) - .map(Some) - .with_context(|| format!("failed to open corpus root {}", absolute.display())); - }; - let parent_path = absolute.parent().ok_or_else(|| { - anyhow!( - "corpus root has no parent directory: {}", - absolute.display() - ) - })?; - - if create { - std::fs::create_dir_all(parent_path).with_context(|| { - format!( - "failed to create corpus root parent {}", - parent_path.display() - ) - })?; - } - let parent = match Dir::open_ambient_dir(parent_path, ambient_authority()) { - Ok(parent) => parent, - Err(error) if !create && error.kind() == std::io::ErrorKind::NotFound => return Ok(None), - Err(error) => { - return Err(error).with_context(|| { - format!( - "failed to open corpus root parent {}", - parent_path.display() - ) - }); - } - }; - - if create { - ensure_corpus_directory(&parent, name, &absolute).map(Some) - } else { - open_existing_corpus_directory(&parent, name, &absolute) - } -} - -fn open_existing_corpus_directory( - parent: &Dir, - name: &OsStr, - display_path: &Path, -) -> Result> { - match parent.symlink_metadata(name) { - Ok(metadata) if metadata.file_type().is_symlink() => { - bail!( - "refusing to traverse corpus directory symlink {}", - display_path.display() - ); - } - Ok(metadata) if !metadata.is_dir() => { - bail!( - "corpus directory path is not a directory: {}", - display_path.display() - ); - } - Ok(_) => open_dir_nofollow(parent, name) - .map(Some) - .with_context(|| format!("failed to open corpus directory {}", display_path.display())), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(None), - Err(error) => Err(error).with_context(|| { - format!( - "failed to inspect corpus directory {}", - display_path.display() - ) - }), - } -} - -fn ensure_corpus_directory(parent: &Dir, name: &OsStr, display_path: &Path) -> Result { - if let Some(directory) = open_existing_corpus_directory(parent, name, display_path)? { - return Ok(directory); - } - - match parent.create_dir(name) { - Ok(()) => {} - Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {} - Err(error) => { - return Err(error).with_context(|| { - format!( - "failed to create corpus directory {}", - display_path.display() - ) - }); - } - } - open_existing_corpus_directory(parent, name, display_path)?.ok_or_else(|| { - anyhow!( - "created corpus directory disappeared before it could be opened: {}", - display_path.display() - ) - }) -} - -fn open_dir_nofollow(parent: &Dir, name: &OsStr) -> std::io::Result { - let mut options = OpenOptions::new(); - options.read(true); - options.follow(FollowSymlinks::No); - options.maybe_dir(true); - let file = parent.open_with(name, &options)?; - if !file.metadata()?.is_dir() { - return Err(std::io::Error::new( - std::io::ErrorKind::NotADirectory, - "corpus path component is not a directory", - )); - } - Ok(Dir::from_std_file(file.into_std())) -} - -fn open_file_nofollow(parent: &Dir, name: &OsStr) -> std::io::Result { - let mut options = OpenOptions::new(); - options.read(true); - options.follow(FollowSymlinks::No); - parent.open_with(name, &options) -} - -fn write_corpus(root: &Path, files: &[ProviderArtifactCorpusFileV1]) -> Result<()> { - let root_directory = open_corpus_root(root, true)?.ok_or_else(|| { - anyhow!( - "created corpus root could not be opened: {}", - root.display() - ) - })?; - let actual = read_actual_corpus_from_directory(&root_directory, files)?; - let expected_paths = files - .iter() - .map(ProviderArtifactCorpusFileV1::relative_path) - .collect::>(); - if let Some(unexpected) = actual - .iter() - .find(|file| !expected_paths.contains(file.relative_path())) - { - bail!( - "refusing to generate over unexpected corpus entry {}", - unexpected.relative_path() - ); - } - - let directories = prepare_corpus_directories(&root_directory, root, files)?; - preflight_corpus_write(&directories, files)?; - for file in files { - let (parent, leaf) = corpus_file_parts(file.relative_path()); - let directory = directories.get(parent).ok_or_else(|| { - anyhow!( - "corpus file parent was not retained: {}", - file.relative_path() - ) - })?; - let path = root.join(file.relative_path()); - replace_corpus_file(directory, OsStr::new(leaf), file.bytes(), &path)?; - println!(" wrote {}", path.display()); - } - Ok(()) -} - -fn prepare_corpus_directories( - root: &Dir, - root_display: &Path, - files: &[ProviderArtifactCorpusFileV1], -) -> Result> { - let mut directories = BTreeMap::new(); - directories.insert( - String::new(), - root.try_clone() - .context("failed to retain the corpus root directory")?, - ); - - for relative_path in expected_directories(files) { - let (parent, name) = corpus_file_parts(&relative_path); - let parent_directory = directories - .get(parent) - .ok_or_else(|| anyhow!("corpus directory parent was not retained: {relative_path}"))?; - let directory = ensure_corpus_directory( - parent_directory, - OsStr::new(name), - &root_display.join(&relative_path), - )?; - directories.insert(relative_path, directory); - } - - Ok(directories) -} - -fn preflight_corpus_write( - directories: &BTreeMap, - files: &[ProviderArtifactCorpusFileV1], -) -> Result<()> { - for file in files { - let (parent, leaf) = corpus_file_parts(file.relative_path()); - let directory = directories.get(parent).ok_or_else(|| { - anyhow!( - "corpus file parent was not retained: {}", - file.relative_path() - ) - })?; - validate_existing_corpus_file( - directory, - OsStr::new(leaf), - Path::new(file.relative_path()), - )?; - } - Ok(()) -} - -fn corpus_file_parts(relative_path: &str) -> (&str, &str) { - relative_path - .rsplit_once('/') - .unwrap_or(("", relative_path)) -} - -fn validate_existing_corpus_file(parent: &Dir, leaf: &OsStr, display_path: &Path) -> Result<()> { - match parent.symlink_metadata(leaf) { - Ok(metadata) if metadata.file_type().is_symlink() => { - bail!( - "refusing to replace corpus symlink {}", - display_path.display() - ); - } - Ok(metadata) if !metadata.is_file() => { - bail!( - "refusing to replace non-file corpus entry {}", - display_path.display() - ); - } - Ok(_) => Ok(()), - Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(error) => Err(error) - .with_context(|| format!("failed to inspect corpus file {}", display_path.display())), - } -} - -fn replace_corpus_file( - parent: &Dir, - leaf: &OsStr, - bytes: &[u8], - display_path: &Path, -) -> Result<()> { - validate_existing_corpus_file(parent, leaf, display_path)?; - let display_parent = display_path.parent().ok_or_else(|| { - anyhow!( - "corpus file has no display parent: {}", - display_path.display() - ) - })?; - let (temporary_name, mut temporary_file) = create_temporary_file(parent, display_parent)?; - - let write_result = temporary_file - .write_all(bytes) - .with_context(|| { - format!( - "failed to write temporary corpus file {}", - display_parent.join(&temporary_name).display() - ) - }) - .and_then(|()| { - temporary_file.sync_all().with_context(|| { - format!( - "failed to sync temporary corpus file {}", - display_parent.join(&temporary_name).display() - ) - }) - }); - drop(temporary_file); - if let Err(error) = write_result { - remove_temporary_file(parent, &temporary_name); - return Err(error); - } - - validate_existing_corpus_file(parent, leaf, display_path)?; - if let Err(error) = replace_temporary_file(parent, &temporary_name, leaf, display_path) { - remove_temporary_file(parent, &temporary_name); - return Err(error); - } - Ok(()) -} - -fn create_temporary_file(parent: &Dir, display_parent: &Path) -> Result<(OsString, File)> { - for _ in 0..MAX_TEMP_FILE_ATTEMPTS { - let sequence = NEXT_TEMP_FILE.fetch_add(1, Ordering::Relaxed); - let name = OsString::from(format!( - ".echo-provider-artifact-{}-{sequence}.tmp", - std::process::id() - )); - let mut options = OpenOptions::new(); - options.write(true).create_new(true); - options.follow(FollowSymlinks::No); - match parent.open_with(&name, &options) { - Ok(file) => return Ok((name, file)), - Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {} - Err(error) => { - return Err(error).with_context(|| { - format!( - "failed to create temporary corpus file {}", - display_parent.join(&name).display() - ) - }); - } - } - } - bail!( - "failed to reserve a temporary corpus file in {} after {} attempts", - display_parent.display(), - MAX_TEMP_FILE_ATTEMPTS - ); -} - -fn replace_temporary_file( - parent: &Dir, - temporary_name: &OsStr, - destination_name: &OsStr, - destination_display: &Path, -) -> Result<()> { - replace_temporary_file_with( - temporary_name, - destination_name, - destination_display, - |from, to| parent.rename(from, parent, to), - ) -} - -fn replace_temporary_file_with( - temporary_name: &OsStr, - destination_name: &OsStr, - destination_display: &Path, - replace: impl FnOnce(&OsStr, &OsStr) -> std::io::Result<()>, -) -> Result<()> { - replace(temporary_name, destination_name).with_context(|| { - format!( - "failed to replace corpus file {} from {}", - destination_display.display(), - temporary_name.to_string_lossy() - ) - }) -} - -fn remove_temporary_file(parent: &Dir, name: &OsStr) { - drop(parent.remove_file(name)); -} - -#[cfg(test)] -mod tests { - use super::{ - open_dir_nofollow, replace_corpus_file, replace_temporary_file_with, NEXT_TEMP_FILE, - }; - use anyhow::Result; - use cap_std::{ambient_authority, fs::Dir}; - use std::ffi::OsStr; - use std::path::{Path, PathBuf}; - use std::sync::atomic::Ordering; - - fn test_directory(label: &str) -> PathBuf { - std::env::temp_dir().join(format!( - "echo-provider-{label}-{}-{}", - std::process::id(), - NEXT_TEMP_FILE.fetch_add(1, Ordering::Relaxed) - )) - } - - #[test] - fn failed_replacement_preserves_existing_destination() -> Result<()> { - let root = test_directory("replacement-test"); - std::fs::create_dir(&root)?; - let temporary = root.join("temporary"); - let destination = root.join("destination"); - std::fs::write(&temporary, b"replacement")?; - std::fs::write(&destination, b"admitted")?; - - let result = replace_temporary_file_with( - OsStr::new("temporary"), - OsStr::new("destination"), - &destination, - |_, _| Err(std::io::Error::other("injected replacement failure")), - ); - - assert!(result.is_err()); - assert_eq!(std::fs::read(&destination)?, b"admitted"); - assert_eq!(std::fs::read(&temporary)?, b"replacement"); - std::fs::remove_dir_all(root)?; - Ok(()) - } - - #[cfg(unix)] - #[test] - fn retained_parent_handle_prevents_symlink_redirection() -> Result<()> { - use std::os::unix::fs::symlink; - - let root = test_directory("parent-swap"); - let outside = test_directory("parent-swap-outside"); - let evidence = root.join("evidence"); - let parked = root.join("evidence-parked"); - std::fs::create_dir_all(&evidence)?; - std::fs::create_dir_all(&outside)?; - let root_directory = Dir::open_ambient_dir(&root, ambient_authority())?; - let evidence_directory = open_dir_nofollow(&root_directory, OsStr::new("evidence"))?; - - std::fs::rename(&evidence, &parked)?; - symlink(&outside, &evidence)?; - - replace_corpus_file( - &evidence_directory, - OsStr::new("artifact"), - b"canonical", - Path::new("evidence/artifact"), - )?; - - assert!(!outside.join("artifact").exists()); - assert_eq!(std::fs::read(parked.join("artifact"))?, b"canonical"); - std::fs::remove_dir_all(root)?; - std::fs::remove_dir_all(outside)?; - Ok(()) - } -} diff --git a/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs b/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs new file mode 100644 index 00000000..5a0dd864 --- /dev/null +++ b/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::print_stdout, clippy::print_stderr)] +//! Generates or checks Echo's deterministic digest-locked Edict provider package. + +use anyhow::{bail, Result}; +use clap::Parser; +use echo_wesley_gen::provider_artifacts::generate_provider_primary_artifacts_v1; +use echo_wesley_gen::provider_contract_pack::admit_provider_contract_pack_v1; +use echo_wesley_gen::provider_corpus::{ + checked_provider_artifact_corpus_v1, checked_provider_generator_source_bundle_v1, + diff_exact_corpus_files_v1, ProviderArtifactCorpusFileV1, +}; +use echo_wesley_gen::provider_corpus_fs::{read_actual_corpus, write_corpus}; +use echo_wesley_gen::provider_generation::build_provider_generation_input_v1; +use echo_wesley_gen::provider_package::{ + assemble_provider_package_v1, ProviderPackageComponentMaterialV1, ProviderPackageV1, +}; +use echo_wesley_gen::provider_provenance::generate_provider_generation_provenance_v1; +use echo_wesley_gen::provider_review::generate_provider_generation_review_v1; +use std::path::PathBuf; + +const SOURCE: &[u8] = + include_bytes!("../../../../schemas/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = + include_bytes!("../../../../schemas/edict-provider/generation-settings-v1.json"); +const CONTRACT_CDDL: &[u8] = + include_bytes!("../../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); +const CONTRACT_MANIFEST: &[u8] = + include_bytes!("../../../../schemas/edict-provider/contracts/v1/manifest.json"); +const LOWERER: &[u8] = include_bytes!( + "../../../../schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm" +); +const VERIFIER: &[u8] = include_bytes!( + "../../../../schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm" +); + +#[derive(Parser)] +#[command( + author, + version, + about = "Generates or checks Echo's deterministic digest-locked Edict provider package" +)] +struct Args { + /// Output directory for the checked provider package. + #[arg(long, default_value = "schemas/edict-provider/package/v1")] + out: PathBuf, + + /// Report package drift without creating, deleting, or rewriting files. + #[arg(long)] + check: bool, +} + +fn main() -> Result<()> { + let args = Args::parse(); + let contract_pack = admit_provider_contract_pack_v1(CONTRACT_CDDL, CONTRACT_MANIFEST)?; + let input = build_provider_generation_input_v1(SOURCE, &contract_pack, SETTINGS)?; + let primary = generate_provider_primary_artifacts_v1(&input, &contract_pack)?; + let generator = checked_provider_generator_source_bundle_v1()?.generator_material()?; + let provenance = generate_provider_generation_provenance_v1(&input, &primary, &generator)?; + let review = generate_provider_generation_review_v1(&input, &provenance)?; + let package = assemble_provider_package_v1( + &input, + &primary, + &generator, + &provenance, + &review, + vec![ + ProviderPackageComponentMaterialV1::new("lowerer.echo-dpo", LOWERER)?, + ProviderPackageComponentMaterialV1::new("verifier.echo-dpo", VERIFIER)?, + ], + )?; + + // The package crossing consumes the checked #652 publication. It must not + // silently publish a freshly rendered but unchecked generation occurrence. + verify_checked_generated_members(&package)?; + let files = corpus_files(&package)?; + + if args.check { + let actual = read_actual_corpus(&args.out, &files)?; + let drift = diff_exact_corpus_files_v1(&files, &actual)?; + if drift.is_empty() { + println!("Provider package is current in {}", args.out.display()); + return Ok(()); + } + + eprintln!("Provider package drift:"); + for entry in &drift { + eprintln!(" {}: {}", entry.kind().as_str(), entry.relative_path()); + } + bail!("provider package is not current"); + } + + write_corpus(&args.out, &files)?; + println!("Provider package generated in {}", args.out.display()); + Ok(()) +} + +fn verify_checked_generated_members(package: &ProviderPackageV1) -> Result<()> { + let checked = checked_provider_artifact_corpus_v1()?; + let packaged = package + .files() + .iter() + .filter(|file| file.relative_path().starts_with("generated/")) + .collect::>(); + + if packaged.len() != checked.files().len() { + bail!( + "provider package generated-member count {} does not match checked corpus count {}", + packaged.len(), + checked.files().len() + ); + } + + for (packaged_file, checked_file) in packaged.iter().zip(checked.files()) { + let expected_path = format!("generated/{}", checked_file.relative_path()); + if packaged_file.relative_path() != expected_path { + bail!( + "provider package generated member {} does not match checked path {}", + packaged_file.relative_path(), + expected_path + ); + } + if packaged_file.bytes() != checked_file.bytes() { + bail!( + "provider package generated member {} does not match the checked exact bytes", + packaged_file.relative_path() + ); + } + } + + Ok(()) +} + +fn corpus_files(package: &ProviderPackageV1) -> Result> { + let mut files = Vec::with_capacity(package.files().len()); + for file in package.files() { + files.push(ProviderArtifactCorpusFileV1::new( + file.relative_path(), + file.bytes(), + )?); + } + Ok(files) +} diff --git a/crates/echo-wesley-gen/src/lib.rs b/crates/echo-wesley-gen/src/lib.rs index 08966790..d2538d5a 100644 --- a/crates/echo-wesley-gen/src/lib.rs +++ b/crates/echo-wesley-gen/src/lib.rs @@ -36,6 +36,9 @@ pub mod provider_review; /// Exact generator source identity and checked provider artifact corpus. pub mod provider_corpus; +/// Capability-bounded check/write boundary for exact provider corpora. +pub mod provider_corpus_fs; + /// Deterministic digest-locked Echo Edict provider package. pub mod provider_package; diff --git a/crates/echo-wesley-gen/src/provider_corpus.rs b/crates/echo-wesley-gen/src/provider_corpus.rs index 2bb82234..4202a026 100644 --- a/crates/echo-wesley-gen/src/provider_corpus.rs +++ b/crates/echo-wesley-gen/src/provider_corpus.rs @@ -349,7 +349,7 @@ pub fn build_provider_generator_source_bundle_v1( /// contract. No filesystem or environment discovery is performed. pub fn checked_provider_generator_source_bundle_v1( ) -> Result { - let sources: [(&str, &[u8]); 16] = [ + let sources: [(&str, &[u8]); 17] = [ ("Cargo.lock", include_bytes!("../../../Cargo.lock")), ("Cargo.toml", include_bytes!("../../../Cargo.toml")), ( @@ -388,6 +388,10 @@ pub fn checked_provider_generator_source_bundle_v1( "crates/echo-wesley-gen/src/provider_corpus.rs", include_bytes!("provider_corpus.rs"), ), + ( + "crates/echo-wesley-gen/src/provider_corpus_fs.rs", + include_bytes!("provider_corpus_fs.rs"), + ), ( "crates/echo-wesley-gen/src/provider_generation.rs", include_bytes!("provider_generation.rs"), @@ -478,6 +482,158 @@ impl ProviderArtifactCorpusV1 { } } +/// Loads the exact checked 22-file #652 corpus from compile-time repository bytes. +/// +/// This is an explicit source boundary for later package assembly. It performs +/// no filesystem, registry, environment, process, clock, or network discovery. +/// +/// # Errors +/// +/// Returns a structured error if a checked logical path no longer satisfies the +/// bounded v1 corpus grammar. +pub fn checked_provider_artifact_corpus_v1( +) -> Result { + let checked: [(&str, &[u8]); EXPECTED_CORPUS_FILE_COUNT] = [ + ( + "evidence/provenance.provider-generation.json", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json" + ), + ), + ( + "evidence/review.provider-generation.json", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/evidence/review.provider-generation.json" + ), + ), + ( + "primary/authority-facts.echo-dpo.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor" + ), + ), + ( + "primary/authority-facts.echo-lawpack.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor" + ), + ), + ( + "primary/generated-artifact-profile.echo-dpo-registration.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/primary/generated-artifact-profile.echo-dpo-registration.cbor" + ), + ), + ( + "primary/lawpack.echo-dpo.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor" + ), + ), + ( + "primary/schema.echo-provider-artifacts.cddl", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl" + ), + ), + ( + "primary/target-profile.echo-dpo.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor" + ), + ), + ( + "resources/resource.conformance-corpus.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor" + ), + ), + ( + "resources/resource.lawpack-compatibility.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-compatibility.cbor" + ), + ), + ( + "resources/resource.lawpack-exports.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-exports.cbor" + ), + ), + ( + "resources/resource.lawpack-target-adapter.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-target-adapter.cbor" + ), + ), + ( + "resources/resource.lawpack-verifier.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-verifier.cbor" + ), + ), + ( + "resources/resource.target-bundle-profile.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-bundle-profile.cbor" + ), + ), + ( + "resources/resource.target-cost-algebra.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-cost-algebra.cbor" + ), + ), + ( + "resources/resource.target-footprint-algebra.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-footprint-algebra.cbor" + ), + ), + ( + "resources/resource.target-intrinsics.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-intrinsics.cbor" + ), + ), + ( + "resources/resource.target-ir.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-ir.cbor" + ), + ), + ( + "resources/resource.target-lowerer-contract.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-lowerer-contract.cbor" + ), + ), + ( + "resources/resource.target-obstruction-taxonomy.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-obstruction-taxonomy.cbor" + ), + ), + ( + "resources/resource.target-operation-profiles.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-operation-profiles.cbor" + ), + ), + ( + "resources/resource.target-verifier-contract.cbor", + include_bytes!( + "../../../schemas/edict-provider/generated/v1/resources/resource.target-verifier-contract.cbor" + ), + ), + ]; + let files = checked + .into_iter() + .map(|(path, bytes)| ProviderArtifactCorpusFileV1::new(path, bytes)) + .collect::, _>>()?; + Ok(ProviderArtifactCorpusV1 { files }) +} + /// Stable kinds of checked-corpus drift. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum ProviderArtifactCorpusDriftKind { @@ -620,7 +776,23 @@ pub fn diff_provider_artifact_corpus_v1( expected: &ProviderArtifactCorpusV1, actual: &[ProviderArtifactCorpusFileV1], ) -> Result, ProviderArtifactCorpusError> { - let expected_by_path = corpus_inventory(&expected.files, "expected-corpus")?; + diff_exact_corpus_files_v1(&expected.files, actual) +} + +/// Compares two exact file inventories without imposing a corpus-specific size. +/// +/// The returned drift is sorted first by `missing`, `changed`, `unexpected`, +/// and then lexicographically by relative path. This function is pure and does +/// not read, write, create, normalize, or delete filesystem entries. +/// +/// # Errors +/// +/// Returns a stable failure if either inventory repeats a relative path. +pub fn diff_exact_corpus_files_v1( + expected: &[ProviderArtifactCorpusFileV1], + actual: &[ProviderArtifactCorpusFileV1], +) -> Result, ProviderArtifactCorpusError> { + let expected_by_path = corpus_inventory(expected, "expected-corpus")?; let actual_by_path = corpus_inventory(actual, "actual-corpus")?; let mut drift = Vec::new(); diff --git a/crates/echo-wesley-gen/src/provider_corpus_fs.rs b/crates/echo-wesley-gen/src/provider_corpus_fs.rs new file mode 100644 index 00000000..d8b5e4f7 --- /dev/null +++ b/crates/echo-wesley-gen/src/provider_corpus_fs.rs @@ -0,0 +1,833 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +//! Safe exact-tree filesystem access for deterministic provider corpora. + +use crate::provider_corpus::ProviderArtifactCorpusFileV1; +use anyhow::{anyhow, bail, Context, Result}; +use cap_fs_ext::{FollowSymlinks, OpenOptionsFollowExt, OpenOptionsMaybeDirExt}; +use cap_std::{ + ambient_authority, + fs::{Dir, File, OpenOptions}, +}; +use std::collections::{BTreeMap, BTreeSet}; +use std::ffi::{OsStr, OsString}; +use std::io::{Read, Write}; +use std::path::Path; +use std::sync::atomic::{AtomicU64, Ordering}; + +const NON_REGULAR_ENTRY_BYTES: &[u8] = b"echo.provider-artifact-corpus.non-regular/v1"; +const UNEXPECTED_ENTRY_BYTES: &[u8] = b"echo.provider-artifact-corpus.unexpected/v1"; +const CHANGED_ENTRY_BYTES: &[u8] = b"echo.provider-artifact-corpus.changed/v1"; +const ALTERNATE_CHANGED_ENTRY_BYTES: &[u8] = b"echo.provider-artifact-corpus.changed-alt/v1"; +const MAX_ACTUAL_CORPUS_FILE_BYTES: usize = 32 * 1024 * 1024; +const MAX_ACTUAL_CORPUS_FILE_BYTES_U64: u64 = 32 * 1024 * 1024; +const MAX_EXPECTED_CORPUS_FILE_COUNT: usize = 256; +const MAX_EXPECTED_CORPUS_TOTAL_BYTES: usize = 64 * 1024 * 1024; +const MAX_ACTUAL_CORPUS_ENTRY_COUNT: usize = 1_024; +const MAX_ACTUAL_CORPUS_READ_BYTES: usize = + MAX_EXPECTED_CORPUS_TOTAL_BYTES + MAX_EXPECTED_CORPUS_FILE_COUNT; +const MAX_TEMP_FILE_ATTEMPTS: usize = 1_024; + +static NEXT_TEMP_FILE: AtomicU64 = AtomicU64::new(0); + +/// Reads the exact corpus tree without following symbolic links. +pub fn read_actual_corpus( + root: &Path, + expected: &[ProviderArtifactCorpusFileV1], +) -> Result> { + let expected_by_path = validate_expected_corpus(expected)?; + let Some(root_directory) = open_corpus_root(root, false)? else { + return Ok(Vec::new()); + }; + + read_actual_corpus_from_directory(&root_directory, expected, &expected_by_path) +} + +fn read_actual_corpus_from_directory<'a>( + root: &Dir, + expected: &'a [ProviderArtifactCorpusFileV1], + expected_by_path: &BTreeMap<&'a str, &'a [u8]>, +) -> Result> { + let expected_directories = expected_directories(expected); + let mut actual = Vec::new(); + let mut budget = ActualCorpusReadBudget::default(); + read_actual_directory( + root, + "", + &expected_directories, + expected_by_path, + &mut budget, + &mut actual, + )?; + Ok(actual) +} + +fn validate_expected_corpus( + expected: &[ProviderArtifactCorpusFileV1], +) -> Result> { + if expected.is_empty() { + bail!("expected corpus inventory must not be empty"); + } + if expected.len() > MAX_EXPECTED_CORPUS_FILE_COUNT { + bail!("expected corpus inventory exceeds file limit {MAX_EXPECTED_CORPUS_FILE_COUNT}"); + } + + let mut total_bytes = 0usize; + let mut inventory = BTreeMap::new(); + let mut previous_path: Option<&str> = None; + for file in expected { + if let Some(previous) = previous_path { + if previous.as_bytes() >= file.relative_path().as_bytes() { + bail!( + "expected corpus paths must be strictly sorted: {previous} then {}", + file.relative_path() + ); + } + } + if file.bytes().len() > MAX_ACTUAL_CORPUS_FILE_BYTES { + bail!( + "expected corpus file {} exceeds byte limit {MAX_ACTUAL_CORPUS_FILE_BYTES}", + file.relative_path() + ); + } + total_bytes = total_bytes + .checked_add(file.bytes().len()) + .ok_or_else(|| anyhow!("expected corpus total byte length overflow"))?; + if total_bytes > MAX_EXPECTED_CORPUS_TOTAL_BYTES { + bail!("expected corpus exceeds total byte limit {MAX_EXPECTED_CORPUS_TOTAL_BYTES}"); + } + inventory.insert(file.relative_path(), file.bytes()); + previous_path = Some(file.relative_path()); + } + for file in expected { + for (separator, _) in file.relative_path().match_indices('/') { + let ancestor = &file.relative_path()[..separator]; + if inventory.contains_key(ancestor) { + bail!("expected corpus path is both file and directory: {ancestor}"); + } + } + } + let directory_count = expected_directories(expected).len(); + let expected_entry_count = expected + .len() + .checked_add(directory_count) + .ok_or_else(|| anyhow!("expected corpus entry count overflow"))?; + if expected_entry_count > MAX_ACTUAL_CORPUS_ENTRY_COUNT { + bail!("expected corpus tree exceeds entry limit {MAX_ACTUAL_CORPUS_ENTRY_COUNT}"); + } + Ok(inventory) +} + +#[derive(Default)] +struct ActualCorpusReadBudget { + entries: usize, + read_bytes: usize, +} + +impl ActualCorpusReadBudget { + fn observe_entry(&mut self) -> Result<()> { + self.entries = self + .entries + .checked_add(1) + .ok_or_else(|| anyhow!("actual corpus entry count overflow"))?; + if self.entries > MAX_ACTUAL_CORPUS_ENTRY_COUNT { + bail!("actual corpus exceeds entry limit {MAX_ACTUAL_CORPUS_ENTRY_COUNT}"); + } + Ok(()) + } + + fn reserve_read(&mut self, bytes: usize) -> Result<()> { + self.read_bytes = self + .read_bytes + .checked_add(bytes) + .ok_or_else(|| anyhow!("actual corpus read byte count overflow"))?; + if self.read_bytes > MAX_ACTUAL_CORPUS_READ_BYTES { + bail!("actual corpus exceeds read limit {MAX_ACTUAL_CORPUS_READ_BYTES}"); + } + Ok(()) + } +} + +fn expected_directories(expected: &[ProviderArtifactCorpusFileV1]) -> BTreeSet { + let mut directories = BTreeSet::new(); + for file in expected { + let components = file.relative_path().split('/').collect::>(); + for end in 1..components.len() { + directories.insert(components[..end].join("/")); + } + } + directories +} + +fn read_actual_directory( + directory: &Dir, + relative_directory: &str, + expected_directories: &BTreeSet, + expected_by_path: &BTreeMap<&str, &[u8]>, + budget: &mut ActualCorpusReadBudget, + actual: &mut Vec, +) -> Result<()> { + let mut entries = Vec::new(); + for entry in directory + .entries() + .with_context(|| format!("failed to read corpus directory {relative_directory}"))? + { + budget.observe_entry()?; + entries.push(entry.with_context(|| { + format!("failed to enumerate corpus directory {relative_directory}") + })?); + } + entries.sort_by_key(cap_std::fs::DirEntry::file_name); + + for entry in entries { + let raw_file_name = entry.file_name(); + let diagnostic_path = Path::new(relative_directory).join(&raw_file_name); + let file_name = utf8_file_name(raw_file_name.clone(), &diagnostic_path)?; + let relative_path = if relative_directory.is_empty() { + file_name + } else { + format!("{relative_directory}/{file_name}") + }; + let file_type = entry + .file_type() + .with_context(|| format!("failed to inspect corpus entry {relative_path}"))?; + + if file_type.is_file() { + let Some(expected_bytes) = expected_by_path.get(relative_path.as_str()).copied() else { + actual.push(ProviderArtifactCorpusFileV1::new( + relative_path, + UNEXPECTED_ENTRY_BYTES, + )?); + continue; + }; + let file = open_file_nofollow(directory, &raw_file_name) + .with_context(|| format!("failed to open corpus file {relative_path}"))?; + let metadata = file + .metadata() + .with_context(|| format!("failed to inspect corpus file {relative_path}"))?; + if !metadata.is_file() + || metadata.len() > MAX_ACTUAL_CORPUS_FILE_BYTES_U64 + || metadata.len() != expected_bytes.len() as u64 + { + actual.push(ProviderArtifactCorpusFileV1::new( + relative_path, + changed_entry_bytes(expected_bytes), + )?); + } else { + let read_limit = expected_bytes.len().checked_add(1).ok_or_else(|| { + anyhow!("actual corpus read limit overflow for {relative_path}") + })?; + budget.reserve_read(read_limit)?; + let mut bytes = Vec::new(); + file.take(read_limit as u64) + .read_to_end(&mut bytes) + .with_context(|| format!("failed to read corpus file {relative_path}"))?; + let exact_bytes = if bytes.len() == expected_bytes.len() { + &bytes + } else { + changed_entry_bytes(expected_bytes) + }; + actual.push(ProviderArtifactCorpusFileV1::new( + relative_path, + exact_bytes, + )?); + } + } else if file_type.is_dir() && expected_directories.contains(&relative_path) { + let child = open_dir_nofollow(directory, &raw_file_name) + .with_context(|| format!("failed to open corpus directory {relative_path}"))?; + read_actual_directory( + &child, + &relative_path, + expected_directories, + expected_by_path, + budget, + actual, + )?; + } else { + let marker = expected_by_path + .get(relative_path.as_str()) + .map_or(NON_REGULAR_ENTRY_BYTES, |expected| { + changed_entry_bytes(expected) + }); + actual.push(ProviderArtifactCorpusFileV1::new(relative_path, marker)?); + } + } + Ok(()) +} + +fn changed_entry_bytes(expected: &[u8]) -> &'static [u8] { + if expected == CHANGED_ENTRY_BYTES { + ALTERNATE_CHANGED_ENTRY_BYTES + } else { + CHANGED_ENTRY_BYTES + } +} + +fn utf8_file_name(file_name: OsString, path: &Path) -> Result { + file_name.into_string().map_err(|name| { + anyhow!( + "corpus entry name is not UTF-8 at {}: {}", + path.display(), + name.to_string_lossy() + ) + }) +} + +fn open_corpus_root(root: &Path, create: bool) -> Result> { + let absolute = std::path::absolute(root) + .with_context(|| format!("failed to resolve corpus root {}", root.display()))?; + let Some(name) = absolute.file_name() else { + return Dir::open_ambient_dir(&absolute, ambient_authority()) + .map(Some) + .with_context(|| format!("failed to open corpus root {}", absolute.display())); + }; + let parent_path = absolute.parent().ok_or_else(|| { + anyhow!( + "corpus root has no parent directory: {}", + absolute.display() + ) + })?; + + if create { + std::fs::create_dir_all(parent_path).with_context(|| { + format!( + "failed to create corpus root parent {}", + parent_path.display() + ) + })?; + } + let parent = match Dir::open_ambient_dir(parent_path, ambient_authority()) { + Ok(parent) => parent, + Err(error) if !create && error.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(error) => { + return Err(error).with_context(|| { + format!( + "failed to open corpus root parent {}", + parent_path.display() + ) + }); + } + }; + + if create { + ensure_corpus_directory(&parent, name, &absolute).map(Some) + } else { + open_existing_corpus_directory(&parent, name, &absolute) + } +} + +fn open_existing_corpus_directory( + parent: &Dir, + name: &OsStr, + display_path: &Path, +) -> Result> { + match parent.symlink_metadata(name) { + Ok(metadata) if metadata.file_type().is_symlink() => { + bail!( + "refusing to traverse corpus directory symlink {}", + display_path.display() + ); + } + Ok(metadata) if !metadata.is_dir() => { + bail!( + "corpus directory path is not a directory: {}", + display_path.display() + ); + } + Ok(_) => open_dir_nofollow(parent, name) + .map(Some) + .with_context(|| format!("failed to open corpus directory {}", display_path.display())), + Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(None), + Err(error) => Err(error).with_context(|| { + format!( + "failed to inspect corpus directory {}", + display_path.display() + ) + }), + } +} + +fn ensure_corpus_directory(parent: &Dir, name: &OsStr, display_path: &Path) -> Result { + if let Some(directory) = open_existing_corpus_directory(parent, name, display_path)? { + return Ok(directory); + } + + match parent.create_dir(name) { + Ok(()) => {} + Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {} + Err(error) => { + return Err(error).with_context(|| { + format!( + "failed to create corpus directory {}", + display_path.display() + ) + }); + } + } + open_existing_corpus_directory(parent, name, display_path)?.ok_or_else(|| { + anyhow!( + "created corpus directory disappeared before it could be opened: {}", + display_path.display() + ) + }) +} + +fn open_dir_nofollow(parent: &Dir, name: &OsStr) -> std::io::Result { + let mut options = OpenOptions::new(); + options.read(true); + options.follow(FollowSymlinks::No); + options.maybe_dir(true); + let file = parent.open_with(name, &options)?; + if !file.metadata()?.is_dir() { + return Err(std::io::Error::new( + std::io::ErrorKind::NotADirectory, + "corpus path component is not a directory", + )); + } + Ok(Dir::from_std_file(file.into_std())) +} + +fn open_file_nofollow(parent: &Dir, name: &OsStr) -> std::io::Result { + let mut options = OpenOptions::new(); + options.read(true); + options.follow(FollowSymlinks::No); + parent.open_with(name, &options) +} + +/// Writes an exact corpus tree after refusing unsafe or unexpected entries. +#[allow(clippy::print_stdout)] +pub fn write_corpus(root: &Path, files: &[ProviderArtifactCorpusFileV1]) -> Result<()> { + let expected_by_path = validate_expected_corpus(files)?; + let root_directory = open_corpus_root(root, true)?.ok_or_else(|| { + anyhow!( + "created corpus root could not be opened: {}", + root.display() + ) + })?; + let actual = read_actual_corpus_from_directory(&root_directory, files, &expected_by_path)?; + if let Some(unexpected) = actual + .iter() + .find(|file| !expected_by_path.contains_key(file.relative_path())) + { + bail!( + "refusing to generate over unexpected corpus entry {}", + unexpected.relative_path() + ); + } + + let directories = prepare_corpus_directories(&root_directory, root, files)?; + preflight_corpus_write(&directories, files)?; + for file in files { + let (parent, leaf) = corpus_file_parts(file.relative_path()); + let directory = directories.get(parent).ok_or_else(|| { + anyhow!( + "corpus file parent was not retained: {}", + file.relative_path() + ) + })?; + let path = root.join(file.relative_path()); + replace_corpus_file(directory, OsStr::new(leaf), file.bytes(), &path)?; + println!(" wrote {}", path.display()); + } + Ok(()) +} + +fn prepare_corpus_directories( + root: &Dir, + root_display: &Path, + files: &[ProviderArtifactCorpusFileV1], +) -> Result> { + let mut directories = BTreeMap::new(); + directories.insert( + String::new(), + root.try_clone() + .context("failed to retain the corpus root directory")?, + ); + + for relative_path in expected_directories(files) { + let (parent, name) = corpus_file_parts(&relative_path); + let parent_directory = directories + .get(parent) + .ok_or_else(|| anyhow!("corpus directory parent was not retained: {relative_path}"))?; + let directory = ensure_corpus_directory( + parent_directory, + OsStr::new(name), + &root_display.join(&relative_path), + )?; + directories.insert(relative_path, directory); + } + + Ok(directories) +} + +fn preflight_corpus_write( + directories: &BTreeMap, + files: &[ProviderArtifactCorpusFileV1], +) -> Result<()> { + for file in files { + let (parent, leaf) = corpus_file_parts(file.relative_path()); + let directory = directories.get(parent).ok_or_else(|| { + anyhow!( + "corpus file parent was not retained: {}", + file.relative_path() + ) + })?; + validate_existing_corpus_file( + directory, + OsStr::new(leaf), + Path::new(file.relative_path()), + )?; + } + Ok(()) +} + +fn corpus_file_parts(relative_path: &str) -> (&str, &str) { + relative_path + .rsplit_once('/') + .unwrap_or(("", relative_path)) +} + +fn validate_existing_corpus_file(parent: &Dir, leaf: &OsStr, display_path: &Path) -> Result<()> { + match parent.symlink_metadata(leaf) { + Ok(metadata) if metadata.file_type().is_symlink() => { + bail!( + "refusing to replace corpus symlink {}", + display_path.display() + ); + } + Ok(metadata) if !metadata.is_file() => { + bail!( + "refusing to replace non-file corpus entry {}", + display_path.display() + ); + } + Ok(_) => Ok(()), + Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(error) => Err(error) + .with_context(|| format!("failed to inspect corpus file {}", display_path.display())), + } +} + +fn replace_corpus_file( + parent: &Dir, + leaf: &OsStr, + bytes: &[u8], + display_path: &Path, +) -> Result<()> { + validate_existing_corpus_file(parent, leaf, display_path)?; + let display_parent = display_path.parent().ok_or_else(|| { + anyhow!( + "corpus file has no display parent: {}", + display_path.display() + ) + })?; + let (temporary_name, mut temporary_file) = create_temporary_file(parent, display_parent)?; + + let write_result = temporary_file + .write_all(bytes) + .with_context(|| { + format!( + "failed to write temporary corpus file {}", + display_parent.join(&temporary_name).display() + ) + }) + .and_then(|()| { + temporary_file.sync_all().with_context(|| { + format!( + "failed to sync temporary corpus file {}", + display_parent.join(&temporary_name).display() + ) + }) + }); + drop(temporary_file); + if let Err(error) = write_result { + remove_temporary_file(parent, &temporary_name); + return Err(error); + } + + validate_existing_corpus_file(parent, leaf, display_path)?; + if let Err(error) = replace_temporary_file(parent, &temporary_name, leaf, display_path) { + remove_temporary_file(parent, &temporary_name); + return Err(error); + } + Ok(()) +} + +fn create_temporary_file(parent: &Dir, display_parent: &Path) -> Result<(OsString, File)> { + for _ in 0..MAX_TEMP_FILE_ATTEMPTS { + let sequence = NEXT_TEMP_FILE.fetch_add(1, Ordering::Relaxed); + let name = OsString::from(format!( + ".echo-provider-artifact-{}-{sequence}.tmp", + std::process::id() + )); + let mut options = OpenOptions::new(); + options.write(true).create_new(true); + options.follow(FollowSymlinks::No); + match parent.open_with(&name, &options) { + Ok(file) => return Ok((name, file)), + Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {} + Err(error) => { + return Err(error).with_context(|| { + format!( + "failed to create temporary corpus file {}", + display_parent.join(&name).display() + ) + }); + } + } + } + bail!( + "failed to reserve a temporary corpus file in {} after {} attempts", + display_parent.display(), + MAX_TEMP_FILE_ATTEMPTS + ); +} + +fn replace_temporary_file( + parent: &Dir, + temporary_name: &OsStr, + destination_name: &OsStr, + destination_display: &Path, +) -> Result<()> { + replace_temporary_file_with( + temporary_name, + destination_name, + destination_display, + |from, to| parent.rename(from, parent, to), + ) +} + +fn replace_temporary_file_with( + temporary_name: &OsStr, + destination_name: &OsStr, + destination_display: &Path, + replace: impl FnOnce(&OsStr, &OsStr) -> std::io::Result<()>, +) -> Result<()> { + replace(temporary_name, destination_name).with_context(|| { + format!( + "failed to replace corpus file {} from {}", + destination_display.display(), + temporary_name.to_string_lossy() + ) + }) +} + +fn remove_temporary_file(parent: &Dir, name: &OsStr) { + drop(parent.remove_file(name)); +} + +#[cfg(test)] +mod tests { + use super::{ + open_dir_nofollow, read_actual_corpus, replace_corpus_file, replace_temporary_file_with, + write_corpus, NEXT_TEMP_FILE, + }; + use crate::provider_corpus::ProviderArtifactCorpusFileV1; + use anyhow::Result; + use cap_std::{ambient_authority, fs::Dir}; + use std::ffi::OsStr; + use std::path::{Path, PathBuf}; + use std::sync::atomic::Ordering; + + fn test_directory(label: &str) -> PathBuf { + let path = std::env::temp_dir().join(format!( + "echo-provider-{label}-{}-{}", + std::process::id(), + NEXT_TEMP_FILE.fetch_add(1, Ordering::Relaxed) + )); + drop(std::fs::remove_dir_all(&path)); + path + } + + #[test] + fn failed_replacement_preserves_existing_destination() -> Result<()> { + let root = test_directory("replacement-test"); + std::fs::create_dir(&root)?; + let temporary = root.join("temporary"); + let destination = root.join("destination"); + std::fs::write(&temporary, b"replacement")?; + std::fs::write(&destination, b"admitted")?; + + let result = replace_temporary_file_with( + OsStr::new("temporary"), + OsStr::new("destination"), + &destination, + |_, _| Err(std::io::Error::other("injected replacement failure")), + ); + + assert!(result.is_err()); + assert_eq!(std::fs::read(&destination)?, b"admitted"); + assert_eq!(std::fs::read(&temporary)?, b"replacement"); + std::fs::remove_dir_all(root)?; + Ok(()) + } + + #[test] + fn invalid_expected_inventories_refuse_before_root_creation() -> Result<()> { + let duplicate_root = test_directory("duplicate-inventory"); + let duplicate = vec![ + ProviderArtifactCorpusFileV1::new("same", b"first")?, + ProviderArtifactCorpusFileV1::new("same", b"second")?, + ]; + let Err(duplicate_error) = write_corpus(&duplicate_root, &duplicate) else { + anyhow::bail!("duplicate expected paths did not fail closed"); + }; + assert!(duplicate_error.to_string().contains("strictly sorted")); + assert!(!duplicate_root.exists()); + + let unordered_root = test_directory("unordered-inventory"); + let unordered = vec![ + ProviderArtifactCorpusFileV1::new("z", b"last")?, + ProviderArtifactCorpusFileV1::new("a", b"first")?, + ]; + let Err(unordered_error) = write_corpus(&unordered_root, &unordered) else { + anyhow::bail!("unordered expected paths did not fail closed"); + }; + assert!(unordered_error.to_string().contains("strictly sorted")); + assert!(!unordered_root.exists()); + + let empty_root = test_directory("empty-inventory"); + let Err(empty_error) = write_corpus(&empty_root, &[]) else { + anyhow::bail!("an empty expected inventory did not fail closed"); + }; + assert!(empty_error.to_string().contains("must not be empty")); + assert!(!empty_root.exists()); + + let prefix_root = test_directory("prefix-inventory"); + let prefix_conflict = vec![ + ProviderArtifactCorpusFileV1::new("artifact", b"file")?, + ProviderArtifactCorpusFileV1::new("artifact/child", b"child")?, + ]; + let Err(prefix_error) = write_corpus(&prefix_root, &prefix_conflict) else { + anyhow::bail!("a file/directory prefix conflict did not fail closed"); + }; + assert!(prefix_error.to_string().contains("both file and directory")); + assert!(!prefix_root.exists()); + + let interposed_prefix_root = test_directory("interposed-prefix-inventory"); + let interposed_prefix_conflict = vec![ + ProviderArtifactCorpusFileV1::new("artifact", b"file")?, + ProviderArtifactCorpusFileV1::new("artifact.", b"interposed")?, + ProviderArtifactCorpusFileV1::new("artifact/child", b"child")?, + ]; + let Err(interposed_prefix_error) = + write_corpus(&interposed_prefix_root, &interposed_prefix_conflict) + else { + anyhow::bail!("an interposed file/directory conflict did not fail closed"); + }; + assert!(interposed_prefix_error + .to_string() + .contains("both file and directory")); + assert!(!interposed_prefix_root.exists()); + + let overfull_root = test_directory("overfull-inventory"); + let overfull = (0..257) + .map(|index| ProviderArtifactCorpusFileV1::new(format!("entry-{index:04}"), &[])) + .collect::, _>>()?; + let Err(overfull_error) = write_corpus(&overfull_root, &overfull) else { + anyhow::bail!("an excessive expected inventory did not fail closed"); + }; + assert!(overfull_error.to_string().contains("file limit 256")); + assert!(!overfull_root.exists()); + + let deep_root = test_directory("deep-inventory"); + let deep = (0..5) + .map(|branch| { + let path = std::iter::once(format!("b{branch}")) + .chain(std::iter::repeat_n("s".to_owned(), 210)) + .chain(std::iter::once("file".to_owned())) + .collect::>() + .join("/"); + ProviderArtifactCorpusFileV1::new(path, &[]) + }) + .collect::, _>>()?; + let Err(deep_error) = write_corpus(&deep_root, &deep) else { + anyhow::bail!("an excessive expected directory tree did not fail closed"); + }; + assert!(deep_error + .to_string() + .contains("tree exceeds entry limit 1024")); + assert!(!deep_root.exists()); + Ok(()) + } + + #[test] + fn actual_tree_scan_is_bounded_and_does_not_read_unexpected_files() -> Result<()> { + const ADVERSARIAL_ENTRY_COUNT: usize = 1_025; + const UNEXPECTED_MARKER: &[u8] = b"echo.provider-artifact-corpus.unexpected/v1"; + + let unexpected_root = test_directory("unexpected-content"); + std::fs::create_dir(&unexpected_root)?; + std::fs::write( + unexpected_root.join("operator-owned"), + b"operator-secret-bytes", + )?; + let expected = vec![ProviderArtifactCorpusFileV1::new("expected", b"expected")?]; + let actual = read_actual_corpus(&unexpected_root, &expected)?; + assert_eq!(actual.len(), 1); + assert_eq!(actual[0].relative_path(), "operator-owned"); + assert_eq!(actual[0].bytes(), UNEXPECTED_MARKER); + assert_eq!( + std::fs::read(unexpected_root.join("operator-owned"))?, + b"operator-secret-bytes" + ); + std::fs::remove_dir_all(unexpected_root)?; + + let marker_root = test_directory("marker-collision"); + std::fs::create_dir_all(marker_root.join("expected"))?; + let marker_expected = vec![ProviderArtifactCorpusFileV1::new( + "expected", + super::NON_REGULAR_ENTRY_BYTES, + )?]; + let marker_actual = read_actual_corpus(&marker_root, &marker_expected)?; + assert_ne!(marker_actual[0].bytes(), marker_expected[0].bytes()); + std::fs::remove_dir_all(marker_root)?; + + let crowded_root = test_directory("entry-budget"); + std::fs::create_dir(&crowded_root)?; + for index in 0..ADVERSARIAL_ENTRY_COUNT { + std::fs::write(crowded_root.join(format!("unexpected-{index:04}")), [])?; + } + let Err(error) = read_actual_corpus(&crowded_root, &expected) else { + anyhow::bail!("an excessive actual inventory did not fail closed"); + }; + assert!(error.to_string().contains("entry limit 1024")); + assert_eq!( + std::fs::read_dir(&crowded_root)?.count(), + ADVERSARIAL_ENTRY_COUNT + ); + std::fs::remove_dir_all(crowded_root)?; + Ok(()) + } + + #[cfg(unix)] + #[test] + fn retained_parent_handle_prevents_symlink_redirection() -> Result<()> { + use std::os::unix::fs::symlink; + + let root = test_directory("parent-swap"); + let outside = test_directory("parent-swap-outside"); + let evidence = root.join("evidence"); + let parked = root.join("evidence-parked"); + std::fs::create_dir_all(&evidence)?; + std::fs::create_dir_all(&outside)?; + let root_directory = Dir::open_ambient_dir(&root, ambient_authority())?; + let evidence_directory = open_dir_nofollow(&root_directory, OsStr::new("evidence"))?; + + std::fs::rename(&evidence, &parked)?; + symlink(&outside, &evidence)?; + + replace_corpus_file( + &evidence_directory, + OsStr::new("artifact"), + b"canonical", + Path::new("evidence/artifact"), + )?; + + assert!(!outside.join("artifact").exists()); + assert_eq!(std::fs::read(parked.join("artifact"))?, b"canonical"); + std::fs::remove_dir_all(root)?; + std::fs::remove_dir_all(outside)?; + Ok(()) + } +} diff --git a/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs b/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs index c18ce001..95cbe824 100644 --- a/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs +++ b/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs @@ -38,7 +38,7 @@ const CONTRACT_CDDL: &[u8] = const CONTRACT_MANIFEST: &[u8] = include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); -const GENERATOR_SOURCE_PATHS: [&str; 16] = [ +const GENERATOR_SOURCE_PATHS: [&str; 17] = [ "Cargo.lock", "Cargo.toml", "crates/echo-edict-canonical/Cargo.toml", @@ -50,6 +50,7 @@ const GENERATOR_SOURCE_PATHS: [&str; 16] = [ "crates/echo-wesley-gen/src/provider_canonical.rs", "crates/echo-wesley-gen/src/provider_contract_pack.rs", "crates/echo-wesley-gen/src/provider_corpus.rs", + "crates/echo-wesley-gen/src/provider_corpus_fs.rs", "crates/echo-wesley-gen/src/provider_generation.rs", "crates/echo-wesley-gen/src/provider_provenance.rs", "crates/echo-wesley-gen/src/provider_review.rs", diff --git a/crates/echo-wesley-gen/tests/provider_package.rs b/crates/echo-wesley-gen/tests/provider_package.rs index 4c6be31e..61b0bc65 100644 --- a/crates/echo-wesley-gen/tests/provider_package.rs +++ b/crates/echo-wesley-gen/tests/provider_package.rs @@ -9,7 +9,9 @@ use echo_wesley_gen::provider_artifacts::{ use echo_wesley_gen::provider_contract_pack::{ admit_provider_contract_pack_v1, AdmittedProviderContractPackV1, }; -use echo_wesley_gen::provider_corpus::checked_provider_generator_source_bundle_v1; +use echo_wesley_gen::provider_corpus::{ + checked_provider_artifact_corpus_v1, checked_provider_generator_source_bundle_v1, +}; use echo_wesley_gen::provider_generation::{ build_provider_generation_input_v1, ProviderGenerationInputV1, }; @@ -182,6 +184,23 @@ fn checked_materials_assemble_one_digest_locked_provider_package() { assert_eq!(admitted.manifest(), package.manifest()); } +#[test] +fn package_generated_members_are_the_exact_checked_652_corpus() { + let package = assemble(false); + let checked = checked_provider_artifact_corpus_v1() + .expect("checked #652 provider artifact corpus is an exact bounded value"); + assert_eq!(checked.files().len(), 22); + for checked_file in checked.files() { + let package_path = format!("generated/{}", checked_file.relative_path()); + let packaged = package + .files() + .iter() + .find(|file| file.relative_path() == package_path) + .expect("every checked #652 file is a package member"); + assert_eq!(packaged.bytes(), checked_file.bytes()); + } +} + #[test] fn manifest_routes_preserve_semantic_and_exact_byte_digest_classes() { let (input, primary, generator, provenance, review) = generate(); diff --git a/crates/echo-wesley-gen/tests/provider_package_corpus.rs b/crates/echo-wesley-gen/tests/provider_package_corpus.rs new file mode 100644 index 00000000..d1423082 --- /dev/null +++ b/crates/echo-wesley-gen/tests/provider_package_corpus.rs @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::expect_used, clippy::panic)] +//! Checked filesystem publication for Echo's digest-locked Edict provider package. + +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; +use std::sync::atomic::{AtomicU64, Ordering}; + +use sha2::{Digest as _, Sha256}; + +const EXPECTED_PROVIDER_DIGEST: &str = + "sha256:cf0147bea65cdfa7d426dc11a0eeab8f3ac889bfb3daa14f3d6b05ccd80f2d6e"; +const EXPECTED_MANIFEST_RAW_SHA256: &str = + "2ddc03d00a9ce9e3c29d74064e90458ede1aa08a0845bbe984d555710967c29b"; + +const PACKAGE_PATHS: [&str; 25] = [ + "components/lowerer.echo-dpo.component.wasm", + "components/verifier.echo-dpo.component.wasm", + "generated/evidence/provenance.provider-generation.json", + "generated/evidence/review.provider-generation.json", + "generated/primary/authority-facts.echo-dpo.cbor", + "generated/primary/authority-facts.echo-lawpack.cbor", + "generated/primary/generated-artifact-profile.echo-dpo-registration.cbor", + "generated/primary/lawpack.echo-dpo.cbor", + "generated/primary/schema.echo-provider-artifacts.cddl", + "generated/primary/target-profile.echo-dpo.cbor", + "generated/resources/resource.conformance-corpus.cbor", + "generated/resources/resource.lawpack-compatibility.cbor", + "generated/resources/resource.lawpack-exports.cbor", + "generated/resources/resource.lawpack-target-adapter.cbor", + "generated/resources/resource.lawpack-verifier.cbor", + "generated/resources/resource.target-bundle-profile.cbor", + "generated/resources/resource.target-cost-algebra.cbor", + "generated/resources/resource.target-footprint-algebra.cbor", + "generated/resources/resource.target-intrinsics.cbor", + "generated/resources/resource.target-ir.cbor", + "generated/resources/resource.target-lowerer-contract.cbor", + "generated/resources/resource.target-obstruction-taxonomy.cbor", + "generated/resources/resource.target-operation-profiles.cbor", + "generated/resources/resource.target-verifier-contract.cbor", + "provider-manifest.echo.json", +]; + +static NEXT_TEMP_DIRECTORY: AtomicU64 = AtomicU64::new(0); + +struct TestDirectory(PathBuf); + +impl TestDirectory { + fn new(label: &str) -> Self { + let sequence = NEXT_TEMP_DIRECTORY.fetch_add(1, Ordering::Relaxed); + let path = std::env::temp_dir().join(format!( + "echo-provider-package-{label}-{}-{sequence}", + std::process::id() + )); + if path.exists() { + std::fs::remove_dir_all(&path).expect("stale test directory is removable"); + } + std::fs::create_dir_all(&path).expect("test directory is created"); + Self(path) + } + + fn path(&self) -> &Path { + &self.0 + } +} + +impl Drop for TestDirectory { + fn drop(&mut self) { + drop(std::fs::remove_dir_all(&self.0)); + } +} + +fn run_package(root: &Path, check: bool) -> Output { + let mut command = Command::new(env!("CARGO_BIN_EXE_echo-edict-provider-package")); + if check { + command.arg("--check"); + } + command + .arg("--out") + .arg(root) + .output() + .expect("provider package command executes") +} + +fn snapshot(root: &Path) -> BTreeMap> { + let mut files = BTreeMap::new(); + collect_files(root, root, &mut files); + files +} + +fn collect_files(root: &Path, directory: &Path, files: &mut BTreeMap>) { + let mut entries = std::fs::read_dir(directory) + .expect("package directory is readable") + .collect::, _>>() + .expect("package directory entries are readable"); + entries.sort_by_key(std::fs::DirEntry::file_name); + + for entry in entries { + let file_type = entry.file_type().expect("package entry type is readable"); + if file_type.is_dir() { + collect_files(root, &entry.path(), files); + continue; + } + if !file_type.is_file() { + continue; + } + + let relative = entry + .path() + .strip_prefix(root) + .expect("package entry is below the corpus root") + .components() + .map(|component| { + component + .as_os_str() + .to_str() + .expect("package paths are UTF-8") + }) + .collect::>() + .join("/"); + files.insert( + relative, + std::fs::read(entry.path()).expect("package file is readable"), + ); + } +} + +fn expected_paths() -> Vec { + PACKAGE_PATHS + .iter() + .map(|path| (*path).to_owned()) + .collect() +} + +#[test] +fn generation_writes_the_exact_package_and_check_mode_is_read_only() { + let directory = TestDirectory::new("write-check"); + let generated = run_package(directory.path(), false); + assert!( + generated.status.success(), + "provider package generation failed:\n{}", + String::from_utf8_lossy(&generated.stderr) + ); + + let before = snapshot(directory.path()); + assert_eq!(before.keys().cloned().collect::>(), expected_paths()); + let manifest_bytes = before + .get("provider-manifest.echo.json") + .expect("provider manifest is present"); + let manifest: serde_json::Value = + serde_json::from_slice(manifest_bytes).expect("provider manifest is JSON"); + assert_eq!( + manifest["provider"]["digest"].as_str(), + Some(EXPECTED_PROVIDER_DIGEST) + ); + assert_eq!( + hex::encode(Sha256::digest(manifest_bytes)), + EXPECTED_MANIFEST_RAW_SHA256 + ); + + let checked = run_package(directory.path(), true); + assert!( + checked.status.success(), + "provider package check failed:\n{}", + String::from_utf8_lossy(&checked.stderr) + ); + assert!(String::from_utf8_lossy(&checked.stdout).contains("is current")); + assert_eq!(snapshot(directory.path()), before); +} + +#[test] +fn check_mode_reports_drift_without_rewriting_or_creating_members() { + let directory = TestDirectory::new("no-write-check"); + let generated = run_package(directory.path(), false); + assert!( + generated.status.success(), + "provider package generation failed:\n{}", + String::from_utf8_lossy(&generated.stderr) + ); + + let changed_path = directory.path().join("provider-manifest.echo.json"); + let missing_path = directory + .path() + .join("components/lowerer.echo-dpo.component.wasm"); + let unexpected_path = directory.path().join("operator-owned.txt"); + std::fs::write(&changed_path, b"tampered manifest") + .expect("changed package manifest is written"); + std::fs::remove_file(&missing_path).expect("lowerer package member is removed"); + std::fs::write(&unexpected_path, b"operator bytes") + .expect("unexpected operator file is written"); + + let checked = run_package(directory.path(), true); + assert!(!checked.status.success()); + let stderr = String::from_utf8(checked.stderr).expect("checker diagnostics are UTF-8"); + assert!(stderr.contains("missing: components/lowerer.echo-dpo.component.wasm")); + assert!(stderr.contains("changed: provider-manifest.echo.json")); + assert!(stderr.contains("unexpected: operator-owned.txt")); + assert_eq!( + std::fs::read(&changed_path).expect("tampered manifest remains readable"), + b"tampered manifest" + ); + assert!(!missing_path.exists()); + assert_eq!( + std::fs::read(&unexpected_path).expect("operator file remains readable"), + b"operator bytes" + ); +} + +#[test] +fn generation_refuses_unexpected_entries_before_writing_package_members() { + let directory = TestDirectory::new("unexpected-entry"); + let unexpected_path = directory.path().join("operator-owned.txt"); + std::fs::write(&unexpected_path, b"operator bytes") + .expect("unexpected operator file is written"); + + let generated = run_package(directory.path(), false); + assert!(!generated.status.success()); + assert!(String::from_utf8_lossy(&generated.stderr) + .contains("refusing to generate over unexpected corpus entry operator-owned.txt")); + assert_eq!( + std::fs::read(&unexpected_path).expect("operator file remains readable"), + b"operator bytes" + ); + assert!(!directory.path().join("components").exists()); + assert!(!directory.path().join("generated").exists()); + assert!(!directory + .path() + .join("provider-manifest.echo.json") + .exists()); +} + +#[test] +fn checked_provider_package_matches_the_current_renderer() { + let package_root = + Path::new(env!("CARGO_MANIFEST_DIR")).join("../../schemas/edict-provider/package/v1"); + let checked = run_package(&package_root, true); + + assert!( + checked.status.success(), + "checked provider package drifted:\n{}", + String::from_utf8_lossy(&checked.stderr) + ); + assert!(String::from_utf8_lossy(&checked.stdout).contains("is current")); +} diff --git a/det-policy.yaml b/det-policy.yaml index fd4135b8..ad32875a 100644 --- a/det-policy.yaml +++ b/det-policy.yaml @@ -43,6 +43,10 @@ crates: class: DET_CRITICAL owner_role: "Tooling Engineer" paths: ["crates/echo-edict-canonical/**"] + echo-edict-provider-artifacts: + class: DET_CRITICAL + owner_role: "Tooling Engineer" + paths: ["crates/echo-wesley-gen/src/provider_*.rs", "crates/echo-wesley-gen/src/bin/echo-edict-provider-*.rs", "crates/echo-wesley-gen/tests/provider_*.rs", "schemas/edict-provider/**"] echo-edict-provider-lowerer: class: DET_CRITICAL owner_role: "Tooling Engineer" diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index 6df97d34..e22fb942 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -199,6 +199,14 @@ That boundary still proves only the distribution occurrence: the Edict-owned schema registry and component host must separately admit roots, bytes, attestations, imports, exports, and WIT types before guest execution. +The checked distribution is a self-contained 25-file publication: the exact +22-file #652 corpus under `generated/`, the exact lowerer and verifier under +`components/`, and the derived manifest. Publication refuses before filesystem +access if the generated members are not byte-identical to the checked source +corpus. Its check mode inventories the exact tree through retained no-follow +directory capabilities and reports drift without repair. This distribution +copy is a release occurrence, not a second semantic authority. + The target-profile lowerer and verifier resources are generated declarative contract documents. They do not select executable implementations. The package manifest separately binds the exact provider-owned components and their frozen diff --git a/schemas/edict-provider/README.md b/schemas/edict-provider/README.md index 7eca4b4d..ddaae11c 100644 --- a/schemas/edict-provider/README.md +++ b/schemas/edict-provider/README.md @@ -199,5 +199,12 @@ packaged provenance/review and requires an external expected provider reference. This is package-occurrence evidence, not Edict component or schema compatibility proof and not Echo runtime installation or authority. +The exact 25-file distribution is checked under +[`package/v1/`](package/README.md). Its dedicated publisher first requires its +22 `generated/` members to equal the checked #652 corpus byte-for-byte, then +writes only the two exact components, those generated members, and the derived +manifest. Run `echo-edict-provider-package --check` to report drift without +creating, deleting, or rewriting package files. + All generated files are derived artifacts. Their digests and review renderings must never be copied back into this file as authored semantic facts. diff --git a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json index 6e2d5405..90602d7f 100644 --- a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:22c293f0b0809335cdfb307ed5912f2a7e9d0a5ae140a63e46cd2d4619cbd1a7","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json index 5c296669..e341b270 100644 --- a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:22c293f0b0809335cdfb307ed5912f2a7e9d0a5ae140a63e46cd2d4619cbd1a7","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:14503aa28ab96c07c93cec00d98b87ff0109c7ad45431c3baf259d502bae4ae1","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:f61cfc7e1d32b1fb75188cc23ca25df852ed50059d3858d716ce136908ea7eae","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/README.md b/schemas/edict-provider/package/README.md new file mode 100644 index 00000000..f58e7325 --- /dev/null +++ b/schemas/edict-provider/package/README.md @@ -0,0 +1,36 @@ + + + +# Checked Echo Edict Provider Package + +[`v1/`](v1/) is the first exact digest-locked Echo Edict provider +distribution. Its inventory is fixed at 25 files: + +- the exact lowerer and verifier component bytes under `components/`; +- the checked 22-file #652 artifact corpus under `generated/`; and +- the derived `provider-manifest.echo.json`. + +The manifest never inventories itself. Its `provider.digest` names an +Echo-owned, domain-framed canonical-CBOR closure over the manifest contract, +routes, schema bindings, and raw identities of all 24 non-manifest members. +The manifest file has a separate raw content identity. + +Regenerate the package only from the repository root: + +```bash +cargo +1.90.0 run --locked -p echo-wesley-gen \ + --bin echo-edict-provider-package -- +``` + +Check the exact tree without repairing or rewriting it: + +```bash +cargo +1.90.0 run --locked -p echo-wesley-gen \ + --bin echo-edict-provider-package -- --check +``` + +The publisher fails before filesystem access unless every packaged +`generated/` member is byte-identical to the checked #652 corpus. The checked +package proves a reproducible distribution occurrence. It does not by itself +prove Edict schema admission, component-host readiness, Echo installation, +runtime authority, invocation, execution, commitment, observation, or receipt. diff --git a/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a85ae30a7ae2c25c4fa087952b53072333f352c5 GIT binary patch literal 130679 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�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 Ha2ozU)-Q8F literal 0 HcmV?d00001 diff --git a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json new file mode 100644 index 00000000..90602d7f --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -0,0 +1 @@ +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json new file mode 100644 index 00000000..e341b270 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -0,0 +1 @@ +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:f61cfc7e1d32b1fb75188cc23ca25df852ed50059d3858d716ce136908ea7eae","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor new file mode 100644 index 00000000..807c2186 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor @@ -0,0 +1 @@ +fsourcedkindmtargetProfilefdigestfsha256X VbZe/T~U2-jcoordinatejecho.dpo@1gbudgetsjapiVersionxedict.authority-facts/v1qoperationProfileskp.effectfuldcorexcontinuum.profile.write/v1sallowedWriteClassesgreplacereffectWriteClassesntarget.replacegreplace \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor new file mode 100644 index 0000000000000000000000000000000000000000..a3a7b68102a0f23667ec264b602f15548bc255a0 GIT binary patch literal 243 zcmXYpJxc^J5I|QDyv|lTTZ>ycL2dmgt`QW3^K67Mne5JOOmdlt-nI%>{slof#9p+p zwf6^D3fkED4-9Dccs$;{VV|PHscy*W%EEa7)fi0`vRoLhVRdbNxYRG2&(~-A**KcJ z9?XArK88=rZ#TQg{r89OtC!2ik@7xjav&H{)xOlhcmHRbz3L?C3We`XD1}@*txsWc zAQ-sgGVLV^Nw!--UYse$*=$+sRetF|Ia`b%&;TQocasIwq@;u-wT~oi*MJgUIqQvm azzC9?{pbx@o1`pIZQQO;Tn~W=SR3B?=fWK~aOnImgys_m?`cOROqe;Jw^r;psww3q4J< zDw>z7h4e%@Z%WK7Ni0fFEpbdqEGPlGs&R38B7_OHPZ`5LsH`4HLKhfcSgiDQV%v8A zx7Y4qX_u#yUB7-@lcB0=CoJ76mtyd4vjR#=<6nf!?k?w|kn5oYBMX8QSnT@%S zI7" (EDICT-DIGEST-WIRE-001). +sha256-digest = [ algorithm: "sha256", bytes: bstr .size 32 ] + +; A named low-level failure an effect can raise. The source obstruction map +; binds it (by coordinate) and constructs a typed domain obstruction from its +; payload (EDICT-ABI-FAILURE-NAMED-001). +; An effect's `effectFailures` list MUST have unique `coordinate`s: since the +; obstruction map is keyed by coordinate, two failures sharing a coordinate (even +; with different authorityClass/payloadType) make exhaustive mapping and binder +; typing ambiguous and are rejected (EDICT-ABI-FAILURE-UNIQUE-001). +; +; Effects carry their failures as a map `{ failure-ident => effect-failure-body }` +; (see the target/lawpack effect schemas). The failure coordinate is the map +; KEY, so it is not repeated in the body and cannot disagree with the key. +effect-failure-body = { + authorityClass: authority-class, + payloadType: core-type-ref, ; typed, bounded (may be empty record) +} + +; A failure coordinate must be a bare Edict `ident` (letter/underscore then +; letters/digits/underscores) AND must not be a reserved keyword (e.g. `else`, +; `basis`, `where`, `require`, `for`, `if`). The source obstruction-map LHS only +; accepts a non-keyword `ident`, so a hyphen/dot/keyword coordinate would be +; ABI-valid yet impossible to map exhaustively in source. The regex captures the +; lexical shape; keyword exclusion is an additional validation rule +; (EDICT-ABI-FAILURE-IDENT-001). +failure-ident = tstr .regexp "[A-Za-z_][A-Za-z0-9_]*" + +effect-kind = "read" / "create" / "ensure" / "replace" / "delete" / + "append" / "reduce" / "semantic.emit" / "custom" + +authority-class = "domainMappable" / "participantOwned" / "integrityFault" / + "resourceFault" / "internalFault" + +core-type-ref = tstr ; canonical Core type coordinate + +; An operation profile supplies the optic template a Core intent resolves its +; opticKind/boundaryKind/supportPolicy/lossDisposition from. Target profiles and +; lawpacks publish these as a map `{ coordinate => operation-profile }`, so the +; coordinate is the KEY, not a value field (EDICT-OPTIC-TEMPLATE-OWNER-001, +; EDICT-ABI-OPPROFILE-UNIQUE-001). +operation-profile = { + opticTemplate: optic-template, + effectPredicate: tstr, ; coordinate of the operation-mode predicate +} + +optic-template = { + opticKind: "revelation" / "affectReintegration", + boundaryKind: "projection" / "affect", + supportPolicy: tstr, ; canonical support-policy coordinate + lossDisposition: tstr, ; canonical loss-disposition coordinate + ? basisTemplate: tstr, ; optional digest-locked basis template coord + ; the aperture requirement this template supplies. Required when the template + ; is the source of a Core optic's apertureRequirement (i.e. the intent has no + ; source `footprint <= ...`), since apertureRequirement is mandatory in Core + ; (EDICT-OPTIC-APERTURE-REF-001). + ? apertureRequirement: aperture-requirement, +} + +; apertureRequirement is a typed reference, never a free-form string. A review +; rendering may show its coordinate (EDICT-OPTIC-APERTURE-REF-001). +aperture-requirement = footprint-ceiling-ref / abstract-footprint-obligation-ref +footprint-ceiling-ref = { kind: "footprintCeiling", ref: tstr } +abstract-footprint-obligation-ref = { kind: "abstractFootprintObligation", ref: tstr } + +; --- edict-core.cddl --- +; edict-core.cddl +; Normative schema for the Edict Core v1 semantic model. +; +; Scope boundary: this file defines Core meaning and schema shape only. It does +; not define a canonical encoder, Core module hash fields, hash fixtures, target +; lowering, admission bundles, or target-owned IR. + +core-module = { + apiVersion: "edict.core/v1", + coordinate: tstr, + imports: [* core-import], + types: { * tstr => core-type }, + intents: { + tstr => core-intent }, + requiredCoreCapabilities: [* tstr], +} + +core-import = { + kind: "lawpack" / "target" / "core", + ref: resource-ref, + ? alias: tstr, +} + +; --- types --------------------------------------------------------------- + +core-type = core-scalar-type / core-record-type / core-variant-type / + core-option-type / core-list-type / core-map-type / + core-capability-ref-type + +core-scalar-type = core-bool-type / core-int-type / core-string-type / + core-bytes-type / core-unit-type + +core-bool-type = { kind: "Bool" } +core-unit-type = { kind: "Unit" } +core-int-type = { + kind: "I64" / "U64" / "I32" / "U32" / "I16" / "U16" / "I8" / "U8", +} +core-string-type = { + kind: "String", + max: uint, + canonical: "unicode-scalar-nfc" / "raw-utf8", +} +core-bytes-type = { + kind: "Bytes", + max: uint, +} +core-record-type = { + kind: "Record", + fields: { * tstr => core-type-ref }, +} +core-variant-type = { + kind: "Variant", + cases: { + tstr => variant-case-body }, +} +variant-case-body = { + ? payload: core-type-ref, +} +core-option-type = { + kind: "Option", + item: core-type-ref, +} +core-list-type = { + kind: "List", + item: core-type-ref, + max: uint, +} +core-map-type = { + kind: "Map", + key: core-type-ref, + value: core-type-ref, + max: uint, +} +core-capability-ref-type = { + kind: "CapabilityRef", + item: core-type-ref, +} + +; core-type-ref is defined in edict-common.cddl and assembled with this schema. + +; --- references and values ---------------------------------------------- + +; Local identity is alpha-stable. `id` is the compiler-owned local coordinate; +; `alphaName` is the normalized human/debug name. Source binder spelling is not +; identity. +local-ref = { + id: tstr, + alphaName: tstr, + type: core-type-ref, +} + +core-value = core-null-value / core-bool-value / core-int-value / + core-string-value / core-bytes-value / core-record-value / + core-variant-value / core-list-value / core-map-value / + core-capability-value + +core-null-value = { kind: "null" } +core-bool-value = { kind: "bool", value: bool } +core-int-value = { kind: "int", width: tstr, value: int } +core-string-value = { kind: "string", value: tstr } +core-bytes-value = { kind: "bytes", value: bstr } +core-record-value = { kind: "record", fields: { * tstr => core-value } } +core-variant-value = { + kind: "variant", + type: core-type-ref, + case: tstr, + ? payload: core-value, +} +core-list-value = { kind: "list", values: [* core-value] } +core-map-value = { kind: "map", entries: [* [key: core-value, value: core-value]] } +core-capability-value = { + kind: "capability", + receipt: sha256-digest, +} + +; Edict-authored pure helpers use a pure Core function body. The body can bind +; pure expressions and return an expression, but it cannot contain Core effect, +; guard, branch, loop, match-node, or proof-obligation nodes. +core-fn-body = { + params: [* local-ref], + body: core-pure-block, +} + +core-pure-block = { + locals: [* local-ref], + bindings: [* pure-let-node], + result: core-expr, +} + +pure-let-node = { + kind: "let", + binding: local-ref, + value: core-expr, +} + +; --- expressions and predicates ----------------------------------------- + +core-expr = local-expr / const-expr / record-expr / field-expr / + variant-expr / match-expr / call-expr / list-expr / map-expr / + if-expr + +local-expr = { kind: "local", ref: local-ref } +const-expr = { kind: "const", value: core-value } +record-expr = { kind: "record", fields: { * tstr => core-expr } } +field-expr = { kind: "field", base: core-expr, field: tstr } +variant-expr = { + kind: "variant", + type: core-type-ref, + case: tstr, + ? payload: core-expr, +} +match-expr = { + kind: "match", + scrutinee: core-expr, + arms: [+ match-arm], +} +match-arm = { + case: tstr, + ? binder: local-ref, + body: core-expr, +} +call-expr = { + kind: "call", + callee: tstr, + typeArgs: [* core-type-ref], + args: [* core-expr], +} +list-expr = { kind: "list", values: [* core-expr] } +map-expr = { kind: "map", entries: [* [key: core-expr, value: core-expr]] } +if-expr = { + kind: "if", + predicate: core-predicate, + then: core-expr, + else: core-expr, +} + +core-predicate = true-predicate / false-predicate / not-predicate / + all-predicate / any-predicate / compare-predicate / + call-predicate / obstruction-predicate + +true-predicate = { kind: "true" } +false-predicate = { kind: "false" } +not-predicate = { kind: "not", value: core-predicate } +all-predicate = { kind: "all", values: [+ core-predicate] } +any-predicate = { kind: "any", values: [+ core-predicate] } +compare-predicate = { + kind: "compare", + op: "==" / "!=" / "<" / "<=" / ">" / ">=", + left: core-expr, + right: core-expr, +} +call-predicate = { + kind: "call", + predicate: tstr, + args: [* core-expr], +} +obstruction-predicate = { + kind: "obstruction", + coordinate: failure-ident, + payload: core-expr, +} + +input-constraint = { + coordinate: tstr, + source: "where" / "compiler", + predicate: core-predicate, +} + +; --- intents, blocks, and nodes ----------------------------------------- + +core-intent = { + input: core-type-ref, + output: core-type-ref, + requiredOperationProfile: tstr, + inputConstraints: [* input-constraint], + coreEvaluationBudget: core-budget, + body: core-block, + ? optic: core-optic, +} + +core-budget = { + maxSteps: uint, + maxAllocatedBytes: uint, + maxOutputBytes: uint, +} + +core-optic = { + opticKind: "revelation" / "affectReintegration", + boundaryKind: "projection" / "affect", + apertureRequirement: aperture-requirement, + supportPolicy: tstr, + lossDisposition: tstr, +} + +core-block = { + locals: [* local-ref], + nodes: [* core-node], + result: core-expr, +} + +core-node = let-node / require-node / effect-node / guard-node / branch-node / + for-node / match-node / proof-obligation-node + +let-node = { + kind: "let", + binding: local-ref, + value: core-expr, +} +require-node = { + kind: "require", + predicate: core-predicate, + onFailure: require-failure-arm, +} +require-failure-arm = terminal-require-failure / + continue-obstructed-require-failure +terminal-require-failure = { + kind: "terminal", + reason: obstruction-reason, +} +continue-obstructed-require-failure = { + kind: "continueObstructed", + reason: obstruction-reason, +} +obstruction-reason = { + reasonKind: tstr, + payload: { * tstr => core-expr }, +} +effect-node = { + kind: "effect", + binding: local-ref, + effect: tstr, + input: core-expr, + obstructionMap: { * failure-ident => obstruction-arm }, +} +obstruction-arm = { + binder: local-ref, + value: core-expr, +} +guard-node = { + kind: "guard", + predicate: core-predicate, + obstruction: core-expr, +} +branch-node = { + kind: "branch", + predicate: core-predicate, + then: core-block, + else: core-block, +} +for-node = { + kind: "for", + binder: local-ref, + iter: core-expr, + bound: core-bound, + body: core-block, +} +match-node = { + kind: "match", + scrutinee: core-expr, + arms: [+ match-block-arm], +} +match-block-arm = { + case: tstr, + ? binder: local-ref, + body: core-block, +} +proof-obligation-node = { + kind: "proof", + coordinate: tstr, + predicate: core-predicate, +} + +core-bound = literal-bound / coordinate-bound +literal-bound = { kind: "literal", value: uint } +coordinate-bound = { kind: "coordinate", ref: tstr } + +; Shared resource-ref, sha256-digest, failure-ident, aperture-requirement, and +; core-type-ref are defined once in edict-common.cddl. + +; --- edict-lawpack.cddl --- +; edict-lawpack.cddl +; Canonical schema for the Edict lawpack manifest and export surface. +; Authoritative byte encoding: edict.canonical-cbor/v1. JSON in the prose specs +; is a review rendering generated from this schema (EDICT-ABI-NODUP-001). + +lawpack-manifest = { + apiVersion: "edict.lawpack/v1", + id: tstr, + version: tstr, + acceptedCoreAbi: [+ tstr], + dependencies: [* lawpack-dep], ; acyclic, digest-locked (EDICT-LAWPACK-DAG-001) + exports: resource-ref, + ? targetAdapters: [+ target-adapter], ; required only if any runtime effect exists + ? helperComponent: executable-component, ; executable helpers carry their own sandbox+fuel + verifier: verifier, ; classified: declarative or executable + compatibility: resource-ref, + conformanceFixtureCorpus: resource-ref, +} + +; A verifier is either a declarative ruleset (no runtime) or an executable +; component. An executable verifier MUST carry its own sandbox and fuel model, +; so the schema enforces that no executable component is left unbounded +; (EDICT-ABI-VERIFIER-BOUND-001). +verifier = declarative-verifier / executable-verifier +declarative-verifier = { class: "declarative", ruleset: resource-ref } +executable-verifier = { + class: "executable", + component: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, +} + +; Any executable component is bounded by its own sandbox + fuel model. +executable-component = { + component: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, +} + +lawpack-dep = { id: tstr, version: tstr, digest: sha256-digest } + +; Adapter selection keys SOLELY off the digest-locked `acceptedTargetProfile` +; (its `id` is the profile id; its `digest` pins the exact profile/version). There +; are no independent display strings that could disagree with the lock, so a +; resolver cannot bind an adapter to one target while the lock proves another +; (EDICT-LAWPACK-ADAPTER-TARGETIR-001). +target-adapter = { + acceptedTargetProfile: resource-ref, ; digest-locked, authoritative selector + acceptedTargetIr: resource-ref, ; digest-locked + adapter: resource-ref, +} + +; Shared types resource-ref and sha256-digest are defined once in +; edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- export surface ------------------------------------------------------ + +lawpack-exports = { + types: [* exported-type], + constants: [* exported-constant], + pureFunctions: [* pure-function], + effects: [* semantic-effect], + obstructions: [* obstruction-def], + ; keyed by operation-profile coordinate → uniqueness enforced + ; (EDICT-ABI-OPPROFILE-UNIQUE-001) + ; operation-profile records this lawpack exports (optic templates that + ; `implements`/`profile` clauses resolve against). operation-profile is + ; defined in edict-common.cddl (EDICT-ABI-OPPROFILE-SLOT-001). + operationProfiles: { * tstr => operation-profile }, ; keyed by coordinate +} + +exported-type = { coordinate: tstr, definition: core-type-ref } +exported-constant = { coordinate: tstr, type: core-type-ref, value: any } + +; A pure helper is a discriminated union by `source`, so the schema itself +; guarantees an implementation exists (EDICT-LAWPACK-PURE-IMPL-001): +; - "edict": authored in Edict/Core; the Core body is carried inline (hashed +; with the export surface). The schema requires the `body` field. +; - "component": implemented outside Edict; carries no inline body and instead +; carries its own digest-locked `implementation` (sandbox + fuel). It does +; not depend on the optional manifest-level helperComponent. +pure-function = edict-pure-function / component-pure-function + +pure-function-common = ( + coordinate: tstr, + typeParameters: [* tstr], + parameterTypes: [* core-type-ref], ; all bounded + returnType: core-type-ref, ; bounded + costTemplate: tstr, + determinismClass: "total" / "total-with-typed-diagnostic", +) + +edict-pure-function = { + pure-function-common, + source: "edict", + body: core-fn-body, ; inline, hash-significant +} + +component-pure-function = { + pure-function-common, + source: "component", + ; the digest-locked component implementing this helper. Required at the schema + ; level so a component helper can never validate without a hash-bound, + ; sandbox+fuel-described implementation (EDICT-LAWPACK-PURE-IMPL-001). + implementation: executable-component, +} + +; core-fn-body is defined by edict-core.cddl and assembled with this lawpack +; schema. It is a pure Core function body, not an effect-capable core-block. + +semantic-effect = { + coordinate: tstr, + typeParameters: [* tstr], + inputType: core-type-ref, ; bounded + outputType: core-type-ref, ; bounded + executionClass: "proofOnly" / "runtime", ; orthogonal to writeClass + effectKindHint: effect-kind, + footprintObligation: tstr, + costObligation: tstr, + effectFailures: { * failure-ident => effect-failure-body }, ; keyed by coordinate; unique + guardSupport: bool, +} + +obstruction-def = { + coordinate: tstr, + authorityClass: authority-class, + payloadSchema: core-type-ref, ; typed, bounded (may be empty record) +} + +; effect-failure-body, effect-kind, authority-class, and core-type-ref are defined +; once in edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- edict-target-profile.cddl --- +; edict-target-profile.cddl +; Canonical schema for the Edict target profile manifest. +; Authoritative byte encoding: edict.canonical-cbor/v1 +; (see SPEC_continuum-contract-bundle-v1.md). JSON in the prose specs is a +; review rendering generated from this schema; this CDDL is the single source +; of truth (EDICT-ABI-NODUP-001). + +target-profile-manifest = { + apiVersion: "edict.target-profile/v1", + id: tstr, ; e.g. "echo.dpo" + version: tstr, ; e.g. "1" + acceptedCoreAbi: [+ tstr], ; e.g. ["edict.core/v1"] + + intrinsics: resource-ref, + intrinsicNamespace: tstr, + ; publishes this profile's operation-profile records (optic templates that + ; `profile`/`implements` clauses resolve against). References an + ; operation-profiles-document (EDICT-ABI-OPPROFILE-SLOT-001). + operationProfiles: resource-ref, + footprintAlgebra: resource-ref, + costAlgebra: resource-ref, + targetIr: resource-ref, + obstructionTaxonomy: resource-ref, + verifier: resource-ref, + lowerer: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, + + ; fields the language spec requires of every profile + bundleProfile: resource-ref, + generatedArtifactProfiles: [* resource-ref], + canonicalEncodingRules: resource-ref, + ; Reserved/deferred: will list accepted lawpack-adapter ABI ids once that + ; byte-level ABI (edict.lawpack-adapter/v1) is specified. The schema enforces + ; emptiness now — the type is the empty array, so non-empty values are + ; rejected, not merely discouraged (EDICT-ABI-LAWPACK-ADAPTER-DEFER-001). + ? acceptedLawpackAdapterAbi: [], + diagnosticAbi: resource-ref, + + ; application doctrine + applicationModel: "atomic", + readConsistency: "application-snapshot" / tstr, + guardEvaluation: "precommit-atomic" / tstr, + obstructionRollback: "no-visible-effects" / tstr, + multiTarget: bool, + ; whether the target can evaluate precommit postcondition (`guarantee`) checks + ; inside the atomic application unit (EDICT-TARGET-POSTCOND-001) + postconditionSupport: bool, + + deterministicExecution: resource-ref, + conformanceFixtureCorpus: resource-ref, +} + +; Shared types resource-ref and sha256-digest are defined once in +; edict-common.cddl and assembled with this schema by the build +; (EDICT-ABI-NODUP-001). They are not redefined here. + +; --- intrinsic signature ------------------------------------------------- +; The artifact referenced by the manifest's `intrinsics` resource-ref is the +; intrinsic-signature corpus document below. Its layout is fixed so two +; independent profiles validate/hash the corpus identically +; (EDICT-ABI-INTRINSICS-DOC-001). + +; intrinsics is a MAP keyed by coordinate, so the schema itself enforces +; coordinate uniqueness. A provider receives the resolved corpus as a +; digest-bound semantic input and resolves coordinates within that artifact. +; Each map key MUST equal its record's `coordinate` field +; (EDICT-ABI-INTRINSIC-UNIQUE-001). +intrinsics-document = { + apiVersion: "edict.target-profile.intrinsics/v1", + intrinsics: { * tstr => intrinsic }, +} + +; The artifact referenced by the manifest's `operationProfiles` resource-ref. +; operation-profile / optic-template are defined in edict-common.cddl. Keyed by +; coordinate so resolution can't pick between two same-coordinate profiles +; (EDICT-ABI-OPPROFILE-SLOT-001, EDICT-ABI-OPPROFILE-UNIQUE-001). +operation-profiles-document = { + apiVersion: "edict.target-profile.operation-profiles/v1", + profiles: { * tstr => operation-profile }, +} + +; A typed pre-lowering question that can be proposed by Watson or an agent and +; checked by the compiler. It is canonical-CBOR encoded under +; `edict.lowering-requirements/v1`; the compiler checks this artifact, not the +; prose that produced it. +lowering-requirements = { + apiVersion: "edict.lowering-requirements/v1", + operationProfile: tstr, + semanticEffects: [* semantic-effect-requirement], + requiredWriteClasses: [* write-class], + guardKinds: [* guard-kind], + atomicity: atomicity-requirement, + postconditionSupport: bool, + obstructionCoordinates: [* tstr], + footprintObligations: [* tstr], + costObligations: [* tstr], + opticContract: tstr, +} + +semantic-effect-requirement = { + coordinate: tstr, + writeClass: write-class, + guardKinds: [* guard-kind], + obstructionCoordinates: [* tstr], + footprintObligations: [* tstr], + costObligations: [* tstr], +} + +write-class = "none" / "read" / "create" / "ensure" / "append" / + "replace" / "delete" / tstr +guard-kind = "precommit-atomic" / tstr +atomicity-requirement = "atomic" / tstr + +; A genuine union: pure constructors carry no effect kind or failures; effect +; intrinsics must (EDICT-TARGET-INTRINSIC-CLASS-001). The schema enforces this, +; not a comment. + +; The intrinsic's coordinate is the intrinsics map KEY, not a value field, so the +; key and coordinate can never disagree (EDICT-ABI-INTRINSIC-UNIQUE-001). +intrinsic = pure-intrinsic / effect-intrinsic + +pure-intrinsic = { + intrinsicClass: "pure", + typeParameters: [* tstr], + argumentTypes: [* core-type-ref], + returnType: core-type-ref, + guardSupport: false, + footprintTemplate: tstr, + costTemplate: tstr, + writeClass: "none", +} + +effect-intrinsic = { + intrinsicClass: "effect", + typeParameters: [* tstr], + argumentTypes: [* core-type-ref], + returnType: core-type-ref, + effectKind: effect-kind, + ; map keyed by failure coordinate (failure-ident); the failure coordinate is + ; the key, not a value field, so uniqueness is structural + ; (EDICT-ABI-FAILURE-UNIQUE-001). + effectFailures: { * failure-ident => effect-failure-body }, + guardSupport: bool, + footprintTemplate: tstr, + costTemplate: tstr, + writeClass: "read" / "create" / "ensure" / "append" / "replace" / + "delete" / "custom", + canParticipateInAtomicGuard: bool, +} + +; effect-failure-body, effect-kind, authority-class, and core-type-ref are defined +; once in edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- edict-authority-facts.cddl --- +; edict-authority-facts.cddl +; Canonical schema for the first compiler-context authority-facts document. +; Authoritative byte encoding: edict.canonical-cbor/v1. +; +; This schema is assembled with edict-common.cddl so source.digest uses the +; shared sha256-digest typed value. JSON is a review/input rendering: its +; `sha256:<64 hex>` source digest is projected to [`sha256`, 32 raw bytes] on +; the wire, and its fact arrays project to the coordinate-keyed maps below. + +authority-facts = { + apiVersion: "edict.authority-facts/v1", + source: authority-fact-source, + operationProfiles: { * tstr => authority-operation-profile-fact }, + effectWriteClasses: { * tstr => authority-write-class }, + budgets: { * tstr => authority-budget-fact }, +} + +authority-fact-source = { + kind: "lawpack" / "targetProfile", + coordinate: tstr, + digest: sha256-digest, +} + +; The map key is the source operation-profile coordinate. It is not repeated in +; the value, so a key and embedded coordinate cannot disagree. Allowed write +; classes are a canonical map-set: the class is the unique key and null is the +; unit marker. Canonical CBOR fixes key order without a second ordering rule. +authority-operation-profile-fact = { + core: tstr, + allowedWriteClasses: { * authority-write-class => null }, +} + +; The effectWriteClasses map key is the semantic effect coordinate. The budgets +; map key is the source budget coordinate. Canonical CBOR map-key uniqueness +; makes duplicate fact coordinates structurally unrepresentable. +authority-budget-fact = { + maxSteps: uint, + maxAllocatedBytes: uint, + maxOutputBytes: uint, +} + +; AuthorityFactsDocument v1 intentionally accepts only the write classes the +; current compiler model can consume. `custom` is the sole v1 custom spelling; +; arbitrary target-profile extension strings do not enter this compiler path. +authority-write-class = "none" / "read" / "create" / "ensure" / "append" / + "replace" / "delete" / "custom" + +; --- edict-target-ir.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-target-ir.cddl +; Canonical schema for the Edict-owned Target IR artifact envelope. +; Authoritative byte encoding: edict.canonical-cbor/v1. +; +; This schema is assembled with edict-common.cddl and edict-core.cddl. It +; deliberately reuses Core expressions, predicates, budgets, local references, +; obstruction reasons, and obstruction arms so the schema matches the value +; emitted by the canonical Target IR encoder rather than restating those types. +; It describes the structural shape of valid lowering-produced artifacts. The +; lowering and encoder contracts separately enforce semantic identifier rules +; and canonical ordering/deduplication for set-like values. + +; Target IR encoding rejects an empty target-profile coordinate before bytes +; exist, so this root tightens the shared structural resource-ref accordingly. +target-ir-resource-ref = { + id: tstr .regexp "(?s).+", + digest: sha256-digest, +} + +target-ir-artifact = { + kind: "targetIrArtifact", + domain: tstr, + targetProfile: target-ir-resource-ref, + sourceCoreCoordinate: tstr, + intents: { * tstr => target-ir-intent }, +} + +target-ir-intent = { + operationProfile: tstr, + inputConstraints: [* input-constraint], + coreEvaluationBudget: core-budget, + requirements: [* target-ir-requirement], + steps: [* target-ir-step], + result: core-expr, +} + +target-ir-requirement = { + id: tstr, + predicate: core-predicate, + onFailure: require-failure-arm, +} + +target-ir-step = { + id: tstr, + binding: local-ref, + effect: tstr, + targetIntrinsic: tstr, + input: core-expr, + obstructionFailures: [* failure-ident], + obstructionArms: { * failure-ident => obstruction-arm }, +} + + +; --- Echo provider-generated declarative contracts ----------------------- +; These roots validate provider semantic descriptions. They confer no Echo +; runtime authority and contain no package, component, or installation state. + +generated-artifact-profile = { + apiVersion: "echo.generated-artifact-profile/v1", + targetProfile: tstr, + types: { * tstr => echo-generated-type }, + operations: { * tstr => generated-operation }, +} + +echo-generated-type = echo-generated-string-alias / echo-generated-record +echo-generated-string-alias = { + kind: "coreStringAlias", + maxScalarValues: uint, + canonical: "raw-utf8", +} +echo-generated-record = { + kind: "record", + fields: [* echo-generated-record-field], +} +echo-generated-record-field = { name: tstr, type: tstr } + +generated-operation = { + inputType: tstr, + outputType: tstr, + effect: tstr, + operationProfile: tstr, + opticContract: tstr, + budget: tstr, + invocationKind: "mutation" / "observer", + implementation: { kind: "native" / "directAdapter", coordinate: tstr }, + obstructionMappings: { * tstr => tstr }, +} + +echo-provider-conformance-corpus = { + apiVersion: "echo.edict-provider.conformance-corpus/v1", + class: "declarative", + operations: { * tstr => null }, + capabilities: { * tstr => null }, + semanticEffects: { * tstr => null }, + cases: [], +} + +echo-provider-lawpack-compatibility = { + apiVersion: "echo.edict-provider.lawpack-compatibility/v1", + class: "declarative", + acceptedCoreAbi: { * tstr => null }, + acceptedTargetProfiles: { * tstr => null }, + semanticEffects: { * tstr => null }, +} + +echo-provider-lawpack-target-adapter = { + apiVersion: "echo.edict-provider.lawpack-target-adapter/v1", + class: "declarative", + targetProfile: tstr, + targetIrDomain: tstr, + effectImplementations: { * tstr => echo-effect-implementation }, +} + +echo-effect-implementation = echo-native-effect-implementation / echo-direct-effect-implementation +echo-native-effect-implementation = { + kind: "native", + capability: tstr, + writeClass: tstr, +} +echo-direct-effect-implementation = { + kind: "directAdapter", + adapter: tstr, + capability: tstr, + writeClass: tstr, +} + +echo-provider-lawpack-verifier = { + apiVersion: "echo.edict-provider.lawpack-verifier/v1", + class: "declarative", + operationObstructions: { * tstr => echo-operation-obstructions }, +} +echo-operation-obstructions = { + effect: tstr, + failureMappings: { * failure-ident => tstr }, +} + +echo-dpo-bundle = { + apiVersion: "echo.dpo.bundle/v1", + class: "declarative", + applicationModel: tstr, + readConsistency: tstr, + operationProfiles: { * tstr => null }, +} + +echo-dpo-cost = { + apiVersion: "echo.dpo.cost/v1", + class: "declarative", + capabilities: { * tstr => echo-cost-capability }, +} +echo-cost-capability = { + effect: tstr, + costTemplate: tstr, + semanticObligation: tstr, +} + +echo-dpo-footprint = { + apiVersion: "echo.dpo.footprint/v1", + class: "declarative", + capabilities: { * tstr => echo-footprint-capability }, +} +echo-footprint-capability = { + effect: tstr, + footprintTemplate: tstr, + semanticObligation: tstr, + writeClass: tstr, +} + +echo-span-ir = { + apiVersion: "echo.span-ir/v1", + class: "declarative", + domain: tstr, + targetProfile: tstr, + capabilities: { * tstr => null }, +} + +echo-dpo-lowerer = { + apiVersion: "echo.dpo.lowerer/v1", + class: "declarative", + acceptedCoreAbi: { * tstr => null }, + outputDomain: tstr, + targetProfile: tstr, + effectImplementations: { * tstr => echo-effect-implementation }, + opticContracts: { * tstr => tstr }, +} + +echo-dpo-obstructions = { + apiVersion: "echo.dpo.obstructions/v1", + class: "declarative", + effectFailures: { * tstr => { authorityClass: authority-class, payloadType: tstr } }, + domainObstructions: { * tstr => { authorityClass: authority-class, payloadSchema: tstr } }, +} + +echo-dpo-verifier = { + apiVersion: "echo.dpo.verifier/v1", + class: "declarative", + targetProfile: tstr, + targetIrDomain: tstr, + capabilities: { * tstr => null }, + operationProfiles: { * tstr => null }, + opticContracts: { * tstr => tstr }, +} + +echo-nonempty-tstr = tstr .regexp "(?s).+" + +generated-artifact = { + apiVersion: "echo.generated-artifact/v1", + profile: resource-ref, + operation: echo-nonempty-tstr, + mediaType: echo-nonempty-tstr, + bytes: bstr, +} + +review-payload = { + apiVersion: "echo.review-payload/v1", + authoritative: false, + subject: resource-ref, + mediaType: echo-nonempty-tstr, + bytes: bstr, +} + +verifier-report = { + apiVersion: "echo.verifier-report/v1", + targetIr: resource-ref, + outcome: "accepted" / "rejected", + diagnosticAbi: resource-ref, + diagnosticBytes: bstr, +} diff --git a/schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor b/schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor new file mode 100644 index 0000000000000000000000000000000000000000..b3ca78618d56814e4c4ff166e45f966b30dc899b GIT binary patch literal 1733 zcmZuxeNYr-7{}6)B1H#ODr8K}$Y#+a3MeBGL7U{;0g^)ZcHiB5VRzr<-FNR!Q3Ogy z>zYClQb4JgQNljNP;o%~s4yUyOM)?VU_fz(Li+%#8EM+RgM(@I&wZX}f6w##*ggBC z8L}3@SWpNnBVIr@fC2tQD=L%4kcr|dtBGSF4-`_&DHb~Pg%>lItZNIt`)fzi*wXPM zt+!yz^3nbcg^L0mo$+(;wI7^yrkq!3i8Uj;4rl``WJrjORz!+HqKqUU5hKt?vJ#vh zJduN~X|Jk#zUmi1Ep4Y?!zs!wjz(MJn;E5Hgw5^b^&8uNg><~kU;4pwAZq98WH z^~zXSU>SSt(2Y*-{HVYln{&roi!VhqH&FZHkND#Ut1KEWMD zh7sZh7=6Oo-L#;yW={Qq_4MJ{OQ=fUAm*DH!iuIYpVZ^IqAC!$$z|WDXjUaw0Lg9| z`U31(;BFbM_-tlG(|7m$?+T~8%ekfZy&o>>HN{o6=a)S6#+wx*`!9$rqB=k zsG}0M{!?|u2sd~f*A_2Z5Lw*jz46)WC+oXcnu` zS+O7@Pb<3e!?|CUIixi;i>KS6deriCjfjorpU&j(6dtq zA1S@vySo+UAsJxT852&pGGq_(pnLk0i8ItM?P($9{*^_?c3gq$GFz%5O6r_hm8E}G z*6!RtXU&$G3-#mO8BL@`pnb0l$eCObZBmd~Ay{Q}=~9s(m}w>#ONg>U1)2pw0geL< zQKpY=qU}gR;x^r4d%z@A$TT3sJCip1Rc+mxcDZm@a-NrU`0)9!hUQ;fndY0F^}4Af zFp4FzmK_F3EYxpFQ)L-pGG=9H2}zn=LY%}P7D{}oDgc*K6Cb5#fMU$Z@JHkv7GD{t zwXTeHv?QHaym{cyjGFqLe*IwurNba=)VIpY0s^oIB`qP4iL(Pn)lZlnVb6eQT|B0K zeVn^xC|~e}Tl1D@J9b?k$FXMyk3Dy@?^;Sz%+JxkhZppH-Z%p7kMls%^90x!Odv-y zWHMGo|8oihUSsNxo)MkrZL1UZgjoWf`r+U^&-9-?*Ks*N-@E11+G~5Ocjx``cHMu@ C+TC^l literal 0 HcmV?d00001 diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor new file mode 100644 index 00000000..4464f53c --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor @@ -0,0 +1 @@ +ecaseseclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperationsga.b@1.tlcapabilitiesrecho.dpo@1.replaceosemanticEffectsntarget.replace \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor new file mode 100644 index 00000000..a703b6fc --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionx,echo.edict-provider.lawpack-compatibility/v1oacceptedCoreAbimedict.core/v1osemanticEffectsntarget.replacevacceptedTargetProfilesjecho.dpo@1 \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor new file mode 100644 index 00000000..a0887cb0 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor @@ -0,0 +1 @@ +etypesjcoordinateha.b@1.Idjdefinitionx!StringgeffectsiinputTypeha.b@1.Idjcoordinatentarget.replacejoutputTypema.b@1.ReceiptlguardSupportncostObligationstarget.replace.costneffectFailureshrejectedkpayloadTypewtarget.replace.rejectednauthorityClassndomainMappableneffectKindHintgreplacenexecutionClassgruntimentypeParameterssfootprintObligationxtarget.replace.footprinticonstantslobstructionsjcoordinatetdomain.WriteRejectedmpayloadSchemaxdomain.WriteRejected.PayloadnauthorityClassndomainMappablempureFunctionsqoperationProfiles \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor new file mode 100644 index 00000000..5a57d65b --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionx-echo.edict-provider.lawpack-target-adapter/v1mtargetProfilejecho.dpo@1ntargetIrDomainoecho.span-ir/v1ueffectImplementationsntarget.replacedkindfnativejcapabilityrecho.dpo@1.replacejwriteClassgreplace \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor new file mode 100644 index 00000000..a6d10bd7 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionx'echo.edict-provider.lawpack-verifier/v1uoperationObstructionsga.b@1.tfeffectntarget.replaceofailureMappingshrejectedtdomain.WriteRejected \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor new file mode 100644 index 00000000..4c13093f --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionrecho.dpo.bundle/v1oreadConsistencytapplication-snapshotpapplicationModelfatomicqoperationProfilesxcontinuum.profile.write/v1 \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor new file mode 100644 index 00000000..2242fed3 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionpecho.dpo.cost/v1lcapabilitiesrecho.dpo@1.replacefeffectntarget.replacelcostTemplatestarget.replace.costrsemanticObligationstarget.replace.cost \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor new file mode 100644 index 00000000..3118bbd0 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionuecho.dpo.footprint/v1lcapabilitiesrecho.dpo@1.replacefeffectntarget.replacejwriteClassgreplaceqfootprintTemplatextarget.replace.footprintrsemanticObligationxtarget.replace.footprint \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor new file mode 100644 index 00000000..3250617a --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor @@ -0,0 +1 @@ +japiVersionx"edict.target-profile.intrinsics/v1jintrinsicsrecho.dpo@1.replacejeffectKindgreplacejreturnTypema.b@1.ReceiptjwriteClassgreplacelcostTemplatestarget.replace.costlguardSupportmargumentTypesha.b@1.IdneffectFailureshrejectedkpayloadTypewtarget.replace.rejectednauthorityClassndomainMappablenintrinsicClassfeffectntypeParametersqfootprintTemplatextarget.replace.footprintxcanParticipateInAtomicGuard \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-ir.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-ir.cbor new file mode 100644 index 00000000..47cd6d6a --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-ir.cbor @@ -0,0 +1 @@ +eclasskdeclarativefdomainoecho.span-ir/v1japiVersionoecho.span-ir/v1lcapabilitiesrecho.dpo@1.replacemtargetProfilejecho.dpo@1 \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor new file mode 100644 index 00000000..102f1d90 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionsecho.dpo.lowerer/v1loutputDomainoecho.span-ir/v1mtargetProfilejecho.dpo@1nopticContractsxcontinuum.profile.write/v1mreplace-pointoacceptedCoreAbimedict.core/v1ueffectImplementationsntarget.replacedkindfnativejcapabilityrecho.dpo@1.replacejwriteClassgreplace \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor new file mode 100644 index 00000000..a15d8a30 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionxecho.dpo.obstructions/v1neffectFailureswtarget.replace.rejectedkpayloadTypewtarget.replace.rejectednauthorityClassndomainMappablerdomainObstructionstdomain.WriteRejectedmpayloadSchemaxdomain.WriteRejected.PayloadnauthorityClassndomainMappable \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor new file mode 100644 index 00000000..f4445c6a --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor @@ -0,0 +1 @@ +hprofilesxcontinuum.profile.write/v1mopticTemplateiopticKindsaffectReintegrationlboundaryKindfaffectmsupportPolicyx&continuum.support.carry-or-obstruct/v1olossDispositionx#continuum.support.reject-on-loss/v1sapertureRequirementcrefxtarget.replace.footprintdkindxabstractFootprintObligationoeffectPredicatex'echo.dpo.operation-mode.replace-only/v1japiVersionx*edict.target-profile.operation-profiles/v1 \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor new file mode 100644 index 00000000..6fd4f838 --- /dev/null +++ b/schemas/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersiontecho.dpo.verifier/v1lcapabilitiesrecho.dpo@1.replacemtargetProfilejecho.dpo@1nopticContractsxcontinuum.profile.write/v1mreplace-pointntargetIrDomainoecho.span-ir/v1qoperationProfilesxcontinuum.profile.write/v1 \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/provider-manifest.echo.json b/schemas/edict-provider/package/v1/provider-manifest.echo.json new file mode 100644 index 00000000..fd3dfa86 --- /dev/null +++ b/schemas/edict-provider/package/v1/provider-manifest.echo.json @@ -0,0 +1,248 @@ +{ + "apiVersion": "edict.provider-manifest/v1", + "providerAbi": "edict:target-provider@1.0.0", + "provider": { + "coordinate": "echo.edict-provider@1", + "digest": "sha256:cf0147bea65cdfa7d426dc11a0eeab8f3ac889bfb3daa14f3d6b05ccd80f2d6e" + }, + "artifacts": [ + { + "role": "authority-facts.echo-dpo", + "artifactKind": "authorityFacts", + "resource": { + "coordinate": "echo.dpo-authority-facts@1", + "digest": "sha256:5c30871b115e82415980714281e250c2fda281afb4a4fe16c2917f93e86182a4" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "authority-facts.echo-lawpack", + "artifactKind": "authorityFacts", + "resource": { + "coordinate": "echo.dpo-lawpack-authority-facts@1", + "digest": "sha256:37591478584a88d3dc08a620873d803a2d6fcf5dc70767aae3587e5862ee99e9" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "generated-artifact-profile.echo-dpo-registration", + "artifactKind": "generatedArtifactProfile", + "resource": { + "coordinate": "echo.dpo.registration/v1", + "digest": "sha256:3377304d8634681821cd958427e0b8baccc37b7b08bfb342d988a08571eb83ab" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "lawpack.echo-dpo", + "artifactKind": "lawpack", + "resource": { + "coordinate": "echo.dpo-lawpack@1", + "digest": "sha256:47006be4c2b569f13759078c560fe508e158b429cd9d4c5e47d9a7ea86b983b2" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "lowerer.echo-dpo", + "artifactKind": "lowerer", + "resource": { + "coordinate": "echo.dpo.lowerer/component@1", + "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + }, + "source": { + "kind": "component", + "component": { + "coordinate": "echo.dpo.lowerer/component@1", + "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + } + } + }, + { + "role": "provenance.provider-generation", + "artifactKind": "generationProvenance", + "resource": { + "coordinate": "echo.edict-provider-generation-provenance@1", + "digest": "sha256:ca526fb8690d86565d71c2af0d043e062b281b51df9a41ddb8375d6fbc606efc" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "review.provider-generation", + "artifactKind": "reviewArtifact", + "resource": { + "coordinate": "echo.edict-provider-generation-review@1", + "digest": "sha256:9044f199975f74b83f6702204385cbd7a979ee29afd26f2dbcb8bbe5b3946c6f" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "schema.echo-provider-artifacts", + "artifactKind": "artifactSchema", + "resource": { + "coordinate": "echo.provider-artifacts.cddl@1", + "digest": "sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "target-profile.echo-dpo", + "artifactKind": "targetProfile", + "resource": { + "coordinate": "echo.dpo@1", + "digest": "sha256:f41df38156625a05c1ee8bce652ffddf04e71b54fe027eeab9d255d0d8322db0" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + } + } + }, + { + "role": "verifier.echo-dpo", + "artifactKind": "verifier", + "resource": { + "coordinate": "echo.dpo.verifier/component@1", + "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + }, + "source": { + "kind": "component", + "component": { + "coordinate": "echo.dpo.verifier/component@1", + "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + } + } + } + ], + "schemaBindings": [ + { + "domain": "echo.generated-artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact" + }, + { + "domain": "echo.review-payload/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "review-payload" + }, + { + "domain": "echo.verifier-report/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "verifier-report" + }, + { + "domain": "edict.authority-facts/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "authority-facts" + }, + { + "domain": "edict.core.module/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "core-module" + }, + { + "domain": "edict.lawpack/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-manifest" + }, + { + "domain": "edict.lowering-requirements/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lowering-requirements" + }, + { + "domain": "edict.target-ir.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "target-ir-artifact" + }, + { + "domain": "edict.target-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "target-profile-manifest" + } + ] +} diff --git a/scripts/tests/classify_changes.test.cjs b/scripts/tests/classify_changes.test.cjs index f481e754..a6545826 100644 --- a/scripts/tests/classify_changes.test.cjs +++ b/scripts/tests/classify_changes.test.cjs @@ -140,6 +140,10 @@ test('every workspace member has an explicit non-catch-all policy path', () => { policyYaml, /echo-edict-provider-verifier:\n\s+class: DET_CRITICAL\n\s+owner_role: "Tooling Engineer"\n\s+paths: \["crates\/echo-edict-provider-verifier\/\*\*", "schemas\/edict-provider\/components\/v1\/verifier\.echo-dpo\.component\.wasm", "tests\/edict-provider-host-v1\/\*\*"\]\n/, ); + assert.match( + policyYaml, + /echo-edict-provider-artifacts:\n\s+class: DET_CRITICAL\n\s+owner_role: "Tooling Engineer"\n\s+paths: \[.*"schemas\/edict-provider\/\*\*"\]\n/, + ); assert.match(policyYaml, /echo-runtime-schema:\n\s+class: DET_CRITICAL\n/); assert.match(policyYaml, /echo-file-aperture:\n\s+class: DET_IMPORTANT\n/); assert.match(policyYaml, /echo-trace:\n\s+class: DET_IMPORTANT\n/); From 5ee929479eb5f4be32007a335beebb91cdde10b0 Mon Sep 17 00:00:00 2001 From: James Ross Date: Thu, 16 Jul 2026 14:13:54 -0700 Subject: [PATCH 4/6] Prove provider package readiness --- .gitattributes | 23 + .github/workflows/ci.yml | 2 + CHANGELOG.md | 22 +- crates/echo-wesley-gen/README.md | 27 +- .../v1/edict-provider-contracts.cddl | 793 +++++ .../edict-provider/contracts/v1/manifest.json | 80 + .../echo-provider-semantics-v1.json | 703 +++++ .../generation-settings-v1.json | 7 + .../lowerer.echo-dpo.component.wasm | Bin 0 -> 130679 bytes .../verifier.echo-dpo.component.wasm | Bin 0 -> 188736 bytes .../provenance.provider-generation.json | 1 + .../evidence/review.provider-generation.json | 1 + .../primary/authority-facts.echo-dpo.cbor | 1 + .../primary/authority-facts.echo-lawpack.cbor | Bin 0 -> 243 bytes ...rtifact-profile.echo-dpo-registration.cbor | 1 + .../generated/primary/lawpack.echo-dpo.cbor | Bin 0 -> 799 bytes .../schema.echo-provider-artifacts.cddl | 969 ++++++ .../primary/target-profile.echo-dpo.cbor | Bin 0 -> 1733 bytes .../resource.conformance-corpus.cbor | 1 + .../resource.lawpack-compatibility.cbor | 1 + .../resources/resource.lawpack-exports.cbor | 1 + .../resource.lawpack-target-adapter.cbor | 1 + .../resources/resource.lawpack-verifier.cbor | 1 + .../resource.target-bundle-profile.cbor | 1 + .../resource.target-cost-algebra.cbor | 1 + .../resource.target-footprint-algebra.cbor | 1 + .../resources/resource.target-intrinsics.cbor | 1 + .../resources/resource.target-ir.cbor | 1 + .../resource.target-lowerer-contract.cbor | 1 + .../resource.target-obstruction-taxonomy.cbor | 1 + .../resource.target-operation-profiles.cbor | 1 + .../resource.target-verifier-contract.cbor | 1 + .../package/v1/provider-manifest.echo.json | 338 ++ .../assets/v1/repository/Cargo.lock.source | 2785 +++++++++++++++++ .../assets/v1/repository/Cargo.toml.source | 118 + .../echo-edict-canonical/Cargo.toml.source | 20 + .../echo-edict-canonical/src/lib.rs.source | 521 +++ .../crates/echo-wesley-gen/Cargo.toml.source | 37 + .../v1/repository/rust-toolchain.toml.source | 5 + .../src/bin/echo-edict-provider-artifacts.rs | 8 +- .../src/bin/echo-edict-provider-assets.rs | 446 +++ .../src/bin/echo-edict-provider-package.rs | 12 +- crates/echo-wesley-gen/src/main.rs | 2 +- .../echo-wesley-gen/src/provider_artifacts.rs | 38 +- crates/echo-wesley-gen/src/provider_corpus.rs | 64 +- .../echo-wesley-gen/src/provider_package.rs | 34 +- .../echo-wesley-gen/src/provider_semantics.rs | 83 + .../tests/provider_artifact_corpus.rs | 12 +- .../tests/provider_canonical_contract.rs | 4 +- .../tests/provider_contract_pack.rs | 4 +- .../tests/provider_generation_input.rs | 10 +- .../tests/provider_generation_provenance.rs | 10 +- .../tests/provider_generation_review.rs | 10 +- .../echo-wesley-gen/tests/provider_package.rs | 21 +- .../tests/provider_package_assets.rs | 109 + .../tests/provider_package_corpus.rs | 6 +- .../tests/provider_primary_artifacts.rs | 10 +- .../tests/provider_semantic_source.rs | 109 +- det-policy.yaml | 2 +- .../application-contract-hosting.md | 31 +- schemas/edict-provider/README.md | 22 +- .../echo-provider-semantics-v1.json | 90 + .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- schemas/edict-provider/package/README.md | 19 +- .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../package/v1/provider-manifest.echo.json | 128 +- scripts/tests/classify_changes.test.cjs | 2 +- scripts/verify-edict-provider-host-v1.sh | 6 + tests/edict-provider-host-v1/Cargo.lock | 1 + tests/edict-provider-host-v1/Cargo.toml | 1 + .../tests/package_contract.rs | 1312 ++++++++ 73 files changed, 8923 insertions(+), 159 deletions(-) create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/manifest.json create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/echo-provider-semantics-v1.json create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/generation-settings-v1.json create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/generated-artifact-profile.echo-dpo-registration.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-ir.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor create mode 100644 crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json create mode 100644 crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source create mode 100644 crates/echo-wesley-gen/assets/v1/repository/Cargo.toml.source create mode 100644 crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/Cargo.toml.source create mode 100644 crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source create mode 100644 crates/echo-wesley-gen/assets/v1/repository/crates/echo-wesley-gen/Cargo.toml.source create mode 100644 crates/echo-wesley-gen/assets/v1/repository/rust-toolchain.toml.source create mode 100644 crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs create mode 100644 crates/echo-wesley-gen/tests/provider_package_assets.rs create mode 100644 tests/edict-provider-host-v1/tests/package_contract.rs diff --git a/.gitattributes b/.gitattributes index 8114b509..e6da31fa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,24 @@ # Preserve concurrent additions to the shared agent instructions. AGENTS.md merge=union +# Preserve every authored byte occurrence hashed into provider-generator identity. +Cargo.lock -text +Cargo.toml -text +rust-toolchain.toml -text +crates/echo-edict-canonical/Cargo.toml -text +crates/echo-edict-canonical/src/lib.rs -text +crates/echo-wesley-gen/Cargo.toml -text +crates/echo-wesley-gen/src/lib.rs -text +crates/echo-wesley-gen/src/provider_*.rs -text +crates/echo-wesley-gen/src/bin/echo-edict-provider-*.rs -text +schemas/edict-provider/contracts/v1/** -text +schemas/edict-provider/echo-provider-semantics-v1.json -text +schemas/edict-provider/generation-settings-v1.json -text + +# Preserve the exact audited component owners before package assembly. +schemas/edict-provider/components/v1/** -text +schemas/edict-provider/components/v1/**/*.wasm binary + # Preserve exact checked provider corpus bytes across checkout configurations. schemas/edict-provider/generated/v1/** -text schemas/edict-provider/generated/v1/**/*.cbor binary @@ -9,3 +27,8 @@ schemas/edict-provider/generated/v1/**/*.cbor binary schemas/edict-provider/package/v1/** -text schemas/edict-provider/package/v1/**/*.cbor binary schemas/edict-provider/package/v1/**/*.wasm binary + +# Preserve package-local provider source/artifact carriers byte-for-byte. +crates/echo-wesley-gen/assets/v1/** -text +crates/echo-wesley-gen/assets/v1/**/*.cbor binary +crates/echo-wesley-gen/assets/v1/**/*.wasm binary diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba5da273..91090aac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -177,6 +177,8 @@ jobs: . - name: cargo test (workspace sans warp-core) run: cargo test --workspace --exclude warp-core + - name: checked Edict provider crate assets are current and packaged + run: cargo +1.90.0 run --locked -p echo-wesley-gen --bin echo-edict-provider-assets -- --check-package-list - name: checked Edict provider package is current run: cargo +1.90.0 run --locked -p echo-wesley-gen --bin echo-edict-provider-package -- --check - name: package publishable Edict canonical leaf diff --git a/CHANGELOG.md b/CHANGELOG.md index 8706cfca..661ed01a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,9 @@ - `echo-wesley-gen` now purely assembles and digest-admits the first complete Echo Edict provider distribution from the verified 22-file generated corpus and explicit lowerer/verifier bytes. The derived provider manifest carries ten - exact routes and nine schema bindings but never inventories itself. A - versioned canonical-CBOR package root binds those semantics plus raw hashes of + exact routes and 24 schema bindings—nine invocation domains, the generated + artifact profile, and 14 generated-resource domains—but never inventories + itself. A versioned canonical-CBOR package root binds those semantics plus raw hashes of all 24 non-manifest members, while the exact 25-file inventory, deterministic JSON rendering, mixed raw/domain-framed digest laws, packaged Wesley provenance/review, component bounds, and an external expected provider pin @@ -25,6 +26,23 @@ bounds actual-tree enumeration and expected-byte reads, never opens an unexpected regular file, and makes `--check` report sorted drift without creating, deleting, or rewriting package material. +- The checked provider package now passes an isolated Edict-native readiness + boundary pinned to Edict merge `c75c3f55`. The exact manifest constructs its + immutable 24-domain schema registry, all five canonical primaries and 14 + generated resources satisfy their owning CDDL roots, resource references are + bound field-by-field to independently recomputed domain-framed digests, both + components pass frozen-WIT preflight, and both request kinds produce opaque + validation proofs. Schema-valid byte replacement, digest mutation, semantic + field swaps, authority-source disagreement, malformed schemas/components, + and invalid requests all fail before guest execution. This proves package + readiness only, never Echo installation, execution, or runtime authority. +- `echo-wesley-gen` now carries a fixed 35-file package-local source and provider + asset boundary, preserving original logical source labels while making its + `.crate` archive independent of workspace-parent files. An explicit sync tool + distinguishes authoritative generated/component owners from their checked + package corroboration, supports staged regeneration without circularity, and + checks exact Cargo archive selection. The extracted archive compiles when its + still-unpublished Echo dependencies are supplied through local patches. - Echo now provides the exact `edict:target-provider/lowerer@1.0.0` Component Model implementation for the first checked provider closure. The pure lowerer accepts only explicit digest-bound Core, target-profile, diff --git a/crates/echo-wesley-gen/README.md b/crates/echo-wesley-gen/README.md index 75e4e263..f7d3286e 100644 --- a/crates/echo-wesley-gen/README.md +++ b/crates/echo-wesley-gen/README.md @@ -116,7 +116,9 @@ identity, not an executable-build or supply-chain attestation. provider components into one 24-member, non-self-referential package closure, then derives the separate `edict.provider-manifest/v1` JSON file. The Echo-owned package root is a domain-framed canonical-CBOR value over the exact manifest -routes, nine schema bindings, and raw SHA-256 of every non-manifest member. +routes, 24 schema bindings (nine invocation domains, the generated artifact +profile, and 14 generated-resource domains), and raw SHA-256 of every +non-manifest member. Canonical-CBOR artifact routes retain their Edict domain-framed identities; CDDL, Wesley evidence JSON, components, and every physical member retain raw exact-byte identities. Digest admission requires exact deterministic manifest @@ -129,7 +131,8 @@ remains later still. `echo-edict-provider-package` is the explicit publication boundary for that distribution. Before any filesystem action it proves that the package's 22 -`generated/` members are the exact checked #652 corpus, then writes the two +`generated/` members are the current checked provider corpus introduced by #652, +then writes the two checked components and derived manifest through the same no-follow, unexpected-entry-refusing filesystem boundary used by the artifact corpus. The checked 25-file result lives under `schemas/edict-provider/package/v1/`. @@ -139,6 +142,26 @@ unique expected inventory before resolving the root, caps that inventory at 256 files and 64 MiB, caps an actual scan at 1,024 entries, and never opens or reads an unexpected regular file. +`echo-edict-provider-assets` maintains the exact 35-file package-local carrier +tree under `assets/v1/`. The physical carrier names are packaging locations, +not replacement source identities: generator provenance continues to name the +original repository-relative authored paths. Read-only mode requires every +carrier to match its fixed owner, requires generated artifacts and components +to match their checked package copies, and can prove that `cargo package --list` +selects exactly the complete carrier inventory. Explicit `--write` mode copies +authoritative owners without requiring the temporarily stale package copy, +allowing the honest staged sequence artifact generation, carrier sync, package +generation, then final carrier corroboration. It never discovers a preferred +owner or normalizes authored bytes. + +The isolated `tests/edict-provider-host-v1` gate pins Edict revision +`c75c3f550d049485ba00eae0dc272c6dd6aca11f` and consumes the exact checked +package. It constructs the native 24-domain schema registry, validates all 19 +canonical package members under their owning roots, binds every lawpack and +target-profile resource field to exact packaged bytes, prepares both frozen-WIT +components, and validates both request kinds without invoking guest code. That +is pre-execution package readiness, not Echo installation or runtime authority. + The dedicated `echo-edict-provider-artifacts` binary is the explicit filesystem boundary. The caller-supplied `--out` path is resolved once under ambient filesystem authority; its final corpus-root entry is opened or created without diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl b/crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl new file mode 100644 index 00000000..7544122d --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl @@ -0,0 +1,793 @@ +; SPDX-License-Identifier: Apache-2.0 +; edict-provider-contracts.cddl +; Generated from Edict-owned ABI fragments. DO NOT EDIT. + +; --- edict-common.cddl --- +; edict-common.cddl +; Shared CDDL types for the Edict ABIs, defined ONCE here so they cannot drift +; (EDICT-ABI-NODUP-001). Two groups: +; - resource-ref, sha256-digest, effect-failure-body, effect-kind, authority-class, +; core-type-ref: assembled with edict-target-profile.cddl and +; edict-lawpack.cddl by the build; those schemas do not redefine them. +; - operation-profile, optic-template, aperture-requirement and their refs: +; consumed by the Core/optic layer (edict-core.cddl) and referenced by the +; language/target-profile specs. +; Authoritative byte encoding: edict.canonical-cbor/v1. + +; A normative subcomponent referenced by identity plus digest. Manifests never +; embed their own self-digest in their preimage (EDICT-CORE-SELFHASH-001). +resource-ref = { id: tstr, digest: sha256-digest } + +; Digests are authoritative as typed byte values, never hex strings. Review JSON +; renders this as "sha256:<64 lowercase hex>" (EDICT-DIGEST-WIRE-001). +sha256-digest = [ algorithm: "sha256", bytes: bstr .size 32 ] + +; A named low-level failure an effect can raise. The source obstruction map +; binds it (by coordinate) and constructs a typed domain obstruction from its +; payload (EDICT-ABI-FAILURE-NAMED-001). +; An effect's `effectFailures` list MUST have unique `coordinate`s: since the +; obstruction map is keyed by coordinate, two failures sharing a coordinate (even +; with different authorityClass/payloadType) make exhaustive mapping and binder +; typing ambiguous and are rejected (EDICT-ABI-FAILURE-UNIQUE-001). +; +; Effects carry their failures as a map `{ failure-ident => effect-failure-body }` +; (see the target/lawpack effect schemas). The failure coordinate is the map +; KEY, so it is not repeated in the body and cannot disagree with the key. +effect-failure-body = { + authorityClass: authority-class, + payloadType: core-type-ref, ; typed, bounded (may be empty record) +} + +; A failure coordinate must be a bare Edict `ident` (letter/underscore then +; letters/digits/underscores) AND must not be a reserved keyword (e.g. `else`, +; `basis`, `where`, `require`, `for`, `if`). The source obstruction-map LHS only +; accepts a non-keyword `ident`, so a hyphen/dot/keyword coordinate would be +; ABI-valid yet impossible to map exhaustively in source. The regex captures the +; lexical shape; keyword exclusion is an additional validation rule +; (EDICT-ABI-FAILURE-IDENT-001). +failure-ident = tstr .regexp "[A-Za-z_][A-Za-z0-9_]*" + +effect-kind = "read" / "create" / "ensure" / "replace" / "delete" / + "append" / "reduce" / "semantic.emit" / "custom" + +authority-class = "domainMappable" / "participantOwned" / "integrityFault" / + "resourceFault" / "internalFault" + +core-type-ref = tstr ; canonical Core type coordinate + +; An operation profile supplies the optic template a Core intent resolves its +; opticKind/boundaryKind/supportPolicy/lossDisposition from. Target profiles and +; lawpacks publish these as a map `{ coordinate => operation-profile }`, so the +; coordinate is the KEY, not a value field (EDICT-OPTIC-TEMPLATE-OWNER-001, +; EDICT-ABI-OPPROFILE-UNIQUE-001). +operation-profile = { + opticTemplate: optic-template, + effectPredicate: tstr, ; coordinate of the operation-mode predicate +} + +optic-template = { + opticKind: "revelation" / "affectReintegration", + boundaryKind: "projection" / "affect", + supportPolicy: tstr, ; canonical support-policy coordinate + lossDisposition: tstr, ; canonical loss-disposition coordinate + ? basisTemplate: tstr, ; optional digest-locked basis template coord + ; the aperture requirement this template supplies. Required when the template + ; is the source of a Core optic's apertureRequirement (i.e. the intent has no + ; source `footprint <= ...`), since apertureRequirement is mandatory in Core + ; (EDICT-OPTIC-APERTURE-REF-001). + ? apertureRequirement: aperture-requirement, +} + +; apertureRequirement is a typed reference, never a free-form string. A review +; rendering may show its coordinate (EDICT-OPTIC-APERTURE-REF-001). +aperture-requirement = footprint-ceiling-ref / abstract-footprint-obligation-ref +footprint-ceiling-ref = { kind: "footprintCeiling", ref: tstr } +abstract-footprint-obligation-ref = { kind: "abstractFootprintObligation", ref: tstr } + +; --- edict-core.cddl --- +; edict-core.cddl +; Normative schema for the Edict Core v1 semantic model. +; +; Scope boundary: this file defines Core meaning and schema shape only. It does +; not define a canonical encoder, Core module hash fields, hash fixtures, target +; lowering, admission bundles, or target-owned IR. + +core-module = { + apiVersion: "edict.core/v1", + coordinate: tstr, + imports: [* core-import], + types: { * tstr => core-type }, + intents: { + tstr => core-intent }, + requiredCoreCapabilities: [* tstr], +} + +core-import = { + kind: "lawpack" / "target" / "core", + ref: resource-ref, + ? alias: tstr, +} + +; --- types --------------------------------------------------------------- + +core-type = core-scalar-type / core-record-type / core-variant-type / + core-option-type / core-list-type / core-map-type / + core-capability-ref-type + +core-scalar-type = core-bool-type / core-int-type / core-string-type / + core-bytes-type / core-unit-type + +core-bool-type = { kind: "Bool" } +core-unit-type = { kind: "Unit" } +core-int-type = { + kind: "I64" / "U64" / "I32" / "U32" / "I16" / "U16" / "I8" / "U8", +} +core-string-type = { + kind: "String", + max: uint, + canonical: "unicode-scalar-nfc" / "raw-utf8", +} +core-bytes-type = { + kind: "Bytes", + max: uint, +} +core-record-type = { + kind: "Record", + fields: { * tstr => core-type-ref }, +} +core-variant-type = { + kind: "Variant", + cases: { + tstr => variant-case-body }, +} +variant-case-body = { + ? payload: core-type-ref, +} +core-option-type = { + kind: "Option", + item: core-type-ref, +} +core-list-type = { + kind: "List", + item: core-type-ref, + max: uint, +} +core-map-type = { + kind: "Map", + key: core-type-ref, + value: core-type-ref, + max: uint, +} +core-capability-ref-type = { + kind: "CapabilityRef", + item: core-type-ref, +} + +; core-type-ref is defined in edict-common.cddl and assembled with this schema. + +; --- references and values ---------------------------------------------- + +; Local identity is alpha-stable. `id` is the compiler-owned local coordinate; +; `alphaName` is the normalized human/debug name. Source binder spelling is not +; identity. +local-ref = { + id: tstr, + alphaName: tstr, + type: core-type-ref, +} + +core-value = core-null-value / core-bool-value / core-int-value / + core-string-value / core-bytes-value / core-record-value / + core-variant-value / core-list-value / core-map-value / + core-capability-value + +core-null-value = { kind: "null" } +core-bool-value = { kind: "bool", value: bool } +core-int-value = { kind: "int", width: tstr, value: int } +core-string-value = { kind: "string", value: tstr } +core-bytes-value = { kind: "bytes", value: bstr } +core-record-value = { kind: "record", fields: { * tstr => core-value } } +core-variant-value = { + kind: "variant", + type: core-type-ref, + case: tstr, + ? payload: core-value, +} +core-list-value = { kind: "list", values: [* core-value] } +core-map-value = { kind: "map", entries: [* [key: core-value, value: core-value]] } +core-capability-value = { + kind: "capability", + receipt: sha256-digest, +} + +; Edict-authored pure helpers use a pure Core function body. The body can bind +; pure expressions and return an expression, but it cannot contain Core effect, +; guard, branch, loop, match-node, or proof-obligation nodes. +core-fn-body = { + params: [* local-ref], + body: core-pure-block, +} + +core-pure-block = { + locals: [* local-ref], + bindings: [* pure-let-node], + result: core-expr, +} + +pure-let-node = { + kind: "let", + binding: local-ref, + value: core-expr, +} + +; --- expressions and predicates ----------------------------------------- + +core-expr = local-expr / const-expr / record-expr / field-expr / + variant-expr / match-expr / call-expr / list-expr / map-expr / + if-expr + +local-expr = { kind: "local", ref: local-ref } +const-expr = { kind: "const", value: core-value } +record-expr = { kind: "record", fields: { * tstr => core-expr } } +field-expr = { kind: "field", base: core-expr, field: tstr } +variant-expr = { + kind: "variant", + type: core-type-ref, + case: tstr, + ? payload: core-expr, +} +match-expr = { + kind: "match", + scrutinee: core-expr, + arms: [+ match-arm], +} +match-arm = { + case: tstr, + ? binder: local-ref, + body: core-expr, +} +call-expr = { + kind: "call", + callee: tstr, + typeArgs: [* core-type-ref], + args: [* core-expr], +} +list-expr = { kind: "list", values: [* core-expr] } +map-expr = { kind: "map", entries: [* [key: core-expr, value: core-expr]] } +if-expr = { + kind: "if", + predicate: core-predicate, + then: core-expr, + else: core-expr, +} + +core-predicate = true-predicate / false-predicate / not-predicate / + all-predicate / any-predicate / compare-predicate / + call-predicate / obstruction-predicate + +true-predicate = { kind: "true" } +false-predicate = { kind: "false" } +not-predicate = { kind: "not", value: core-predicate } +all-predicate = { kind: "all", values: [+ core-predicate] } +any-predicate = { kind: "any", values: [+ core-predicate] } +compare-predicate = { + kind: "compare", + op: "==" / "!=" / "<" / "<=" / ">" / ">=", + left: core-expr, + right: core-expr, +} +call-predicate = { + kind: "call", + predicate: tstr, + args: [* core-expr], +} +obstruction-predicate = { + kind: "obstruction", + coordinate: failure-ident, + payload: core-expr, +} + +input-constraint = { + coordinate: tstr, + source: "where" / "compiler", + predicate: core-predicate, +} + +; --- intents, blocks, and nodes ----------------------------------------- + +core-intent = { + input: core-type-ref, + output: core-type-ref, + requiredOperationProfile: tstr, + inputConstraints: [* input-constraint], + coreEvaluationBudget: core-budget, + body: core-block, + ? optic: core-optic, +} + +core-budget = { + maxSteps: uint, + maxAllocatedBytes: uint, + maxOutputBytes: uint, +} + +core-optic = { + opticKind: "revelation" / "affectReintegration", + boundaryKind: "projection" / "affect", + apertureRequirement: aperture-requirement, + supportPolicy: tstr, + lossDisposition: tstr, +} + +core-block = { + locals: [* local-ref], + nodes: [* core-node], + result: core-expr, +} + +core-node = let-node / require-node / effect-node / guard-node / branch-node / + for-node / match-node / proof-obligation-node + +let-node = { + kind: "let", + binding: local-ref, + value: core-expr, +} +require-node = { + kind: "require", + predicate: core-predicate, + onFailure: require-failure-arm, +} +require-failure-arm = terminal-require-failure / + continue-obstructed-require-failure +terminal-require-failure = { + kind: "terminal", + reason: obstruction-reason, +} +continue-obstructed-require-failure = { + kind: "continueObstructed", + reason: obstruction-reason, +} +obstruction-reason = { + reasonKind: tstr, + payload: { * tstr => core-expr }, +} +effect-node = { + kind: "effect", + binding: local-ref, + effect: tstr, + input: core-expr, + obstructionMap: { * failure-ident => obstruction-arm }, +} +obstruction-arm = { + binder: local-ref, + value: core-expr, +} +guard-node = { + kind: "guard", + predicate: core-predicate, + obstruction: core-expr, +} +branch-node = { + kind: "branch", + predicate: core-predicate, + then: core-block, + else: core-block, +} +for-node = { + kind: "for", + binder: local-ref, + iter: core-expr, + bound: core-bound, + body: core-block, +} +match-node = { + kind: "match", + scrutinee: core-expr, + arms: [+ match-block-arm], +} +match-block-arm = { + case: tstr, + ? binder: local-ref, + body: core-block, +} +proof-obligation-node = { + kind: "proof", + coordinate: tstr, + predicate: core-predicate, +} + +core-bound = literal-bound / coordinate-bound +literal-bound = { kind: "literal", value: uint } +coordinate-bound = { kind: "coordinate", ref: tstr } + +; Shared resource-ref, sha256-digest, failure-ident, aperture-requirement, and +; core-type-ref are defined once in edict-common.cddl. + +; --- edict-lawpack.cddl --- +; edict-lawpack.cddl +; Canonical schema for the Edict lawpack manifest and export surface. +; Authoritative byte encoding: edict.canonical-cbor/v1. JSON in the prose specs +; is a review rendering generated from this schema (EDICT-ABI-NODUP-001). + +lawpack-manifest = { + apiVersion: "edict.lawpack/v1", + id: tstr, + version: tstr, + acceptedCoreAbi: [+ tstr], + dependencies: [* lawpack-dep], ; acyclic, digest-locked (EDICT-LAWPACK-DAG-001) + exports: resource-ref, + ? targetAdapters: [+ target-adapter], ; required only if any runtime effect exists + ? helperComponent: executable-component, ; executable helpers carry their own sandbox+fuel + verifier: verifier, ; classified: declarative or executable + compatibility: resource-ref, + conformanceFixtureCorpus: resource-ref, +} + +; A verifier is either a declarative ruleset (no runtime) or an executable +; component. An executable verifier MUST carry its own sandbox and fuel model, +; so the schema enforces that no executable component is left unbounded +; (EDICT-ABI-VERIFIER-BOUND-001). +verifier = declarative-verifier / executable-verifier +declarative-verifier = { class: "declarative", ruleset: resource-ref } +executable-verifier = { + class: "executable", + component: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, +} + +; Any executable component is bounded by its own sandbox + fuel model. +executable-component = { + component: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, +} + +lawpack-dep = { id: tstr, version: tstr, digest: sha256-digest } + +; Adapter selection keys SOLELY off the digest-locked `acceptedTargetProfile` +; (its `id` is the profile id; its `digest` pins the exact profile/version). There +; are no independent display strings that could disagree with the lock, so a +; resolver cannot bind an adapter to one target while the lock proves another +; (EDICT-LAWPACK-ADAPTER-TARGETIR-001). +target-adapter = { + acceptedTargetProfile: resource-ref, ; digest-locked, authoritative selector + acceptedTargetIr: resource-ref, ; digest-locked + adapter: resource-ref, +} + +; Shared types resource-ref and sha256-digest are defined once in +; edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- export surface ------------------------------------------------------ + +lawpack-exports = { + types: [* exported-type], + constants: [* exported-constant], + pureFunctions: [* pure-function], + effects: [* semantic-effect], + obstructions: [* obstruction-def], + ; keyed by operation-profile coordinate → uniqueness enforced + ; (EDICT-ABI-OPPROFILE-UNIQUE-001) + ; operation-profile records this lawpack exports (optic templates that + ; `implements`/`profile` clauses resolve against). operation-profile is + ; defined in edict-common.cddl (EDICT-ABI-OPPROFILE-SLOT-001). + operationProfiles: { * tstr => operation-profile }, ; keyed by coordinate +} + +exported-type = { coordinate: tstr, definition: core-type-ref } +exported-constant = { coordinate: tstr, type: core-type-ref, value: any } + +; A pure helper is a discriminated union by `source`, so the schema itself +; guarantees an implementation exists (EDICT-LAWPACK-PURE-IMPL-001): +; - "edict": authored in Edict/Core; the Core body is carried inline (hashed +; with the export surface). The schema requires the `body` field. +; - "component": implemented outside Edict; carries no inline body and instead +; carries its own digest-locked `implementation` (sandbox + fuel). It does +; not depend on the optional manifest-level helperComponent. +pure-function = edict-pure-function / component-pure-function + +pure-function-common = ( + coordinate: tstr, + typeParameters: [* tstr], + parameterTypes: [* core-type-ref], ; all bounded + returnType: core-type-ref, ; bounded + costTemplate: tstr, + determinismClass: "total" / "total-with-typed-diagnostic", +) + +edict-pure-function = { + pure-function-common, + source: "edict", + body: core-fn-body, ; inline, hash-significant +} + +component-pure-function = { + pure-function-common, + source: "component", + ; the digest-locked component implementing this helper. Required at the schema + ; level so a component helper can never validate without a hash-bound, + ; sandbox+fuel-described implementation (EDICT-LAWPACK-PURE-IMPL-001). + implementation: executable-component, +} + +; core-fn-body is defined by edict-core.cddl and assembled with this lawpack +; schema. It is a pure Core function body, not an effect-capable core-block. + +semantic-effect = { + coordinate: tstr, + typeParameters: [* tstr], + inputType: core-type-ref, ; bounded + outputType: core-type-ref, ; bounded + executionClass: "proofOnly" / "runtime", ; orthogonal to writeClass + effectKindHint: effect-kind, + footprintObligation: tstr, + costObligation: tstr, + effectFailures: { * failure-ident => effect-failure-body }, ; keyed by coordinate; unique + guardSupport: bool, +} + +obstruction-def = { + coordinate: tstr, + authorityClass: authority-class, + payloadSchema: core-type-ref, ; typed, bounded (may be empty record) +} + +; effect-failure-body, effect-kind, authority-class, and core-type-ref are defined +; once in edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- edict-target-profile.cddl --- +; edict-target-profile.cddl +; Canonical schema for the Edict target profile manifest. +; Authoritative byte encoding: edict.canonical-cbor/v1 +; (see SPEC_continuum-contract-bundle-v1.md). JSON in the prose specs is a +; review rendering generated from this schema; this CDDL is the single source +; of truth (EDICT-ABI-NODUP-001). + +target-profile-manifest = { + apiVersion: "edict.target-profile/v1", + id: tstr, ; e.g. "echo.dpo" + version: tstr, ; e.g. "1" + acceptedCoreAbi: [+ tstr], ; e.g. ["edict.core/v1"] + + intrinsics: resource-ref, + intrinsicNamespace: tstr, + ; publishes this profile's operation-profile records (optic templates that + ; `profile`/`implements` clauses resolve against). References an + ; operation-profiles-document (EDICT-ABI-OPPROFILE-SLOT-001). + operationProfiles: resource-ref, + footprintAlgebra: resource-ref, + costAlgebra: resource-ref, + targetIr: resource-ref, + obstructionTaxonomy: resource-ref, + verifier: resource-ref, + lowerer: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, + + ; fields the language spec requires of every profile + bundleProfile: resource-ref, + generatedArtifactProfiles: [* resource-ref], + canonicalEncodingRules: resource-ref, + ; Reserved/deferred: will list accepted lawpack-adapter ABI ids once that + ; byte-level ABI (edict.lawpack-adapter/v1) is specified. The schema enforces + ; emptiness now — the type is the empty array, so non-empty values are + ; rejected, not merely discouraged (EDICT-ABI-LAWPACK-ADAPTER-DEFER-001). + ? acceptedLawpackAdapterAbi: [], + diagnosticAbi: resource-ref, + + ; application doctrine + applicationModel: "atomic", + readConsistency: "application-snapshot" / tstr, + guardEvaluation: "precommit-atomic" / tstr, + obstructionRollback: "no-visible-effects" / tstr, + multiTarget: bool, + ; whether the target can evaluate precommit postcondition (`guarantee`) checks + ; inside the atomic application unit (EDICT-TARGET-POSTCOND-001) + postconditionSupport: bool, + + deterministicExecution: resource-ref, + conformanceFixtureCorpus: resource-ref, +} + +; Shared types resource-ref and sha256-digest are defined once in +; edict-common.cddl and assembled with this schema by the build +; (EDICT-ABI-NODUP-001). They are not redefined here. + +; --- intrinsic signature ------------------------------------------------- +; The artifact referenced by the manifest's `intrinsics` resource-ref is the +; intrinsic-signature corpus document below. Its layout is fixed so two +; independent profiles validate/hash the corpus identically +; (EDICT-ABI-INTRINSICS-DOC-001). + +; intrinsics is a MAP keyed by coordinate, so the schema itself enforces +; coordinate uniqueness. A provider receives the resolved corpus as a +; digest-bound semantic input and resolves coordinates within that artifact. +; Each map key MUST equal its record's `coordinate` field +; (EDICT-ABI-INTRINSIC-UNIQUE-001). +intrinsics-document = { + apiVersion: "edict.target-profile.intrinsics/v1", + intrinsics: { * tstr => intrinsic }, +} + +; The artifact referenced by the manifest's `operationProfiles` resource-ref. +; operation-profile / optic-template are defined in edict-common.cddl. Keyed by +; coordinate so resolution can't pick between two same-coordinate profiles +; (EDICT-ABI-OPPROFILE-SLOT-001, EDICT-ABI-OPPROFILE-UNIQUE-001). +operation-profiles-document = { + apiVersion: "edict.target-profile.operation-profiles/v1", + profiles: { * tstr => operation-profile }, +} + +; A typed pre-lowering question that can be proposed by Watson or an agent and +; checked by the compiler. It is canonical-CBOR encoded under +; `edict.lowering-requirements/v1`; the compiler checks this artifact, not the +; prose that produced it. +lowering-requirements = { + apiVersion: "edict.lowering-requirements/v1", + operationProfile: tstr, + semanticEffects: [* semantic-effect-requirement], + requiredWriteClasses: [* write-class], + guardKinds: [* guard-kind], + atomicity: atomicity-requirement, + postconditionSupport: bool, + obstructionCoordinates: [* tstr], + footprintObligations: [* tstr], + costObligations: [* tstr], + opticContract: tstr, +} + +semantic-effect-requirement = { + coordinate: tstr, + writeClass: write-class, + guardKinds: [* guard-kind], + obstructionCoordinates: [* tstr], + footprintObligations: [* tstr], + costObligations: [* tstr], +} + +write-class = "none" / "read" / "create" / "ensure" / "append" / + "replace" / "delete" / tstr +guard-kind = "precommit-atomic" / tstr +atomicity-requirement = "atomic" / tstr + +; A genuine union: pure constructors carry no effect kind or failures; effect +; intrinsics must (EDICT-TARGET-INTRINSIC-CLASS-001). The schema enforces this, +; not a comment. + +; The intrinsic's coordinate is the intrinsics map KEY, not a value field, so the +; key and coordinate can never disagree (EDICT-ABI-INTRINSIC-UNIQUE-001). +intrinsic = pure-intrinsic / effect-intrinsic + +pure-intrinsic = { + intrinsicClass: "pure", + typeParameters: [* tstr], + argumentTypes: [* core-type-ref], + returnType: core-type-ref, + guardSupport: false, + footprintTemplate: tstr, + costTemplate: tstr, + writeClass: "none", +} + +effect-intrinsic = { + intrinsicClass: "effect", + typeParameters: [* tstr], + argumentTypes: [* core-type-ref], + returnType: core-type-ref, + effectKind: effect-kind, + ; map keyed by failure coordinate (failure-ident); the failure coordinate is + ; the key, not a value field, so uniqueness is structural + ; (EDICT-ABI-FAILURE-UNIQUE-001). + effectFailures: { * failure-ident => effect-failure-body }, + guardSupport: bool, + footprintTemplate: tstr, + costTemplate: tstr, + writeClass: "read" / "create" / "ensure" / "append" / "replace" / + "delete" / "custom", + canParticipateInAtomicGuard: bool, +} + +; effect-failure-body, effect-kind, authority-class, and core-type-ref are defined +; once in edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- edict-authority-facts.cddl --- +; edict-authority-facts.cddl +; Canonical schema for the first compiler-context authority-facts document. +; Authoritative byte encoding: edict.canonical-cbor/v1. +; +; This schema is assembled with edict-common.cddl so source.digest uses the +; shared sha256-digest typed value. JSON is a review/input rendering: its +; `sha256:<64 hex>` source digest is projected to [`sha256`, 32 raw bytes] on +; the wire, and its fact arrays project to the coordinate-keyed maps below. + +authority-facts = { + apiVersion: "edict.authority-facts/v1", + source: authority-fact-source, + operationProfiles: { * tstr => authority-operation-profile-fact }, + effectWriteClasses: { * tstr => authority-write-class }, + budgets: { * tstr => authority-budget-fact }, +} + +authority-fact-source = { + kind: "lawpack" / "targetProfile", + coordinate: tstr, + digest: sha256-digest, +} + +; The map key is the source operation-profile coordinate. It is not repeated in +; the value, so a key and embedded coordinate cannot disagree. Allowed write +; classes are a canonical map-set: the class is the unique key and null is the +; unit marker. Canonical CBOR fixes key order without a second ordering rule. +authority-operation-profile-fact = { + core: tstr, + allowedWriteClasses: { * authority-write-class => null }, +} + +; The effectWriteClasses map key is the semantic effect coordinate. The budgets +; map key is the source budget coordinate. Canonical CBOR map-key uniqueness +; makes duplicate fact coordinates structurally unrepresentable. +authority-budget-fact = { + maxSteps: uint, + maxAllocatedBytes: uint, + maxOutputBytes: uint, +} + +; AuthorityFactsDocument v1 intentionally accepts only the write classes the +; current compiler model can consume. `custom` is the sole v1 custom spelling; +; arbitrary target-profile extension strings do not enter this compiler path. +authority-write-class = "none" / "read" / "create" / "ensure" / "append" / + "replace" / "delete" / "custom" + +; --- edict-target-ir.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-target-ir.cddl +; Canonical schema for the Edict-owned Target IR artifact envelope. +; Authoritative byte encoding: edict.canonical-cbor/v1. +; +; This schema is assembled with edict-common.cddl and edict-core.cddl. It +; deliberately reuses Core expressions, predicates, budgets, local references, +; obstruction reasons, and obstruction arms so the schema matches the value +; emitted by the canonical Target IR encoder rather than restating those types. +; It describes the structural shape of valid lowering-produced artifacts. The +; lowering and encoder contracts separately enforce semantic identifier rules +; and canonical ordering/deduplication for set-like values. + +; Target IR encoding rejects an empty target-profile coordinate before bytes +; exist, so this root tightens the shared structural resource-ref accordingly. +target-ir-resource-ref = { + id: tstr .regexp "(?s).+", + digest: sha256-digest, +} + +target-ir-artifact = { + kind: "targetIrArtifact", + domain: tstr, + targetProfile: target-ir-resource-ref, + sourceCoreCoordinate: tstr, + intents: { * tstr => target-ir-intent }, +} + +target-ir-intent = { + operationProfile: tstr, + inputConstraints: [* input-constraint], + coreEvaluationBudget: core-budget, + requirements: [* target-ir-requirement], + steps: [* target-ir-step], + result: core-expr, +} + +target-ir-requirement = { + id: tstr, + predicate: core-predicate, + onFailure: require-failure-arm, +} + +target-ir-step = { + id: tstr, + binding: local-ref, + effect: tstr, + targetIntrinsic: tstr, + input: core-expr, + obstructionFailures: [* failure-ident], + obstructionArms: { * failure-ident => obstruction-arm }, +} diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/manifest.json b/crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/manifest.json new file mode 100644 index 00000000..fe91f629 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/contracts/v1/manifest.json @@ -0,0 +1,80 @@ +{ + "apiVersion": "edict.provider-contract-pack/v1", + "coordinate": "edict.provider-contract-pack.cddl@1", + "license": "Apache-2.0", + "schema": { + "bytesHex": "3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d70726f76696465722d636f6e7472616374732e6364646c0a3b2047656e6572617465642066726f6d2045646963742d6f776e65642041424920667261676d656e74732e20444f204e4f5420454449542e0a0a3b202d2d2d2065646963742d636f6d6d6f6e2e6364646c202d2d2d0a3b2065646963742d636f6d6d6f6e2e6364646c0a3b20536861726564204344444c20747970657320666f722074686520456469637420414249732c20646566696e6564204f4e4345206865726520736f20746865792063616e6e6f742064726966740a3b202845444943542d4142492d4e4f4455502d303031292e2054776f2067726f7570733a0a3b2020202d207265736f757263652d7265662c207368613235362d6469676573742c206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c0a3b2020202020636f72652d747970652d7265663a20617373656d626c656420776974682065646963742d7461726765742d70726f66696c652e6364646c20616e640a3b202020202065646963742d6c61777061636b2e6364646c20627920746865206275696c643b2074686f736520736368656d617320646f206e6f74207265646566696e65207468656d2e0a3b2020202d206f7065726174696f6e2d70726f66696c652c206f707469632d74656d706c6174652c2061706572747572652d726571756972656d656e7420616e6420746865697220726566733a0a3b2020202020636f6e73756d65642062792074686520436f72652f6f70746963206c61796572202865646963742d636f72652e6364646c2920616e64207265666572656e636564206279207468650a3b20202020206c616e67756167652f7461726765742d70726f66696c652073706563732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a3b2041206e6f726d617469766520737562636f6d706f6e656e74207265666572656e636564206279206964656e7469747920706c7573206469676573742e204d616e696665737473206e657665720a3b20656d626564207468656972206f776e2073656c662d64696765737420696e20746865697220707265696d616765202845444943542d434f52452d53454c46484153482d303031292e0a7265736f757263652d726566203d207b2069643a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20446967657374732061726520617574686f726974617469766520617320747970656420627974652076616c7565732c206e657665722068657820737472696e67732e20526576696577204a534f4e0a3b2072656e64657273207468697320617320227368613235363a3c3634206c6f77657263617365206865783e22202845444943542d4449474553542d574952452d303031292e0a7368613235362d646967657374203d205b20616c676f726974686d3a2022736861323536222c2062797465733a2062737472202e73697a65203332205d0a0a3b2041206e616d6564206c6f772d6c6576656c206661696c75726520616e206566666563742063616e2072616973652e2054686520736f75726365206f62737472756374696f6e206d61700a3b2062696e64732069742028627920636f6f7264696e6174652920616e6420636f6e73747275637473206120747970656420646f6d61696e206f62737472756374696f6e2066726f6d206974730a3b207061796c6f6164202845444943542d4142492d4641494c5552452d4e414d45442d303031292e0a3b20416e20656666656374277320606566666563744661696c7572657360206c697374204d555354206861766520756e697175652060636f6f7264696e61746560733a2073696e6365207468650a3b206f62737472756374696f6e206d6170206973206b6579656420627920636f6f7264696e6174652c2074776f206661696c757265732073686172696e67206120636f6f7264696e61746520286576656e0a3b207769746820646966666572656e7420617574686f72697479436c6173732f7061796c6f61645479706529206d616b652065786861757374697665206d617070696e6720616e642062696e6465720a3b20747970696e6720616d626967756f757320616e64206172652072656a6563746564202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a3b0a3b2045666665637473206361727279207468656972206661696c757265732061732061206d617020607b206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d600a3b202873656520746865207461726765742f6c61777061636b2065666665637420736368656d6173292e20546865206661696c75726520636f6f7264696e61746520697320746865206d61700a3b204b45592c20736f206974206973206e6f7420726570656174656420696e2074686520626f647920616e642063616e6e6f74206469736167726565207769746820746865206b65792e0a6566666563742d6661696c7572652d626f6479203d207b0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164547970653a20636f72652d747970652d7265662c202020202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b2041206661696c75726520636f6f7264696e617465206d7573742062652061206261726520456469637420606964656e746020286c65747465722f756e64657273636f7265207468656e0a3b206c6574746572732f6469676974732f756e64657273636f7265732920414e44206d757374206e6f742062652061207265736572766564206b6579776f72642028652e672e2060656c7365602c0a3b20606261736973602c20607768657265602c206072657175697265602c2060666f72602c2060696660292e2054686520736f75726365206f62737472756374696f6e2d6d6170204c4853206f6e6c790a3b20616363657074732061206e6f6e2d6b6579776f726420606964656e74602c20736f20612068797068656e2f646f742f6b6579776f726420636f6f7264696e61746520776f756c642062650a3b204142492d76616c69642079657420696d706f737369626c6520746f206d617020657868617573746976656c7920696e20736f757263652e20546865207265676578206361707475726573207468650a3b206c65786963616c2073686170653b206b6579776f7264206578636c7573696f6e20697320616e206164646974696f6e616c2076616c69646174696f6e2072756c650a3b202845444943542d4142492d4641494c5552452d4944454e542d303031292e0a6661696c7572652d6964656e74203d2074737472202e72656765787020225b412d5a612d7a5f5d5b412d5a612d7a302d395f5d2a220a0a6566666563742d6b696e64203d20227265616422202f202263726561746522202f2022656e7375726522202f20227265706c61636522202f202264656c65746522202f0a202020202020202020202020202022617070656e6422202f202272656475636522202f202273656d616e7469632e656d697422202f2022637573746f6d220a0a617574686f726974792d636c617373203d2022646f6d61696e4d61707061626c6522202f20227061727469636970616e744f776e656422202f2022696e746567726974794661756c7422202f0a202020202020202020202020202020202020227265736f757263654661756c7422202f2022696e7465726e616c4661756c74220a0a636f72652d747970652d726566203d20747374722020203b2063616e6f6e6963616c20436f7265207479706520636f6f7264696e6174650a0a3b20416e206f7065726174696f6e2070726f66696c6520737570706c69657320746865206f707469632074656d706c617465206120436f726520696e74656e74207265736f6c766573206974730a3b206f707469634b696e642f626f756e646172794b696e642f737570706f7274506f6c6963792f6c6f7373446973706f736974696f6e2066726f6d2e205461726765742070726f66696c657320616e640a3b206c61777061636b73207075626c6973682074686573652061732061206d617020607b20636f6f7264696e617465203d3e206f7065726174696f6e2d70726f66696c65207d602c20736f207468650a3b20636f6f7264696e61746520697320746865204b45592c206e6f7420612076616c7565206669656c64202845444943542d4f505449432d54454d504c4154452d4f574e45522d3030312c0a3b2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65203d207b0a20206f7074696354656d706c6174653a206f707469632d74656d706c6174652c0a20206566666563745072656469636174653a20747374722c20202020202020202020203b20636f6f7264696e617465206f6620746865206f7065726174696f6e2d6d6f6465207072656469636174650a7d0a0a6f707469632d74656d706c617465203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a2020737570706f7274506f6c6963793a20747374722c202020202020202020202020203b2063616e6f6e6963616c20737570706f72742d706f6c69637920636f6f7264696e6174650a20206c6f7373446973706f736974696f6e3a20747374722c20202020202020202020203b2063616e6f6e6963616c206c6f73732d646973706f736974696f6e20636f6f7264696e6174650a20203f20626173697354656d706c6174653a20747374722c20202020202020202020203b206f7074696f6e616c206469676573742d6c6f636b65642062617369732074656d706c61746520636f6f72640a20203b2074686520617065727475726520726571756972656d656e7420746869732074656d706c61746520737570706c6965732e205265717569726564207768656e207468652074656d706c6174650a20203b2069732074686520736f75726365206f66206120436f7265206f707469632773206170657274757265526571756972656d656e742028692e652e2074686520696e74656e7420686173206e6f0a20203b20736f757263652060666f6f747072696e74203c3d202e2e2e60292c2073696e6365206170657274757265526571756972656d656e74206973206d616e6461746f727920696e20436f72650a20203b202845444943542d4f505449432d41504552545552452d5245462d303031292e0a20203f206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a7d0a0a3b206170657274757265526571756972656d656e742069732061207479706564207265666572656e63652c206e65766572206120667265652d666f726d20737472696e672e2041207265766965770a3b2072656e646572696e67206d61792073686f772069747320636f6f7264696e617465202845444943542d4f505449432d41504552545552452d5245462d303031292e0a61706572747572652d726571756972656d656e74203d20666f6f747072696e742d6365696c696e672d726566202f2061627374726163742d666f6f747072696e742d6f626c69676174696f6e2d7265660a666f6f747072696e742d6365696c696e672d726566203d207b206b696e643a2022666f6f747072696e744365696c696e67222c207265663a2074737472207d0a61627374726163742d666f6f747072696e742d6f626c69676174696f6e2d726566203d207b206b696e643a20226162737472616374466f6f747072696e744f626c69676174696f6e222c207265663a2074737472207d0a0a3b202d2d2d2065646963742d636f72652e6364646c202d2d2d0a3b2065646963742d636f72652e6364646c0a3b204e6f726d617469766520736368656d6120666f722074686520456469637420436f72652076312073656d616e746963206d6f64656c2e0a3b0a3b2053636f706520626f756e646172793a20746869732066696c6520646566696e657320436f7265206d65616e696e6720616e6420736368656d61207368617065206f6e6c792e20497420646f65730a3b206e6f7420646566696e6520612063616e6f6e6963616c20656e636f6465722c20436f7265206d6f64756c652068617368206669656c64732c20686173682066697874757265732c207461726765740a3b206c6f776572696e672c2061646d697373696f6e2062756e646c65732c206f72207461726765742d6f776e65642049522e0a0a636f72652d6d6f64756c65203d207b0a202061706956657273696f6e3a202265646963742e636f72652f7631222c0a2020636f6f7264696e6174653a20747374722c0a2020696d706f7274733a205b2a20636f72652d696d706f72745d2c0a202074797065733a207b202a2074737472203d3e20636f72652d74797065207d2c0a2020696e74656e74733a207b202b2074737472203d3e20636f72652d696e74656e74207d2c0a20207265717569726564436f72654361706162696c69746965733a205b2a20747374725d2c0a7d0a0a636f72652d696d706f7274203d207b0a20206b696e643a20226c61777061636b22202f202274617267657422202f2022636f7265222c0a20207265663a207265736f757263652d7265662c0a20203f20616c6961733a20747374722c0a7d0a0a3b202d2d2d207479706573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d74797065203d20636f72652d7363616c61722d74797065202f20636f72652d7265636f72642d74797065202f20636f72652d76617269616e742d74797065202f0a202020202020202020202020636f72652d6f7074696f6e2d74797065202f20636f72652d6c6973742d74797065202f20636f72652d6d61702d74797065202f0a202020202020202020202020636f72652d6361706162696c6974792d7265662d747970650a0a636f72652d7363616c61722d74797065203d20636f72652d626f6f6c2d74797065202f20636f72652d696e742d74797065202f20636f72652d737472696e672d74797065202f0a20202020202020202020202020202020202020636f72652d62797465732d74797065202f20636f72652d756e69742d747970650a0a636f72652d626f6f6c2d74797065203d207b206b696e643a2022426f6f6c22207d0a636f72652d756e69742d74797065203d207b206b696e643a2022556e697422207d0a636f72652d696e742d74797065203d207b0a20206b696e643a202249363422202f202255363422202f202249333222202f202255333222202f202249313622202f202255313622202f2022493822202f20225538222c0a7d0a636f72652d737472696e672d74797065203d207b0a20206b696e643a2022537472696e67222c0a20206d61783a2075696e742c0a202063616e6f6e6963616c3a2022756e69636f64652d7363616c61722d6e666322202f20227261772d75746638222c0a7d0a636f72652d62797465732d74797065203d207b0a20206b696e643a20224279746573222c0a20206d61783a2075696e742c0a7d0a636f72652d7265636f72642d74797065203d207b0a20206b696e643a20225265636f7264222c0a20206669656c64733a207b202a2074737472203d3e20636f72652d747970652d726566207d2c0a7d0a636f72652d76617269616e742d74797065203d207b0a20206b696e643a202256617269616e74222c0a202063617365733a207b202b2074737472203d3e2076617269616e742d636173652d626f6479207d2c0a7d0a76617269616e742d636173652d626f6479203d207b0a20203f207061796c6f61643a20636f72652d747970652d7265662c0a7d0a636f72652d6f7074696f6e2d74797065203d207b0a20206b696e643a20224f7074696f6e222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a636f72652d6c6973742d74797065203d207b0a20206b696e643a20224c697374222c0a20206974656d3a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6d61702d74797065203d207b0a20206b696e643a20224d6170222c0a20206b65793a20636f72652d747970652d7265662c0a202076616c75653a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6361706162696c6974792d7265662d74797065203d207b0a20206b696e643a20224361706162696c697479526566222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a0a3b20636f72652d747970652d72656620697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d612e0a0a3b202d2d2d207265666572656e63657320616e642076616c756573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a3b204c6f63616c206964656e7469747920697320616c7068612d737461626c652e20606964602069732074686520636f6d70696c65722d6f776e6564206c6f63616c20636f6f7264696e6174653b0a3b2060616c7068614e616d656020697320746865206e6f726d616c697a65642068756d616e2f6465627567206e616d652e20536f757263652062696e646572207370656c6c696e67206973206e6f740a3b206964656e746974792e0a6c6f63616c2d726566203d207b0a202069643a20747374722c0a2020616c7068614e616d653a20747374722c0a2020747970653a20636f72652d747970652d7265662c0a7d0a0a636f72652d76616c7565203d20636f72652d6e756c6c2d76616c7565202f20636f72652d626f6f6c2d76616c7565202f20636f72652d696e742d76616c7565202f0a20202020202020202020202020636f72652d737472696e672d76616c7565202f20636f72652d62797465732d76616c7565202f20636f72652d7265636f72642d76616c7565202f0a20202020202020202020202020636f72652d76617269616e742d76616c7565202f20636f72652d6c6973742d76616c7565202f20636f72652d6d61702d76616c7565202f0a20202020202020202020202020636f72652d6361706162696c6974792d76616c75650a0a636f72652d6e756c6c2d76616c7565203d207b206b696e643a20226e756c6c22207d0a636f72652d626f6f6c2d76616c7565203d207b206b696e643a2022626f6f6c222c2076616c75653a20626f6f6c207d0a636f72652d696e742d76616c7565203d207b206b696e643a2022696e74222c2077696474683a20747374722c2076616c75653a20696e74207d0a636f72652d737472696e672d76616c7565203d207b206b696e643a2022737472696e67222c2076616c75653a2074737472207d0a636f72652d62797465732d76616c7565203d207b206b696e643a20226279746573222c2076616c75653a2062737472207d0a636f72652d7265636f72642d76616c7565203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d76616c7565207d207d0a636f72652d76617269616e742d76616c7565203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d76616c75652c0a7d0a636f72652d6c6973742d76616c7565203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d76616c75655d207d0a636f72652d6d61702d76616c7565203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d76616c75652c2076616c75653a20636f72652d76616c75655d5d207d0a636f72652d6361706162696c6974792d76616c7565203d207b0a20206b696e643a20226361706162696c697479222c0a2020726563656970743a207368613235362d6469676573742c0a7d0a0a3b2045646963742d617574686f72656420707572652068656c70657273207573652061207075726520436f72652066756e6374696f6e20626f64792e2054686520626f64792063616e2062696e640a3b20707572652065787072657373696f6e7320616e642072657475726e20616e2065787072657373696f6e2c206275742069742063616e6e6f7420636f6e7461696e20436f7265206566666563742c0a3b2067756172642c206272616e63682c206c6f6f702c206d617463682d6e6f64652c206f722070726f6f662d6f626c69676174696f6e206e6f6465732e0a636f72652d666e2d626f6479203d207b0a2020706172616d733a205b2a206c6f63616c2d7265665d2c0a2020626f64793a20636f72652d707572652d626c6f636b2c0a7d0a0a636f72652d707572652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a202062696e64696e67733a205b2a20707572652d6c65742d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a707572652d6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a0a3b202d2d2d2065787072657373696f6e7320616e642070726564696361746573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d65787072203d206c6f63616c2d65787072202f20636f6e73742d65787072202f207265636f72642d65787072202f206669656c642d65787072202f0a20202020202020202020202076617269616e742d65787072202f206d617463682d65787072202f2063616c6c2d65787072202f206c6973742d65787072202f206d61702d65787072202f0a20202020202020202020202069662d657870720a0a6c6f63616c2d65787072203d207b206b696e643a20226c6f63616c222c207265663a206c6f63616c2d726566207d0a636f6e73742d65787072203d207b206b696e643a2022636f6e7374222c2076616c75653a20636f72652d76616c7565207d0a7265636f72642d65787072203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d65787072207d207d0a6669656c642d65787072203d207b206b696e643a20226669656c64222c20626173653a20636f72652d657870722c206669656c643a2074737472207d0a76617269616e742d65787072203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d657870722c0a7d0a6d617463682d65787072203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d61726d5d2c0a7d0a6d617463682d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d657870722c0a7d0a63616c6c2d65787072203d207b0a20206b696e643a202263616c6c222c0a202063616c6c65653a20747374722c0a202074797065417267733a205b2a20636f72652d747970652d7265665d2c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6c6973742d65787072203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d657870725d207d0a6d61702d65787072203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d657870722c2076616c75653a20636f72652d657870725d5d207d0a69662d65787072203d207b0a20206b696e643a20226966222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d657870722c0a2020656c73653a20636f72652d657870722c0a7d0a0a636f72652d707265646963617465203d20747275652d707265646963617465202f2066616c73652d707265646963617465202f206e6f742d707265646963617465202f0a2020202020202020202020202020202020616c6c2d707265646963617465202f20616e792d707265646963617465202f20636f6d706172652d707265646963617465202f0a202020202020202020202020202020202063616c6c2d707265646963617465202f206f62737472756374696f6e2d7072656469636174650a0a747275652d707265646963617465203d207b206b696e643a20227472756522207d0a66616c73652d707265646963617465203d207b206b696e643a202266616c736522207d0a6e6f742d707265646963617465203d207b206b696e643a20226e6f74222c2076616c75653a20636f72652d707265646963617465207d0a616c6c2d707265646963617465203d207b206b696e643a2022616c6c222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a616e792d707265646963617465203d207b206b696e643a2022616e79222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a636f6d706172652d707265646963617465203d207b0a20206b696e643a2022636f6d70617265222c0a20206f703a20223d3d22202f2022213d22202f20223c22202f20223c3d22202f20223e22202f20223e3d222c0a20206c6566743a20636f72652d657870722c0a202072696768743a20636f72652d657870722c0a7d0a63616c6c2d707265646963617465203d207b0a20206b696e643a202263616c6c222c0a20207072656469636174653a20747374722c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6f62737472756374696f6e2d707265646963617465203d207b0a20206b696e643a20226f62737472756374696f6e222c0a2020636f6f7264696e6174653a206661696c7572652d6964656e742c0a20207061796c6f61643a20636f72652d657870722c0a7d0a0a696e7075742d636f6e73747261696e74203d207b0a2020636f6f7264696e6174653a20747374722c0a2020736f757263653a2022776865726522202f2022636f6d70696c6572222c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a3b202d2d2d20696e74656e74732c20626c6f636b732c20616e64206e6f646573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d696e74656e74203d207b0a2020696e7075743a20636f72652d747970652d7265662c0a20206f75747075743a20636f72652d747970652d7265662c0a202072657175697265644f7065726174696f6e50726f66696c653a20747374722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020626f64793a20636f72652d626c6f636b2c0a20203f206f707469633a20636f72652d6f707469632c0a7d0a0a636f72652d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a636f72652d6f70746963203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a20206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a2020737570706f7274506f6c6963793a20747374722c0a20206c6f7373446973706f736974696f6e3a20747374722c0a7d0a0a636f72652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a20206e6f6465733a205b2a20636f72652d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a636f72652d6e6f6465203d206c65742d6e6f6465202f20726571756972652d6e6f6465202f206566666563742d6e6f6465202f2067756172642d6e6f6465202f206272616e63682d6e6f6465202f0a202020202020202020202020666f722d6e6f6465202f206d617463682d6e6f6465202f2070726f6f662d6f626c69676174696f6e2d6e6f64650a0a6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a726571756972652d6e6f6465203d207b0a20206b696e643a202272657175697265222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a726571756972652d6661696c7572652d61726d203d207465726d696e616c2d726571756972652d6661696c757265202f0a20202020202020202020202020202020202020202020636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c7572650a7465726d696e616c2d726571756972652d6661696c757265203d207b0a20206b696e643a20227465726d696e616c222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c757265203d207b0a20206b696e643a2022636f6e74696e75654f627374727563746564222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a6f62737472756374696f6e2d726561736f6e203d207b0a2020726561736f6e4b696e643a20747374722c0a20207061796c6f61643a207b202a2074737472203d3e20636f72652d65787072207d2c0a7d0a6566666563742d6e6f6465203d207b0a20206b696e643a2022656666656374222c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4d61703a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a6f62737472756374696f6e2d61726d203d207b0a202062696e6465723a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a67756172642d6e6f6465203d207b0a20206b696e643a20226775617264222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f62737472756374696f6e3a20636f72652d657870722c0a7d0a6272616e63682d6e6f6465203d207b0a20206b696e643a20226272616e6368222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d626c6f636b2c0a2020656c73653a20636f72652d626c6f636b2c0a7d0a666f722d6e6f6465203d207b0a20206b696e643a2022666f72222c0a202062696e6465723a206c6f63616c2d7265662c0a2020697465723a20636f72652d657870722c0a2020626f756e643a20636f72652d626f756e642c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a6d617463682d6e6f6465203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d626c6f636b2d61726d5d2c0a7d0a6d617463682d626c6f636b2d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a70726f6f662d6f626c69676174696f6e2d6e6f6465203d207b0a20206b696e643a202270726f6f66222c0a2020636f6f7264696e6174653a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a636f72652d626f756e64203d206c69746572616c2d626f756e64202f20636f6f7264696e6174652d626f756e640a6c69746572616c2d626f756e64203d207b206b696e643a20226c69746572616c222c2076616c75653a2075696e74207d0a636f6f7264696e6174652d626f756e64203d207b206b696e643a2022636f6f7264696e617465222c207265663a2074737472207d0a0a3b20536861726564207265736f757263652d7265662c207368613235362d6469676573742c206661696c7572652d6964656e742c2061706572747572652d726571756972656d656e742c20616e640a3b20636f72652d747970652d7265662061726520646566696e6564206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d6c61777061636b2e6364646c202d2d2d0a3b2065646963742d6c61777061636b2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374206c61777061636b206d616e696665737420616e64206578706f727420737572666163652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e204a534f4e20696e207468652070726f73652073706563730a3b2069732061207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a6c61777061636b2d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2f7631222c0a202069643a20747374722c0a202076657273696f6e3a20747374722c0a20206163636570746564436f72654162693a205b2b20747374725d2c0a2020646570656e64656e636965733a205b2a206c61777061636b2d6465705d2c202020202020202020203b20616379636c69632c206469676573742d6c6f636b6564202845444943542d4c41575041434b2d4441472d303031290a20206578706f7274733a207265736f757263652d7265662c0a20203f2074617267657441646170746572733a205b2b207461726765742d616461707465725d2c2020203b207265717569726564206f6e6c7920696620616e792072756e74696d6520656666656374206578697374730a20203f2068656c706572436f6d706f6e656e743a2065786563757461626c652d636f6d706f6e656e742c203b2065786563757461626c652068656c70657273206361727279207468656972206f776e2073616e64626f782b6675656c0a202076657269666965723a2076657269666965722c202020202020202020202020202020202020202020203b20636c61737369666965643a206465636c61726174697665206f722065786563757461626c650a2020636f6d7061746962696c6974793a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b2041207665726966696572206973206569746865722061206465636c617261746976652072756c6573657420286e6f2072756e74696d6529206f7220616e2065786563757461626c650a3b20636f6d706f6e656e742e20416e2065786563757461626c65207665726966696572204d55535420636172727920697473206f776e2073616e64626f7820616e64206675656c206d6f64656c2c0a3b20736f2074686520736368656d6120656e666f726365732074686174206e6f2065786563757461626c6520636f6d706f6e656e74206973206c65667420756e626f756e6465640a3b202845444943542d4142492d56455249464945522d424f554e442d303031292e0a7665726966696572203d206465636c617261746976652d7665726966696572202f2065786563757461626c652d76657269666965720a6465636c617261746976652d7665726966696572203d207b20636c6173733a20226465636c61726174697665222c2072756c657365743a207265736f757263652d726566207d0a65786563757461626c652d7665726966696572203d207b0a2020636c6173733a202265786563757461626c65222c0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a3b20416e792065786563757461626c6520636f6d706f6e656e7420697320626f756e64656420627920697473206f776e2073616e64626f78202b206675656c206d6f64656c2e0a65786563757461626c652d636f6d706f6e656e74203d207b0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a6c61777061636b2d646570203d207b2069643a20747374722c2076657273696f6e3a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20416461707465722073656c656374696f6e206b65797320534f4c454c59206f666620746865206469676573742d6c6f636b65642060616363657074656454617267657450726f66696c65600a3b20286974732060696460206973207468652070726f66696c652069643b206974732060646967657374602070696e73207468652065786163742070726f66696c652f76657273696f6e292e2054686572650a3b20617265206e6f20696e646570656e64656e7420646973706c617920737472696e6773207468617420636f756c64206469736167726565207769746820746865206c6f636b2c20736f20610a3b207265736f6c7665722063616e6e6f742062696e6420616e206164617074657220746f206f6e6520746172676574207768696c6520746865206c6f636b2070726f76657320616e6f746865720a3b202845444943542d4c41575041434b2d414441505445522d54415247455449522d303031292e0a7461726765742d61646170746572203d207b0a2020616363657074656454617267657450726f66696c653a207265736f757263652d7265662c202020203b206469676573742d6c6f636b65642c20617574686f72697461746976652073656c6563746f720a2020616363657074656454617267657449723a207265736f757263652d7265662c2020202020202020203b206469676573742d6c6f636b65640a2020616461707465723a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d206578706f72742073757266616365202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a6c61777061636b2d6578706f727473203d207b0a202074797065733a205b2a206578706f727465642d747970655d2c0a2020636f6e7374616e74733a205b2a206578706f727465642d636f6e7374616e745d2c0a20207075726546756e6374696f6e733a205b2a20707572652d66756e6374696f6e5d2c0a2020656666656374733a205b2a2073656d616e7469632d6566666563745d2c0a20206f62737472756374696f6e733a205b2a206f62737472756374696f6e2d6465665d2c0a20203b206b65796564206279206f7065726174696f6e2d70726f66696c6520636f6f7264696e61746520e2869220756e697175656e65737320656e666f726365640a20203b202845444943542d4142492d4f5050524f46494c452d554e495155452d303031290a20203b206f7065726174696f6e2d70726f66696c65207265636f7264732074686973206c61777061636b206578706f72747320286f707469632074656d706c6174657320746861740a20203b2060696d706c656d656e7473602f6070726f66696c656020636c6175736573207265736f6c766520616761696e7374292e206f7065726174696f6e2d70726f66696c652069730a20203b20646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c20203b206b6579656420627920636f6f7264696e6174650a7d0a0a6578706f727465642d7479706520202020203d207b20636f6f7264696e6174653a20747374722c20646566696e6974696f6e3a20636f72652d747970652d726566207d0a6578706f727465642d636f6e7374616e74203d207b20636f6f7264696e6174653a20747374722c20747970653a20636f72652d747970652d7265662c2076616c75653a20616e79207d0a0a3b204120707572652068656c7065722069732061206469736372696d696e6174656420756e696f6e2062792060736f75726365602c20736f2074686520736368656d6120697473656c660a3b2067756172616e7465657320616e20696d706c656d656e746174696f6e20657869737473202845444943542d4c41575041434b2d505552452d494d504c2d303031293a0a3b2020202d20226564696374223a20617574686f72656420696e2045646963742f436f72653b2074686520436f726520626f6479206973206361727269656420696e6c696e6520286861736865640a3b20202020207769746820746865206578706f72742073757266616365292e2054686520736368656d61207265717569726573207468652060626f647960206669656c642e0a3b2020202d2022636f6d706f6e656e74223a20696d706c656d656e746564206f7574736964652045646963743b2063617272696573206e6f20696e6c696e6520626f647920616e6420696e73746561640a3b20202020206361727269657320697473206f776e206469676573742d6c6f636b65642060696d706c656d656e746174696f6e60202873616e64626f78202b206675656c292e20497420646f65730a3b20202020206e6f7420646570656e64206f6e20746865206f7074696f6e616c206d616e69666573742d6c6576656c2068656c706572436f6d706f6e656e742e0a707572652d66756e6374696f6e203d2065646963742d707572652d66756e6374696f6e202f20636f6d706f6e656e742d707572652d66756e6374696f6e0a0a707572652d66756e6374696f6e2d636f6d6d6f6e203d20280a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020706172616d6574657254797065733a205b2a20636f72652d747970652d7265665d2c2020202020203b20616c6c20626f756e6465640a202072657475726e547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020636f737454656d706c6174653a20747374722c0a202064657465726d696e69736d436c6173733a2022746f74616c22202f2022746f74616c2d776974682d74797065642d646961676e6f73746963222c0a290a0a65646963742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a20226564696374222c0a2020626f64793a20636f72652d666e2d626f64792c2020202020202020202020202020202020202020203b20696e6c696e652c20686173682d7369676e69666963616e740a7d0a0a636f6d706f6e656e742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a2022636f6d706f6e656e74222c0a20203b20746865206469676573742d6c6f636b656420636f6d706f6e656e7420696d706c656d656e74696e6720746869732068656c7065722e2052657175697265642061742074686520736368656d610a20203b206c6576656c20736f206120636f6d706f6e656e742068656c7065722063616e206e657665722076616c696461746520776974686f7574206120686173682d626f756e642c0a20203b2073616e64626f782b6675656c2d64657363726962656420696d706c656d656e746174696f6e202845444943542d4c41575041434b2d505552452d494d504c2d303031292e0a2020696d706c656d656e746174696f6e3a2065786563757461626c652d636f6d706f6e656e742c0a7d0a0a3b20636f72652d666e2d626f647920697320646566696e65642062792065646963742d636f72652e6364646c20616e6420617373656d626c656420776974682074686973206c61777061636b0a3b20736368656d612e2049742069732061207075726520436f72652066756e6374696f6e20626f64792c206e6f7420616e206566666563742d63617061626c6520636f72652d626c6f636b2e0a0a73656d616e7469632d656666656374203d207b0a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020696e707574547970653a20636f72652d747970652d7265662c2020202020202020202020202020203b20626f756e6465640a20206f7574707574547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020657865637574696f6e436c6173733a202270726f6f664f6e6c7922202f202272756e74696d65222c2020203b206f7274686f676f6e616c20746f207772697465436c6173730a20206566666563744b696e6448696e743a206566666563742d6b696e642c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c20203b206b6579656420627920636f6f7264696e6174653b20756e697175650a20206775617264537570706f72743a20626f6f6c2c0a7d0a0a6f62737472756374696f6e2d646566203d207b0a2020636f6f7264696e6174653a20747374722c0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164536368656d613a20636f72652d747970652d7265662c20202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d7461726765742d70726f66696c652e6364646c202d2d2d0a3b2065646963742d7461726765742d70726f66696c652e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374207461726765742070726f66696c65206d616e69666573742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76310a3b202873656520535045435f636f6e74696e75756d2d636f6e74726163742d62756e646c652d76312e6d64292e204a534f4e20696e207468652070726f736520737065637320697320610a3b207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d613b2074686973204344444c206973207468652073696e676c6520736f757263650a3b206f66207472757468202845444943542d4142492d4e4f4455502d303031292e0a0a7461726765742d70726f66696c652d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652f7631222c0a202069643a20747374722c202020202020202020202020202020202020202020202020203b20652e672e20226563686f2e64706f220a202076657273696f6e3a20747374722c20202020202020202020202020202020202020203b20652e672e202231220a20206163636570746564436f72654162693a205b2b20747374725d2c20202020202020203b20652e672e205b2265646963742e636f72652f7631225d0a0a2020696e7472696e736963733a207265736f757263652d7265662c0a2020696e7472696e7369634e616d6573706163653a20747374722c0a20203b207075626c697368657320746869732070726f66696c652773206f7065726174696f6e2d70726f66696c65207265636f72647320286f707469632074656d706c6174657320746861740a20203b206070726f66696c65602f60696d706c656d656e74736020636c6175736573207265736f6c766520616761696e7374292e205265666572656e63657320616e0a20203b206f7065726174696f6e2d70726f66696c65732d646f63756d656e74202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207265736f757263652d7265662c0a2020666f6f747072696e74416c67656272613a207265736f757263652d7265662c0a2020636f7374416c67656272613a207265736f757263652d7265662c0a202074617267657449723a207265736f757263652d7265662c0a20206f62737472756374696f6e5461786f6e6f6d793a207265736f757263652d7265662c0a202076657269666965723a207265736f757263652d7265662c0a20206c6f77657265723a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a0a20203b206669656c647320746865206c616e67756167652073706563207265717569726573206f662065766572792070726f66696c650a202062756e646c6550726f66696c653a207265736f757263652d7265662c0a202067656e657261746564417274696661637450726f66696c65733a205b2a207265736f757263652d7265665d2c0a202063616e6f6e6963616c456e636f64696e6752756c65733a207265736f757263652d7265662c0a20203b2052657365727665642f64656665727265643a2077696c6c206c697374206163636570746564206c61777061636b2d616461707465722041424920696473206f6e636520746861740a20203b20627974652d6c6576656c20414249202865646963742e6c61777061636b2d616461707465722f763129206973207370656369666965642e2054686520736368656d6120656e666f726365730a20203b20656d7074696e657373206e6f7720e280942074686520747970652069732074686520656d7074792061727261792c20736f206e6f6e2d656d7074792076616c756573206172650a20203b2072656a65637465642c206e6f74206d6572656c7920646973636f757261676564202845444943542d4142492d4c41575041434b2d414441505445522d44454645522d303031292e0a20203f2061636365707465644c61777061636b416461707465724162693a205b5d2c0a2020646961676e6f737469634162693a207265736f757263652d7265662c0a0a20203b206170706c69636174696f6e20646f637472696e650a20206170706c69636174696f6e4d6f64656c3a202261746f6d6963222c0a202072656164436f6e73697374656e63793a20226170706c69636174696f6e2d736e617073686f7422202f20747374722c0a202067756172644576616c756174696f6e3a2022707265636f6d6d69742d61746f6d696322202f20747374722c0a20206f62737472756374696f6e526f6c6c6261636b3a20226e6f2d76697369626c652d6566666563747322202f20747374722c0a20206d756c74695461726765743a20626f6f6c2c0a20203b207768657468657220746865207461726765742063616e206576616c7561746520707265636f6d6d697420706f7374636f6e646974696f6e20286067756172616e746565602920636865636b730a20203b20696e73696465207468652061746f6d6963206170706c69636174696f6e20756e6974202845444943542d5441524745542d504f5354434f4e442d303031290a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a0a202064657465726d696e6973746963457865637574696f6e3a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d6120627920746865206275696c640a3b202845444943542d4142492d4e4f4455502d303031292e205468657920617265206e6f74207265646566696e656420686572652e0a0a3b202d2d2d20696e7472696e736963207369676e6174757265202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e696665737427732060696e7472696e7369637360207265736f757263652d726566206973207468650a3b20696e7472696e7369632d7369676e617475726520636f7270757320646f63756d656e742062656c6f772e20497473206c61796f757420697320666978656420736f2074776f0a3b20696e646570656e64656e742070726f66696c65732076616c69646174652f686173682074686520636f72707573206964656e746963616c6c790a3b202845444943542d4142492d494e5452494e534943532d444f432d303031292e0a0a3b20696e7472696e736963732069732061204d4150206b6579656420627920636f6f7264696e6174652c20736f2074686520736368656d6120697473656c6620656e666f726365730a3b20636f6f7264696e61746520756e697175656e6573732e20412070726f766964657220726563656976657320746865207265736f6c76656420636f7270757320617320610a3b206469676573742d626f756e642073656d616e74696320696e70757420616e64207265736f6c76657320636f6f7264696e617465732077697468696e20746861742061727469666163742e0a3b2045616368206d6170206b6579204d55535420657175616c20697473207265636f726427732060636f6f7264696e61746560206669656c640a3b202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e696e7472696e736963732f7631222c0a2020696e7472696e736963733a207b202a2074737472203d3e20696e7472696e736963207d2c0a7d0a0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e6966657374277320606f7065726174696f6e50726f66696c657360207265736f757263652d7265662e0a3b206f7065726174696f6e2d70726f66696c65202f206f707469632d74656d706c6174652061726520646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e204b657965642062790a3b20636f6f7264696e61746520736f207265736f6c7574696f6e2063616e2774207069636b206265747765656e2074776f2073616d652d636f6f7264696e6174652070726f66696c65730a3b202845444943542d4142492d4f5050524f46494c452d534c4f542d3030312c2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e6f7065726174696f6e2d70726f66696c65732f7631222c0a202070726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c0a7d0a0a3b2041207479706564207072652d6c6f776572696e67207175657374696f6e20746861742063616e2062652070726f706f73656420627920576174736f6e206f7220616e206167656e7420616e640a3b20636865636b65642062792074686520636f6d70696c65722e2049742069732063616e6f6e6963616c2d43424f5220656e636f64656420756e6465720a3b206065646963742e6c6f776572696e672d726571756972656d656e74732f7631603b2074686520636f6d70696c657220636865636b7320746869732061727469666163742c206e6f74207468650a3b2070726f736520746861742070726f64756365642069742e0a6c6f776572696e672d726571756972656d656e7473203d207b0a202061706956657273696f6e3a202265646963742e6c6f776572696e672d726571756972656d656e74732f7631222c0a20206f7065726174696f6e50726f66696c653a20747374722c0a202073656d616e746963456666656374733a205b2a2073656d616e7469632d6566666563742d726571756972656d656e745d2c0a202072657175697265645772697465436c61737365733a205b2a2077726974652d636c6173735d2c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a202061746f6d69636974793a2061746f6d69636974792d726571756972656d656e742c0a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a20206f70746963436f6e74726163743a20747374722c0a7d0a0a73656d616e7469632d6566666563742d726571756972656d656e74203d207b0a2020636f6f7264696e6174653a20747374722c0a20207772697465436c6173733a2077726974652d636c6173732c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a7d0a0a77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a2020202020202020202020202020227265706c61636522202f202264656c65746522202f20747374720a67756172642d6b696e64203d2022707265636f6d6d69742d61746f6d696322202f20747374720a61746f6d69636974792d726571756972656d656e74203d202261746f6d696322202f20747374720a0a3b20412067656e75696e6520756e696f6e3a207075726520636f6e7374727563746f7273206361727279206e6f20656666656374206b696e64206f72206661696c757265733b206566666563740a3b20696e7472696e73696373206d757374202845444943542d5441524745542d494e5452494e5349432d434c4153532d303031292e2054686520736368656d6120656e666f7263657320746869732c0a3b206e6f74206120636f6d6d656e742e0a0a3b2054686520696e7472696e736963277320636f6f7264696e6174652069732074686520696e7472696e73696373206d6170204b45592c206e6f7420612076616c7565206669656c642c20736f207468650a3b206b657920616e6420636f6f7264696e6174652063616e206e65766572206469736167726565202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963203d20707572652d696e7472696e736963202f206566666563742d696e7472696e7369630a0a707572652d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a202270757265222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206775617264537570706f72743a2066616c73652c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20226e6f6e65222c0a7d0a0a6566666563742d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a2022656666656374222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206566666563744b696e643a206566666563742d6b696e642c0a20203b206d6170206b65796564206279206661696c75726520636f6f7264696e61746520286661696c7572652d6964656e74293b20746865206661696c75726520636f6f7264696e6174652069730a20203b20746865206b65792c206e6f7420612076616c7565206669656c642c20736f20756e697175656e657373206973207374727563747572616c0a20203b202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c0a20206775617264537570706f72743a20626f6f6c2c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f20227265706c61636522202f0a20202020202020202020202020202264656c65746522202f2022637573746f6d222c0a202063616e5061727469636970617465496e41746f6d696347756172643a20626f6f6c2c0a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d617574686f726974792d66616374732e6364646c202d2d2d0a3b2065646963742d617574686f726974792d66616374732e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f722074686520666972737420636f6d70696c65722d636f6e7465787420617574686f726974792d666163747320646f63756d656e742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20736f20736f757263652e6469676573742075736573207468650a3b20736861726564207368613235362d6469676573742074797065642076616c75652e204a534f4e2069732061207265766965772f696e7075742072656e646572696e673a206974730a3b20607368613235363a3c3634206865783e6020736f75726365206469676573742069732070726f6a656374656420746f205b60736861323536602c203332207261772062797465735d206f6e0a3b2074686520776972652c20616e64206974732066616374206172726179732070726f6a65637420746f2074686520636f6f7264696e6174652d6b65796564206d6170732062656c6f772e0a0a617574686f726974792d6661637473203d207b0a202061706956657273696f6e3a202265646963742e617574686f726974792d66616374732f7631222c0a2020736f757263653a20617574686f726974792d666163742d736f757263652c0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e20617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374207d2c0a20206566666563745772697465436c61737365733a207b202a2074737472203d3e20617574686f726974792d77726974652d636c617373207d2c0a2020627564676574733a207b202a2074737472203d3e20617574686f726974792d6275646765742d66616374207d2c0a7d0a0a617574686f726974792d666163742d736f75726365203d207b0a20206b696e643a20226c61777061636b22202f202274617267657450726f66696c65222c0a2020636f6f7264696e6174653a20747374722c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a3b20546865206d6170206b65792069732074686520736f75726365206f7065726174696f6e2d70726f66696c6520636f6f7264696e6174652e204974206973206e6f7420726570656174656420696e0a3b207468652076616c75652c20736f2061206b657920616e6420656d62656464656420636f6f7264696e6174652063616e6e6f742064697361677265652e20416c6c6f7765642077726974650a3b20636c61737365732061726520612063616e6f6e6963616c206d61702d7365743a2074686520636c6173732069732074686520756e69717565206b657920616e64206e756c6c206973207468650a3b20756e6974206d61726b65722e2043616e6f6e6963616c2043424f52206669786573206b6579206f7264657220776974686f75742061207365636f6e64206f72646572696e672072756c652e0a617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374203d207b0a2020636f72653a20747374722c0a2020616c6c6f7765645772697465436c61737365733a207b202a20617574686f726974792d77726974652d636c617373203d3e206e756c6c207d2c0a7d0a0a3b20546865206566666563745772697465436c6173736573206d6170206b6579206973207468652073656d616e7469632065666665637420636f6f7264696e6174652e2054686520627564676574730a3b206d6170206b65792069732074686520736f757263652062756467657420636f6f7264696e6174652e2043616e6f6e6963616c2043424f52206d61702d6b657920756e697175656e6573730a3b206d616b6573206475706c6963617465206661637420636f6f7264696e61746573207374727563747572616c6c7920756e726570726573656e7461626c652e0a617574686f726974792d6275646765742d66616374203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a3b20417574686f726974794661637473446f63756d656e7420763120696e74656e74696f6e616c6c792061636365707473206f6e6c792074686520777269746520636c6173736573207468650a3b2063757272656e7420636f6d70696c6572206d6f64656c2063616e20636f6e73756d652e2060637573746f6d602069732074686520736f6c6520763120637573746f6d207370656c6c696e673b0a3b20617262697472617279207461726765742d70726f66696c6520657874656e73696f6e20737472696e677320646f206e6f7420656e746572207468697320636f6d70696c657220706174682e0a617574686f726974792d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a202020202020202020202020202020202020202020202020227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b202d2d2d2065646963742d7461726765742d69722e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d7461726765742d69722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72207468652045646963742d6f776e65642054617267657420495220617274696661637420656e76656c6f70652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20616e642065646963742d636f72652e6364646c2e2049740a3b2064656c696265726174656c792072657573657320436f72652065787072657373696f6e732c20707265646963617465732c20627564676574732c206c6f63616c207265666572656e6365732c0a3b206f62737472756374696f6e20726561736f6e732c20616e64206f62737472756374696f6e2061726d7320736f2074686520736368656d61206d617463686573207468652076616c75650a3b20656d6974746564206279207468652063616e6f6e6963616c2054617267657420495220656e636f64657220726174686572207468616e20726573746174696e672074686f73652074797065732e0a3b2049742064657363726962657320746865207374727563747572616c207368617065206f662076616c6964206c6f776572696e672d70726f6475636564206172746966616374732e205468650a3b206c6f776572696e6720616e6420656e636f64657220636f6e7472616374732073657061726174656c7920656e666f7263652073656d616e746963206964656e7469666965722072756c65730a3b20616e642063616e6f6e6963616c206f72646572696e672f64656475706c69636174696f6e20666f72207365742d6c696b652076616c7565732e0a0a3b2054617267657420495220656e636f64696e672072656a6563747320616e20656d707479207461726765742d70726f66696c6520636f6f7264696e617465206265666f72652062797465730a3b2065786973742c20736f207468697320726f6f74207469676874656e732074686520736861726564207374727563747572616c207265736f757263652d726566206163636f7264696e676c792e0a7461726765742d69722d7265736f757263652d726566203d207b0a202069643a2074737472202e7265676578702022283f73292e2b222c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a7461726765742d69722d6172746966616374203d207b0a20206b696e643a202274617267657449724172746966616374222c0a2020646f6d61696e3a20747374722c0a202074617267657450726f66696c653a207461726765742d69722d7265736f757263652d7265662c0a2020736f75726365436f7265436f6f7264696e6174653a20747374722c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d696e74656e74207d2c0a7d0a0a7461726765742d69722d696e74656e74203d207b0a20206f7065726174696f6e50726f66696c653a20747374722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020726571756972656d656e74733a205b2a207461726765742d69722d726571756972656d656e745d2c0a202073746570733a205b2a207461726765742d69722d737465705d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a7461726765742d69722d726571756972656d656e74203d207b0a202069643a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a0a7461726765742d69722d73746570203d207b0a202069643a20747374722c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020746172676574496e7472696e7369633a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4661696c757265733a205b2a206661696c7572652d6964656e745d2c0a20206f62737472756374696f6e41726d733a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a", + "rawSha256": "92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74" + }, + "contracts": [ + {"contract": "authority-facts", "rootRule": "authority-facts"}, + {"contract": "core-module", "rootRule": "core-module"}, + {"contract": "lawpack-exports", "rootRule": "lawpack-exports"}, + {"contract": "lawpack-manifest", "rootRule": "lawpack-manifest"}, + {"contract": "lowering-requirements", "rootRule": "lowering-requirements"}, + {"contract": "target-ir-artifact", "rootRule": "target-ir-artifact"}, + {"contract": "target-profile-intrinsics", "rootRule": "intrinsics-document"}, + {"contract": "target-profile-manifest", "rootRule": "target-profile-manifest"}, + {"contract": "target-profile-operation-profiles", "rootRule": "operation-profiles-document"} + ], + "domains": [ + {"domain": "edict.authority-facts/v1", "rootRule": "authority-facts"}, + {"domain": "edict.core.module/v1", "rootRule": "core-module"}, + {"domain": "edict.lawpack/v1", "rootRule": "lawpack-manifest"}, + {"domain": "edict.lowering-requirements/v1", "rootRule": "lowering-requirements"}, + {"domain": "edict.target-ir.artifact/v1", "rootRule": "target-ir-artifact"}, + {"domain": "edict.target-profile/v1", "rootRule": "target-profile-manifest"} + ], + "resources": [ + { + "coordinate": "edict.canonical-cbor/v1", + "canonicalBytesHex": "a368636f6e7472616374a96a76616c75654d6f64656c8765617272617964626f6f6c65627974657367696e7465676572636d6170646e756c6c64746578746b6469676573744672616d656f65646963742e6469676573742f76316b6d61704f72646572696e67781b63616e6f6e6963616c2d656e636f6465642d6b65792d62797465736c74657874456e636f64696e67657574662d386d747261696c696e6742797465736672656a6563746f696e7465676572456e636f64696e676873686f727465737470636f6e7461696e65724c656e6774687368646566696e697465706475706c69636174654d61704b6579736672656a656374736d6178696d756d4e657374696e67446570746818806a61706956657273696f6e782965646963742e7461726765742d70726f66696c652e636f6e74726163742d7265736f757263652f76316a636f6f7264696e6174657765646963742e63616e6f6e6963616c2d63626f722f7631", + "rawSha256": "8306e4f08c1e4e7d29ab22bcf55c324312712aac3eeeb675857ced57c3e48bdc", + "domainFramedDigest": "sha256:d1ea6d3de2a9762a438cbf4fac1d5ae2f357a4b27d13e0347e94ea655bf40f9d", + "provenance": { + "repository": "https://github.com/flyingrobots/edict", + "sourcePath": "fixtures/target-profile/contract-resources/canonical-cbor.cbor" + } + }, + { + "coordinate": "edict.determinism/v1", + "canonicalBytesHex": "a368636f6e7472616374aa6c616d6269656e74436c6f636bf46e616d6269656e744e6574776f726bf46e6f75747075744964656e74697479781e686f73742d636f6d70757465642d61667465722d76616c69646174696f6e6e72656769737472794c6f6f6b7570f471616d6269656e7446696c6573797374656df471616d6269656e7452616e646f6d6e657373f472616d6269656e74456e7669726f6e6d656e74f4756d757461626c654e616d655265736f6c7574696f6ef477667265736853746f7265506572496e766f636174696f6ef5782263616e6f6e6963616c526573756c74496e646570656e64656e744f664c696d697473f56a61706956657273696f6e782965646963742e7461726765742d70726f66696c652e636f6e74726163742d7265736f757263652f76316a636f6f7264696e6174657465646963742e64657465726d696e69736d2f7631", + "rawSha256": "84073f5c1734b625e16799048e28458d43e0a10befdae56a79d906f5e37ef76a", + "domainFramedDigest": "sha256:af4e6c774d5ea82db30e680be2ba7abc5ba04c6aead146139de32d8c5bb4981e", + "provenance": { + "repository": "https://github.com/flyingrobots/edict", + "sourcePath": "fixtures/target-profile/contract-resources/determinism.cbor" + } + }, + { + "coordinate": "edict.diagnostics/v1", + "canonicalBytesHex": "a368636f6e7472616374a7666669656c64738464636f6465687365766572697479676d65737361676566726570616972686f72646572696e67781c636f64652d73657665726974792d6d6573736167652d726570616972697265636f7264416269782f65646963743a7461726765742d70726f76696465722f70726f746f636f6c40312e302e3023646961676e6f737469636a7472756e636174696f6e69666f7262696464656e6d73657665726974794f7264657283656572726f72677761726e696e6764696e666f6e6c697374436f756e74426f756e64f57261676772656761746542797465426f756e64f56a61706956657273696f6e782965646963742e7461726765742d70726f66696c652e636f6e74726163742d7265736f757263652f76316a636f6f7264696e6174657465646963742e646961676e6f73746963732f7631", + "rawSha256": "e465a28f1170fe478db5ff65d96a1fdbfbbcb95d327e6965021c252437991e4b", + "domainFramedDigest": "sha256:28fd72a98223153982ca084c29dbb1b2d430623967ab3b6db9d7fee668e614b9", + "provenance": { + "repository": "https://github.com/flyingrobots/edict", + "sourcePath": "fixtures/target-profile/contract-resources/diagnostics.cbor" + } + }, + { + "coordinate": "edict.fuel/v1", + "canonicalBytesHex": "a368636f6e7472616374a6687265717569726564f56a6163636f756e74696e67781864657465726d696e69737469632d67756573742d776f726b6a627564676574556e6974646675656c6a65786861757374696f6e72686f73742d6f776e65642d6661696c7572656d706572496e766f636174696f6ef57165706f6368496e74657272757074696f6e736e6f742d612d7265706c61792d6275646765746a61706956657273696f6e782965646963742e7461726765742d70726f66696c652e636f6e74726163742d7265736f757263652f76316a636f6f7264696e6174656d65646963742e6675656c2f7631", + "rawSha256": "c712c2d831cc8e731bdc1dfb8ea536f4630f38f0b0e0c6448b2df57176d3d0bd", + "domainFramedDigest": "sha256:006c6ebc01a3c5d36d50bd390b69d47e42378be61074e3b5c96ecb9f5ee53207", + "provenance": { + "repository": "https://github.com/flyingrobots/edict", + "sourcePath": "fixtures/target-profile/contract-resources/fuel.cbor" + } + }, + { + "coordinate": "edict.wasm-component/v1", + "canonicalBytesHex": "a368636f6e7472616374a7647761736969666f7262696464656e6e70726f746f636f6c496d706f727469747970652d6f6e6c796f63616c6c61626c65496d706f72747369666f7262696464656e70636f6e74726163744964656e746974796565786163747070726f7669646572436f6e7472616374781b65646963743a7461726765742d70726f766964657240312e302e3077667265736853746f7265506572496e766f636174696f6ef5781b636f6d706f6e656e74446967657374566572696669636174696f6e6d6265666f72652d6465636f64656a61706956657273696f6e782965646963742e7461726765742d70726f66696c652e636f6e74726163742d7265736f757263652f76316a636f6f7264696e6174657765646963742e7761736d2d636f6d706f6e656e742f7631", + "rawSha256": "cd09d702db1d10be825e72effe35627bec56963cb3d78601b69478c58787e34d", + "domainFramedDigest": "sha256:095b4dd18f1a6a7276533f758665be319c5f476e7bdc70cc56d30b6b3e9f0a80", + "provenance": { + "repository": "https://github.com/flyingrobots/edict", + "sourcePath": "fixtures/target-profile/contract-resources/wasm-component.cbor" + } + } + ] +} diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/echo-provider-semantics-v1.json b/crates/echo-wesley-gen/assets/v1/edict-provider/echo-provider-semantics-v1.json new file mode 100644 index 00000000..6b52ada5 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/echo-provider-semantics-v1.json @@ -0,0 +1,703 @@ +{ + "apiVersion": "echo.edict-provider-semantics/v1", + "coordinate": "echo.semantic-schema@1", + "authoritySources": [ + { + "coordinate": "echo.provider-semantic-declaration@1", + "kind": "echoSemanticDeclaration", + "artifact": "schemas/edict-provider/echo-provider-semantics-v1.json" + }, + { + "coordinate": "echo.provider-target-metadata@1", + "kind": "targetMetadata", + "artifact": "schemas/edict-provider/echo-provider-semantics-v1.json" + } + ], + "types": [ + { + "identity": { + "coordinate": "a.b@1.Input", + "domain": "echo.edict-provider/value/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "shape": { + "kind": "record", + "fields": [ + { + "name": "id", + "type": "a.b@1.Id" + } + ] + } + }, + { + "identity": { + "coordinate": "a.b@1.Receipt", + "domain": "echo.edict-provider/value/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "shape": { + "kind": "record", + "fields": [ + { + "name": "id", + "type": "a.b@1.Id" + } + ] + } + }, + { + "identity": { + "coordinate": "a.b@1.Output", + "domain": "echo.edict-provider/value/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "shape": { + "kind": "record", + "fields": [ + { + "name": "id", + "type": "a.b@1.Id" + } + ] + } + }, + { + "identity": { + "coordinate": "a.b@1.Id", + "domain": "echo.edict-provider/value/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "shape": { + "kind": "coreStringAlias", + "maxScalarValues": 16, + "canonical": "raw-utf8" + } + }, + { + "identity": { + "coordinate": "domain.WriteRejected.Payload", + "domain": "echo.edict-provider/value/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "shape": { + "kind": "record", + "fields": [] + } + }, + { + "identity": { + "coordinate": "target.replace.rejected", + "domain": "echo.edict-provider/value/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "shape": { + "kind": "record", + "fields": [] + } + } + ], + "writeClasses": [ + { + "identity": { + "coordinate": "replace", + "domain": "echo.edict-provider/write-class/v1", + "authority": "echo.provider-target-metadata@1" + } + } + ], + "obstructions": [ + { + "identity": { + "coordinate": "domain.WriteRejected", + "domain": "echo.edict-provider/obstruction/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "authorityClass": "domainMappable", + "payloadSchema": "domain.WriteRejected.Payload" + } + ], + "effects": [ + { + "identity": { + "coordinate": "target.replace", + "domain": "echo.edict-provider/semantic-effect/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "parameterTypes": ["a.b@1.Id"], + "resultType": "a.b@1.Receipt", + "executionClass": "runtime", + "effectKindHint": "replace", + "guardKinds": ["precommit-atomic"], + "failures": [ + { + "key": "rejected", + "domain": "echo.edict-provider/effect-failure/v1", + "authority": "echo.provider-target-metadata@1", + "authorityClass": "domainMappable", + "payloadType": "target.replace.rejected" + } + ], + "footprintObligation": "target.replace.footprint", + "costObligation": "target.replace.cost", + "guardSupport": true + } + ], + "profiles": [ + { + "identity": { + "coordinate": "continuum.profile.write/v1", + "domain": "echo.edict-provider/operation-profile/v1", + "authority": "echo.provider-target-metadata@1" + }, + "sourceNames": ["p.effectful"], + "allowedWriteClasses": ["replace"], + "guardKinds": ["precommit-atomic"], + "atomicity": "atomic", + "postconditionSupport": true, + "opticTemplate": { + "opticKind": "affectReintegration", + "boundaryKind": "affect", + "supportPolicy": "continuum.support.carry-or-obstruct/v1", + "lossDisposition": "continuum.support.reject-on-loss/v1", + "apertureRequirement": { + "kind": "abstractFootprintObligation", + "ref": "target.replace.footprint" + } + }, + "effectPredicate": "echo.dpo.operation-mode.replace-only/v1", + "opticContract": "replace-point" + } + ], + "budgets": [ + { + "identity": { + "coordinate": "p.tiny", + "domain": "echo.edict-provider/core-budget/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "maxSteps": 8, + "maxAllocatedBytes": 1024, + "maxOutputBytes": 256 + } + ], + "capabilities": [ + { + "identity": { + "coordinate": "echo.dpo@1.replace", + "domain": "echo.edict-provider/target-intrinsic/v1", + "authority": "echo.provider-target-metadata@1" + }, + "effect": "target.replace", + "effectKind": "replace", + "writeClass": "replace", + "guardSupport": true, + "footprintTemplate": "target.replace.footprint", + "costTemplate": "target.replace.cost", + "semanticDischarge": { + "effectKindHint": "replace", + "footprintObligation": "target.replace.footprint", + "costObligation": "target.replace.cost" + }, + "canParticipateInAtomicGuard": true, + "targetProfile": "echo.dpo@1", + "targetIrDomain": "echo.span-ir/v1" + } + ], + "directAdapters": [], + "operations": [ + { + "identity": { + "coordinate": "a.b@1.t", + "domain": "echo.edict-provider/operation/v1", + "authority": "echo.provider-semantic-declaration@1" + }, + "inputType": "a.b@1.Input", + "outputType": "a.b@1.Output", + "effect": "target.replace", + "profile": "continuum.profile.write/v1", + "budget": "p.tiny", + "obstructionMappings": [ + { + "failure": "rejected", + "obstruction": "domain.WriteRejected" + } + ], + "implementation": { + "kind": "native", + "capability": "echo.dpo@1.replace" + } + } + ], + "artifactResources": [ + { + "role": "resource.canonical-encoding", + "coordinate": "edict.canonical-cbor/v1", + "schemaContract": "edict.canonical-cbor/v1", + "provision": "external" + }, + { + "role": "resource.conformance-corpus", + "coordinate": "echo.dpo.fixtures/v1", + "schemaContract": "echo.edict-provider.conformance-corpus/v1", + "provision": "generated" + }, + { + "role": "resource.diagnostic-abi", + "coordinate": "edict.diagnostics/v1", + "schemaContract": "edict.diagnostics/v1", + "provision": "external" + }, + { + "role": "resource.deterministic-execution", + "coordinate": "edict.determinism/v1", + "schemaContract": "edict.determinism/v1", + "provision": "external" + }, + { + "role": "resource.fuel-model", + "coordinate": "edict.fuel/v1", + "schemaContract": "edict.fuel/v1", + "provision": "external" + }, + { + "role": "resource.lawpack-compatibility", + "coordinate": "echo.dpo-lawpack.compatibility@1", + "schemaContract": "echo.edict-provider.lawpack-compatibility/v1", + "provision": "generated" + }, + { + "role": "resource.lawpack-exports", + "coordinate": "echo.dpo-lawpack.exports@1", + "schemaContract": "edict.lawpack/v1#lawpack-exports", + "provision": "generated" + }, + { + "role": "resource.lawpack-target-adapter", + "coordinate": "echo.dpo-lawpack.adapter.echo-dpo@1", + "schemaContract": "echo.edict-provider.lawpack-target-adapter/v1", + "provision": "generated" + }, + { + "role": "resource.lawpack-verifier", + "coordinate": "echo.dpo-lawpack.verifier@1", + "schemaContract": "echo.edict-provider.lawpack-verifier/v1", + "provision": "generated" + }, + { + "role": "resource.sandbox", + "coordinate": "edict.wasm-component/v1", + "schemaContract": "edict.wasm-component/v1", + "provision": "external" + }, + { + "role": "resource.target-bundle-profile", + "coordinate": "echo.dpo.bundle/v1", + "schemaContract": "echo.dpo.bundle/v1", + "provision": "generated" + }, + { + "role": "resource.target-cost-algebra", + "coordinate": "echo.dpo.cost/v1", + "schemaContract": "echo.dpo.cost/v1", + "provision": "generated" + }, + { + "role": "resource.target-footprint-algebra", + "coordinate": "echo.dpo.footprint/v1", + "schemaContract": "echo.dpo.footprint/v1", + "provision": "generated" + }, + { + "role": "resource.target-intrinsics", + "coordinate": "echo.dpo.intrinsics/v1", + "schemaContract": "edict.target-profile.intrinsics/v1", + "provision": "generated" + }, + { + "role": "resource.target-ir", + "coordinate": "echo.span-ir/v1", + "schemaContract": "echo.span-ir/v1", + "provision": "generated" + }, + { + "role": "resource.target-lowerer-contract", + "coordinate": "echo.dpo.lowerer/v1", + "schemaContract": "echo.dpo.lowerer/v1", + "provision": "generated" + }, + { + "role": "resource.target-obstruction-taxonomy", + "coordinate": "echo.dpo.obstructions/v1", + "schemaContract": "echo.dpo.obstructions/v1", + "provision": "generated" + }, + { + "role": "resource.target-operation-profiles", + "coordinate": "echo.dpo.operation-profiles/v1", + "schemaContract": "edict.target-profile.operation-profiles/v1", + "provision": "generated" + }, + { + "role": "resource.target-verifier-contract", + "coordinate": "echo.dpo.verifier/v1", + "schemaContract": "echo.dpo.verifier/v1", + "provision": "generated" + } + ], + "lawpackProjection": { + "authority": "echo.provider-semantic-declaration@1", + "artifactRole": "lawpack.echo-dpo", + "id": "echo.dpo-lawpack", + "version": "1", + "acceptedCoreAbis": ["edict.core/v1"], + "dependencies": [], + "exportsResource": "resource.lawpack-exports", + "targetAdapters": [ + { + "acceptedTargetProfileRole": "target-profile.echo-dpo", + "acceptedTargetIrResource": "resource.target-ir", + "adapterResource": "resource.lawpack-target-adapter", + "effects": ["target.replace"] + } + ], + "verifier": { + "class": "declarative", + "rulesetResource": "resource.lawpack-verifier" + }, + "compatibilityResource": "resource.lawpack-compatibility", + "conformanceFixtureCorpusResource": "resource.conformance-corpus" + }, + "targetProfileProjection": { + "authority": "echo.provider-target-metadata@1", + "artifactRole": "target-profile.echo-dpo", + "id": "echo.dpo", + "version": "1", + "acceptedCoreAbis": ["edict.core/v1"], + "intrinsicNamespace": "echo.dpo@1", + "intrinsicsResource": "resource.target-intrinsics", + "operationProfilesResource": "resource.target-operation-profiles", + "footprintAlgebraResource": "resource.target-footprint-algebra", + "costAlgebraResource": "resource.target-cost-algebra", + "targetIrResource": "resource.target-ir", + "obstructionTaxonomyResource": "resource.target-obstruction-taxonomy", + "verifierResource": "resource.target-verifier-contract", + "lowererResource": "resource.target-lowerer-contract", + "sandboxResource": "resource.sandbox", + "fuelModelResource": "resource.fuel-model", + "bundleProfileResource": "resource.target-bundle-profile", + "generatedArtifactProfileRoles": [ + "generated-artifact-profile.echo-dpo-registration" + ], + "canonicalEncodingRulesResource": "resource.canonical-encoding", + "acceptedLawpackAdapterAbis": [], + "diagnosticAbiResource": "resource.diagnostic-abi", + "applicationModel": "atomic", + "readConsistency": "application-snapshot", + "guardEvaluation": "precommit-atomic", + "obstructionRollback": "no-visible-effects", + "multiTarget": false, + "postconditionSupport": true, + "deterministicExecutionResource": "resource.deterministic-execution", + "conformanceFixtureCorpusResource": "resource.conformance-corpus" + }, + "generatedArtifacts": [ + { + "role": "authority-facts.echo-dpo", + "kind": "authorityFacts", + "coordinate": "echo.dpo-authority-facts@1", + "schemaContract": "edict.authority-facts/v1", + "contractOwner": "flyingrobots/edict#157", + "authorityFactSource": { + "kind": "targetProfile", + "coordinate": "echo.dpo@1" + } + }, + { + "role": "authority-facts.echo-lawpack", + "kind": "authorityFacts", + "coordinate": "echo.dpo-lawpack-authority-facts@1", + "schemaContract": "edict.authority-facts/v1", + "contractOwner": "flyingrobots/edict#157", + "authorityFactSource": { + "kind": "lawpack", + "coordinate": "echo.dpo-lawpack@1" + } + }, + { + "role": "generated-artifact-profile.echo-dpo-registration", + "kind": "generatedArtifactProfile", + "coordinate": "echo.dpo.registration/v1", + "schemaContract": "echo.generated-artifact-profile/v1" + }, + { + "role": "lawpack.echo-dpo", + "kind": "lawpack", + "coordinate": "echo.dpo-lawpack@1", + "schemaContract": "edict.lawpack/v1" + }, + { + "role": "provenance.provider-generation", + "kind": "generationProvenance", + "coordinate": "echo.edict-provider-generation-provenance@1", + "schemaContract": "wesley:GenerationProvenanceManifestV1", + "contractOwner": "flyingrobots/wesley#728" + }, + { + "role": "review.provider-generation", + "kind": "reviewArtifact", + "coordinate": "echo.edict-provider-generation-review@1", + "schemaContract": "wesley:GenerationReviewV1", + "contractOwner": "flyingrobots/wesley#728" + }, + { + "role": "schema.echo-provider-artifacts", + "kind": "artifactSchema", + "coordinate": "echo.provider-artifacts.cddl@1", + "schemaContract": "selfContainedCddlV1" + }, + { + "role": "target-profile.echo-dpo", + "kind": "targetProfile", + "coordinate": "echo.dpo@1", + "schemaContract": "edict.target-profile/v1" + } + ], + "packageManifest": { + "role": "provider-manifest.echo", + "coordinate": "echo.edict-provider-manifest@1", + "schemaContract": "edict.provider-manifest/v1", + "providerAbi": "edict:target-provider@1.0.0", + "providerCoordinate": "echo.edict-provider@1", + "components": [ + { + "role": "lowerer.echo-dpo", + "kind": "lowerer", + "coordinate": "echo.dpo.lowerer/component@1", + "contract": "edict:target-provider/lowerer@1.0.0" + }, + { + "role": "verifier.echo-dpo", + "kind": "verifier", + "coordinate": "echo.dpo.verifier/component@1", + "contract": "edict:target-provider/verifier@1.0.0" + } + ] + }, + "invocationInputs": [ + { + "role": "authority-facts.echo-dpo", + "kind": "authorityFacts", + "domain": "edict.authority-facts/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "authority-facts.echo-lawpack", + "kind": "authorityFacts", + "domain": "edict.authority-facts/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "core.echo-provider", + "kind": "core", + "domain": "edict.core.module/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "lawpack.echo-dpo", + "kind": "lawpack", + "domain": "edict.lawpack/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "lowerability.echo-dpo", + "kind": "lowerabilityFacts", + "domain": "edict.lowering-requirements/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "target-ir.echo-dpo", + "kind": "targetIr", + "domain": "edict.target-ir.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "target-profile.echo-dpo", + "kind": "targetProfile", + "domain": "edict.target-profile/v1", + "schemaRole": "schema.echo-provider-artifacts" + } + ], + "invocationOutputs": [ + { + "role": "generated.echo-dpo", + "kind": "generatedArtifact", + "domain": "echo.generated-artifact/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "review.echo-dpo", + "kind": "reviewPayload", + "domain": "echo.review-payload/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "target-ir.echo-dpo", + "kind": "targetIr", + "domain": "edict.target-ir.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, + { + "role": "verifier-report.echo-dpo", + "kind": "verifierReport", + "domain": "echo.verifier-report/v1", + "schemaRole": "schema.echo-provider-artifacts" + } + ], + "schemaBindings": [ + { + "domain": "echo.dpo-lawpack.adapter.echo-dpo@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-target-adapter" + }, + { + "domain": "echo.dpo-lawpack.compatibility@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-compatibility" + }, + { + "domain": "echo.dpo-lawpack.exports@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-exports" + }, + { + "domain": "echo.dpo-lawpack.verifier@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-verifier" + }, + { + "domain": "echo.dpo.bundle/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-bundle" + }, + { + "domain": "echo.dpo.cost/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-cost" + }, + { + "domain": "echo.dpo.fixtures/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-conformance-corpus" + }, + { + "domain": "echo.dpo.footprint/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-footprint" + }, + { + "domain": "echo.dpo.intrinsics/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "intrinsics-document" + }, + { + "domain": "echo.dpo.lowerer/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-lowerer" + }, + { + "domain": "echo.dpo.obstructions/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-obstructions" + }, + { + "domain": "echo.dpo.operation-profiles/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "operation-profiles-document" + }, + { + "domain": "echo.dpo.verifier/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-verifier" + }, + { + "domain": "echo.generated-artifact-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact-profile" + }, + { + "domain": "echo.generated-artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact" + }, + { + "domain": "echo.review-payload/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "review-payload" + }, + { + "domain": "echo.span-ir/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-span-ir" + }, + { + "domain": "echo.verifier-report/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "verifier-report" + }, + { + "domain": "edict.authority-facts/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "authority-facts" + }, + { + "domain": "edict.core.module/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "core-module" + }, + { + "domain": "edict.lawpack/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-manifest" + }, + { + "domain": "edict.lowering-requirements/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lowering-requirements" + }, + { + "domain": "edict.target-ir.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "target-ir-artifact" + }, + { + "domain": "edict.target-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "target-profile-manifest" + } + ] +} diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/generation-settings-v1.json b/crates/echo-wesley-gen/assets/v1/edict-provider/generation-settings-v1.json new file mode 100644 index 00000000..ab8cc166 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/generation-settings-v1.json @@ -0,0 +1,7 @@ +{ + "apiVersion": "echo.edict-provider-generation-settings/v1", + "shapeSource": "none", + "canonicalArtifactEncoding": "edict.canonical-cbor/v1", + "contractPack": "edict.provider-contract-pack.cddl@1", + "generatorAbi": "wesley.extension-generator/v1" +} diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a85ae30a7ae2c25c4fa087952b53072333f352c5 GIT binary patch literal 130679 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�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 Ha2ozU)-Q8F literal 0 HcmV?d00001 diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json new file mode 100644 index 00000000..425401f7 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -0,0 +1 @@ +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json new file mode 100644 index 00000000..3e8c6a48 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -0,0 +1 @@ +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:86d7daf0639a8879199f6f0a57acf7cb935a99fa40bd48afc652e3afcffaf304","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor new file mode 100644 index 00000000..807c2186 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor @@ -0,0 +1 @@ +fsourcedkindmtargetProfilefdigestfsha256X VbZe/T~U2-jcoordinatejecho.dpo@1gbudgetsjapiVersionxedict.authority-facts/v1qoperationProfileskp.effectfuldcorexcontinuum.profile.write/v1sallowedWriteClassesgreplacereffectWriteClassesntarget.replacegreplace \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor new file mode 100644 index 0000000000000000000000000000000000000000..a3a7b68102a0f23667ec264b602f15548bc255a0 GIT binary patch literal 243 zcmXYpJxc^J5I|QDyv|lTTZ>ycL2dmgt`QW3^K67Mne5JOOmdlt-nI%>{slof#9p+p zwf6^D3fkED4-9Dccs$;{VV|PHscy*W%EEa7)fi0`vRoLhVRdbNxYRG2&(~-A**KcJ z9?XArK88=rZ#TQg{r89OtC!2ik@7xjav&H{)xOlhcmHRbz3L?C3We`XD1}@*txsWc zAQ-sgGVLV^Nw!--UYse$*=$+sRetF|Ia`b%&;TQocasIwq@;u-wT~oi*MJgUIqQvm azzC9?{pbx@o1`pIZQQO;Tn~W=SR3B?=fWK~aOnImgys_m?`cOROqe;Jw^r;psww3q4J< zDw>z7h4e%@Z%WK7Ni0fFEpbdqEGPlGs&R38B7_OHPZ`5LsH`4HLKhfcSgiDQV%v8A zx7Y4qX_u#yUB7-@lcB0=CoJ76mtyd4vjR#=<6nf!?k?w|kn5oYBMX8QSnT@%S zI7" (EDICT-DIGEST-WIRE-001). +sha256-digest = [ algorithm: "sha256", bytes: bstr .size 32 ] + +; A named low-level failure an effect can raise. The source obstruction map +; binds it (by coordinate) and constructs a typed domain obstruction from its +; payload (EDICT-ABI-FAILURE-NAMED-001). +; An effect's `effectFailures` list MUST have unique `coordinate`s: since the +; obstruction map is keyed by coordinate, two failures sharing a coordinate (even +; with different authorityClass/payloadType) make exhaustive mapping and binder +; typing ambiguous and are rejected (EDICT-ABI-FAILURE-UNIQUE-001). +; +; Effects carry their failures as a map `{ failure-ident => effect-failure-body }` +; (see the target/lawpack effect schemas). The failure coordinate is the map +; KEY, so it is not repeated in the body and cannot disagree with the key. +effect-failure-body = { + authorityClass: authority-class, + payloadType: core-type-ref, ; typed, bounded (may be empty record) +} + +; A failure coordinate must be a bare Edict `ident` (letter/underscore then +; letters/digits/underscores) AND must not be a reserved keyword (e.g. `else`, +; `basis`, `where`, `require`, `for`, `if`). The source obstruction-map LHS only +; accepts a non-keyword `ident`, so a hyphen/dot/keyword coordinate would be +; ABI-valid yet impossible to map exhaustively in source. The regex captures the +; lexical shape; keyword exclusion is an additional validation rule +; (EDICT-ABI-FAILURE-IDENT-001). +failure-ident = tstr .regexp "[A-Za-z_][A-Za-z0-9_]*" + +effect-kind = "read" / "create" / "ensure" / "replace" / "delete" / + "append" / "reduce" / "semantic.emit" / "custom" + +authority-class = "domainMappable" / "participantOwned" / "integrityFault" / + "resourceFault" / "internalFault" + +core-type-ref = tstr ; canonical Core type coordinate + +; An operation profile supplies the optic template a Core intent resolves its +; opticKind/boundaryKind/supportPolicy/lossDisposition from. Target profiles and +; lawpacks publish these as a map `{ coordinate => operation-profile }`, so the +; coordinate is the KEY, not a value field (EDICT-OPTIC-TEMPLATE-OWNER-001, +; EDICT-ABI-OPPROFILE-UNIQUE-001). +operation-profile = { + opticTemplate: optic-template, + effectPredicate: tstr, ; coordinate of the operation-mode predicate +} + +optic-template = { + opticKind: "revelation" / "affectReintegration", + boundaryKind: "projection" / "affect", + supportPolicy: tstr, ; canonical support-policy coordinate + lossDisposition: tstr, ; canonical loss-disposition coordinate + ? basisTemplate: tstr, ; optional digest-locked basis template coord + ; the aperture requirement this template supplies. Required when the template + ; is the source of a Core optic's apertureRequirement (i.e. the intent has no + ; source `footprint <= ...`), since apertureRequirement is mandatory in Core + ; (EDICT-OPTIC-APERTURE-REF-001). + ? apertureRequirement: aperture-requirement, +} + +; apertureRequirement is a typed reference, never a free-form string. A review +; rendering may show its coordinate (EDICT-OPTIC-APERTURE-REF-001). +aperture-requirement = footprint-ceiling-ref / abstract-footprint-obligation-ref +footprint-ceiling-ref = { kind: "footprintCeiling", ref: tstr } +abstract-footprint-obligation-ref = { kind: "abstractFootprintObligation", ref: tstr } + +; --- edict-core.cddl --- +; edict-core.cddl +; Normative schema for the Edict Core v1 semantic model. +; +; Scope boundary: this file defines Core meaning and schema shape only. It does +; not define a canonical encoder, Core module hash fields, hash fixtures, target +; lowering, admission bundles, or target-owned IR. + +core-module = { + apiVersion: "edict.core/v1", + coordinate: tstr, + imports: [* core-import], + types: { * tstr => core-type }, + intents: { + tstr => core-intent }, + requiredCoreCapabilities: [* tstr], +} + +core-import = { + kind: "lawpack" / "target" / "core", + ref: resource-ref, + ? alias: tstr, +} + +; --- types --------------------------------------------------------------- + +core-type = core-scalar-type / core-record-type / core-variant-type / + core-option-type / core-list-type / core-map-type / + core-capability-ref-type + +core-scalar-type = core-bool-type / core-int-type / core-string-type / + core-bytes-type / core-unit-type + +core-bool-type = { kind: "Bool" } +core-unit-type = { kind: "Unit" } +core-int-type = { + kind: "I64" / "U64" / "I32" / "U32" / "I16" / "U16" / "I8" / "U8", +} +core-string-type = { + kind: "String", + max: uint, + canonical: "unicode-scalar-nfc" / "raw-utf8", +} +core-bytes-type = { + kind: "Bytes", + max: uint, +} +core-record-type = { + kind: "Record", + fields: { * tstr => core-type-ref }, +} +core-variant-type = { + kind: "Variant", + cases: { + tstr => variant-case-body }, +} +variant-case-body = { + ? payload: core-type-ref, +} +core-option-type = { + kind: "Option", + item: core-type-ref, +} +core-list-type = { + kind: "List", + item: core-type-ref, + max: uint, +} +core-map-type = { + kind: "Map", + key: core-type-ref, + value: core-type-ref, + max: uint, +} +core-capability-ref-type = { + kind: "CapabilityRef", + item: core-type-ref, +} + +; core-type-ref is defined in edict-common.cddl and assembled with this schema. + +; --- references and values ---------------------------------------------- + +; Local identity is alpha-stable. `id` is the compiler-owned local coordinate; +; `alphaName` is the normalized human/debug name. Source binder spelling is not +; identity. +local-ref = { + id: tstr, + alphaName: tstr, + type: core-type-ref, +} + +core-value = core-null-value / core-bool-value / core-int-value / + core-string-value / core-bytes-value / core-record-value / + core-variant-value / core-list-value / core-map-value / + core-capability-value + +core-null-value = { kind: "null" } +core-bool-value = { kind: "bool", value: bool } +core-int-value = { kind: "int", width: tstr, value: int } +core-string-value = { kind: "string", value: tstr } +core-bytes-value = { kind: "bytes", value: bstr } +core-record-value = { kind: "record", fields: { * tstr => core-value } } +core-variant-value = { + kind: "variant", + type: core-type-ref, + case: tstr, + ? payload: core-value, +} +core-list-value = { kind: "list", values: [* core-value] } +core-map-value = { kind: "map", entries: [* [key: core-value, value: core-value]] } +core-capability-value = { + kind: "capability", + receipt: sha256-digest, +} + +; Edict-authored pure helpers use a pure Core function body. The body can bind +; pure expressions and return an expression, but it cannot contain Core effect, +; guard, branch, loop, match-node, or proof-obligation nodes. +core-fn-body = { + params: [* local-ref], + body: core-pure-block, +} + +core-pure-block = { + locals: [* local-ref], + bindings: [* pure-let-node], + result: core-expr, +} + +pure-let-node = { + kind: "let", + binding: local-ref, + value: core-expr, +} + +; --- expressions and predicates ----------------------------------------- + +core-expr = local-expr / const-expr / record-expr / field-expr / + variant-expr / match-expr / call-expr / list-expr / map-expr / + if-expr + +local-expr = { kind: "local", ref: local-ref } +const-expr = { kind: "const", value: core-value } +record-expr = { kind: "record", fields: { * tstr => core-expr } } +field-expr = { kind: "field", base: core-expr, field: tstr } +variant-expr = { + kind: "variant", + type: core-type-ref, + case: tstr, + ? payload: core-expr, +} +match-expr = { + kind: "match", + scrutinee: core-expr, + arms: [+ match-arm], +} +match-arm = { + case: tstr, + ? binder: local-ref, + body: core-expr, +} +call-expr = { + kind: "call", + callee: tstr, + typeArgs: [* core-type-ref], + args: [* core-expr], +} +list-expr = { kind: "list", values: [* core-expr] } +map-expr = { kind: "map", entries: [* [key: core-expr, value: core-expr]] } +if-expr = { + kind: "if", + predicate: core-predicate, + then: core-expr, + else: core-expr, +} + +core-predicate = true-predicate / false-predicate / not-predicate / + all-predicate / any-predicate / compare-predicate / + call-predicate / obstruction-predicate + +true-predicate = { kind: "true" } +false-predicate = { kind: "false" } +not-predicate = { kind: "not", value: core-predicate } +all-predicate = { kind: "all", values: [+ core-predicate] } +any-predicate = { kind: "any", values: [+ core-predicate] } +compare-predicate = { + kind: "compare", + op: "==" / "!=" / "<" / "<=" / ">" / ">=", + left: core-expr, + right: core-expr, +} +call-predicate = { + kind: "call", + predicate: tstr, + args: [* core-expr], +} +obstruction-predicate = { + kind: "obstruction", + coordinate: failure-ident, + payload: core-expr, +} + +input-constraint = { + coordinate: tstr, + source: "where" / "compiler", + predicate: core-predicate, +} + +; --- intents, blocks, and nodes ----------------------------------------- + +core-intent = { + input: core-type-ref, + output: core-type-ref, + requiredOperationProfile: tstr, + inputConstraints: [* input-constraint], + coreEvaluationBudget: core-budget, + body: core-block, + ? optic: core-optic, +} + +core-budget = { + maxSteps: uint, + maxAllocatedBytes: uint, + maxOutputBytes: uint, +} + +core-optic = { + opticKind: "revelation" / "affectReintegration", + boundaryKind: "projection" / "affect", + apertureRequirement: aperture-requirement, + supportPolicy: tstr, + lossDisposition: tstr, +} + +core-block = { + locals: [* local-ref], + nodes: [* core-node], + result: core-expr, +} + +core-node = let-node / require-node / effect-node / guard-node / branch-node / + for-node / match-node / proof-obligation-node + +let-node = { + kind: "let", + binding: local-ref, + value: core-expr, +} +require-node = { + kind: "require", + predicate: core-predicate, + onFailure: require-failure-arm, +} +require-failure-arm = terminal-require-failure / + continue-obstructed-require-failure +terminal-require-failure = { + kind: "terminal", + reason: obstruction-reason, +} +continue-obstructed-require-failure = { + kind: "continueObstructed", + reason: obstruction-reason, +} +obstruction-reason = { + reasonKind: tstr, + payload: { * tstr => core-expr }, +} +effect-node = { + kind: "effect", + binding: local-ref, + effect: tstr, + input: core-expr, + obstructionMap: { * failure-ident => obstruction-arm }, +} +obstruction-arm = { + binder: local-ref, + value: core-expr, +} +guard-node = { + kind: "guard", + predicate: core-predicate, + obstruction: core-expr, +} +branch-node = { + kind: "branch", + predicate: core-predicate, + then: core-block, + else: core-block, +} +for-node = { + kind: "for", + binder: local-ref, + iter: core-expr, + bound: core-bound, + body: core-block, +} +match-node = { + kind: "match", + scrutinee: core-expr, + arms: [+ match-block-arm], +} +match-block-arm = { + case: tstr, + ? binder: local-ref, + body: core-block, +} +proof-obligation-node = { + kind: "proof", + coordinate: tstr, + predicate: core-predicate, +} + +core-bound = literal-bound / coordinate-bound +literal-bound = { kind: "literal", value: uint } +coordinate-bound = { kind: "coordinate", ref: tstr } + +; Shared resource-ref, sha256-digest, failure-ident, aperture-requirement, and +; core-type-ref are defined once in edict-common.cddl. + +; --- edict-lawpack.cddl --- +; edict-lawpack.cddl +; Canonical schema for the Edict lawpack manifest and export surface. +; Authoritative byte encoding: edict.canonical-cbor/v1. JSON in the prose specs +; is a review rendering generated from this schema (EDICT-ABI-NODUP-001). + +lawpack-manifest = { + apiVersion: "edict.lawpack/v1", + id: tstr, + version: tstr, + acceptedCoreAbi: [+ tstr], + dependencies: [* lawpack-dep], ; acyclic, digest-locked (EDICT-LAWPACK-DAG-001) + exports: resource-ref, + ? targetAdapters: [+ target-adapter], ; required only if any runtime effect exists + ? helperComponent: executable-component, ; executable helpers carry their own sandbox+fuel + verifier: verifier, ; classified: declarative or executable + compatibility: resource-ref, + conformanceFixtureCorpus: resource-ref, +} + +; A verifier is either a declarative ruleset (no runtime) or an executable +; component. An executable verifier MUST carry its own sandbox and fuel model, +; so the schema enforces that no executable component is left unbounded +; (EDICT-ABI-VERIFIER-BOUND-001). +verifier = declarative-verifier / executable-verifier +declarative-verifier = { class: "declarative", ruleset: resource-ref } +executable-verifier = { + class: "executable", + component: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, +} + +; Any executable component is bounded by its own sandbox + fuel model. +executable-component = { + component: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, +} + +lawpack-dep = { id: tstr, version: tstr, digest: sha256-digest } + +; Adapter selection keys SOLELY off the digest-locked `acceptedTargetProfile` +; (its `id` is the profile id; its `digest` pins the exact profile/version). There +; are no independent display strings that could disagree with the lock, so a +; resolver cannot bind an adapter to one target while the lock proves another +; (EDICT-LAWPACK-ADAPTER-TARGETIR-001). +target-adapter = { + acceptedTargetProfile: resource-ref, ; digest-locked, authoritative selector + acceptedTargetIr: resource-ref, ; digest-locked + adapter: resource-ref, +} + +; Shared types resource-ref and sha256-digest are defined once in +; edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- export surface ------------------------------------------------------ + +lawpack-exports = { + types: [* exported-type], + constants: [* exported-constant], + pureFunctions: [* pure-function], + effects: [* semantic-effect], + obstructions: [* obstruction-def], + ; keyed by operation-profile coordinate → uniqueness enforced + ; (EDICT-ABI-OPPROFILE-UNIQUE-001) + ; operation-profile records this lawpack exports (optic templates that + ; `implements`/`profile` clauses resolve against). operation-profile is + ; defined in edict-common.cddl (EDICT-ABI-OPPROFILE-SLOT-001). + operationProfiles: { * tstr => operation-profile }, ; keyed by coordinate +} + +exported-type = { coordinate: tstr, definition: core-type-ref } +exported-constant = { coordinate: tstr, type: core-type-ref, value: any } + +; A pure helper is a discriminated union by `source`, so the schema itself +; guarantees an implementation exists (EDICT-LAWPACK-PURE-IMPL-001): +; - "edict": authored in Edict/Core; the Core body is carried inline (hashed +; with the export surface). The schema requires the `body` field. +; - "component": implemented outside Edict; carries no inline body and instead +; carries its own digest-locked `implementation` (sandbox + fuel). It does +; not depend on the optional manifest-level helperComponent. +pure-function = edict-pure-function / component-pure-function + +pure-function-common = ( + coordinate: tstr, + typeParameters: [* tstr], + parameterTypes: [* core-type-ref], ; all bounded + returnType: core-type-ref, ; bounded + costTemplate: tstr, + determinismClass: "total" / "total-with-typed-diagnostic", +) + +edict-pure-function = { + pure-function-common, + source: "edict", + body: core-fn-body, ; inline, hash-significant +} + +component-pure-function = { + pure-function-common, + source: "component", + ; the digest-locked component implementing this helper. Required at the schema + ; level so a component helper can never validate without a hash-bound, + ; sandbox+fuel-described implementation (EDICT-LAWPACK-PURE-IMPL-001). + implementation: executable-component, +} + +; core-fn-body is defined by edict-core.cddl and assembled with this lawpack +; schema. It is a pure Core function body, not an effect-capable core-block. + +semantic-effect = { + coordinate: tstr, + typeParameters: [* tstr], + inputType: core-type-ref, ; bounded + outputType: core-type-ref, ; bounded + executionClass: "proofOnly" / "runtime", ; orthogonal to writeClass + effectKindHint: effect-kind, + footprintObligation: tstr, + costObligation: tstr, + effectFailures: { * failure-ident => effect-failure-body }, ; keyed by coordinate; unique + guardSupport: bool, +} + +obstruction-def = { + coordinate: tstr, + authorityClass: authority-class, + payloadSchema: core-type-ref, ; typed, bounded (may be empty record) +} + +; effect-failure-body, effect-kind, authority-class, and core-type-ref are defined +; once in edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- edict-target-profile.cddl --- +; edict-target-profile.cddl +; Canonical schema for the Edict target profile manifest. +; Authoritative byte encoding: edict.canonical-cbor/v1 +; (see SPEC_continuum-contract-bundle-v1.md). JSON in the prose specs is a +; review rendering generated from this schema; this CDDL is the single source +; of truth (EDICT-ABI-NODUP-001). + +target-profile-manifest = { + apiVersion: "edict.target-profile/v1", + id: tstr, ; e.g. "echo.dpo" + version: tstr, ; e.g. "1" + acceptedCoreAbi: [+ tstr], ; e.g. ["edict.core/v1"] + + intrinsics: resource-ref, + intrinsicNamespace: tstr, + ; publishes this profile's operation-profile records (optic templates that + ; `profile`/`implements` clauses resolve against). References an + ; operation-profiles-document (EDICT-ABI-OPPROFILE-SLOT-001). + operationProfiles: resource-ref, + footprintAlgebra: resource-ref, + costAlgebra: resource-ref, + targetIr: resource-ref, + obstructionTaxonomy: resource-ref, + verifier: resource-ref, + lowerer: resource-ref, + sandbox: resource-ref, + fuelModel: resource-ref, + + ; fields the language spec requires of every profile + bundleProfile: resource-ref, + generatedArtifactProfiles: [* resource-ref], + canonicalEncodingRules: resource-ref, + ; Reserved/deferred: will list accepted lawpack-adapter ABI ids once that + ; byte-level ABI (edict.lawpack-adapter/v1) is specified. The schema enforces + ; emptiness now — the type is the empty array, so non-empty values are + ; rejected, not merely discouraged (EDICT-ABI-LAWPACK-ADAPTER-DEFER-001). + ? acceptedLawpackAdapterAbi: [], + diagnosticAbi: resource-ref, + + ; application doctrine + applicationModel: "atomic", + readConsistency: "application-snapshot" / tstr, + guardEvaluation: "precommit-atomic" / tstr, + obstructionRollback: "no-visible-effects" / tstr, + multiTarget: bool, + ; whether the target can evaluate precommit postcondition (`guarantee`) checks + ; inside the atomic application unit (EDICT-TARGET-POSTCOND-001) + postconditionSupport: bool, + + deterministicExecution: resource-ref, + conformanceFixtureCorpus: resource-ref, +} + +; Shared types resource-ref and sha256-digest are defined once in +; edict-common.cddl and assembled with this schema by the build +; (EDICT-ABI-NODUP-001). They are not redefined here. + +; --- intrinsic signature ------------------------------------------------- +; The artifact referenced by the manifest's `intrinsics` resource-ref is the +; intrinsic-signature corpus document below. Its layout is fixed so two +; independent profiles validate/hash the corpus identically +; (EDICT-ABI-INTRINSICS-DOC-001). + +; intrinsics is a MAP keyed by coordinate, so the schema itself enforces +; coordinate uniqueness. A provider receives the resolved corpus as a +; digest-bound semantic input and resolves coordinates within that artifact. +; Each map key MUST equal its record's `coordinate` field +; (EDICT-ABI-INTRINSIC-UNIQUE-001). +intrinsics-document = { + apiVersion: "edict.target-profile.intrinsics/v1", + intrinsics: { * tstr => intrinsic }, +} + +; The artifact referenced by the manifest's `operationProfiles` resource-ref. +; operation-profile / optic-template are defined in edict-common.cddl. Keyed by +; coordinate so resolution can't pick between two same-coordinate profiles +; (EDICT-ABI-OPPROFILE-SLOT-001, EDICT-ABI-OPPROFILE-UNIQUE-001). +operation-profiles-document = { + apiVersion: "edict.target-profile.operation-profiles/v1", + profiles: { * tstr => operation-profile }, +} + +; A typed pre-lowering question that can be proposed by Watson or an agent and +; checked by the compiler. It is canonical-CBOR encoded under +; `edict.lowering-requirements/v1`; the compiler checks this artifact, not the +; prose that produced it. +lowering-requirements = { + apiVersion: "edict.lowering-requirements/v1", + operationProfile: tstr, + semanticEffects: [* semantic-effect-requirement], + requiredWriteClasses: [* write-class], + guardKinds: [* guard-kind], + atomicity: atomicity-requirement, + postconditionSupport: bool, + obstructionCoordinates: [* tstr], + footprintObligations: [* tstr], + costObligations: [* tstr], + opticContract: tstr, +} + +semantic-effect-requirement = { + coordinate: tstr, + writeClass: write-class, + guardKinds: [* guard-kind], + obstructionCoordinates: [* tstr], + footprintObligations: [* tstr], + costObligations: [* tstr], +} + +write-class = "none" / "read" / "create" / "ensure" / "append" / + "replace" / "delete" / tstr +guard-kind = "precommit-atomic" / tstr +atomicity-requirement = "atomic" / tstr + +; A genuine union: pure constructors carry no effect kind or failures; effect +; intrinsics must (EDICT-TARGET-INTRINSIC-CLASS-001). The schema enforces this, +; not a comment. + +; The intrinsic's coordinate is the intrinsics map KEY, not a value field, so the +; key and coordinate can never disagree (EDICT-ABI-INTRINSIC-UNIQUE-001). +intrinsic = pure-intrinsic / effect-intrinsic + +pure-intrinsic = { + intrinsicClass: "pure", + typeParameters: [* tstr], + argumentTypes: [* core-type-ref], + returnType: core-type-ref, + guardSupport: false, + footprintTemplate: tstr, + costTemplate: tstr, + writeClass: "none", +} + +effect-intrinsic = { + intrinsicClass: "effect", + typeParameters: [* tstr], + argumentTypes: [* core-type-ref], + returnType: core-type-ref, + effectKind: effect-kind, + ; map keyed by failure coordinate (failure-ident); the failure coordinate is + ; the key, not a value field, so uniqueness is structural + ; (EDICT-ABI-FAILURE-UNIQUE-001). + effectFailures: { * failure-ident => effect-failure-body }, + guardSupport: bool, + footprintTemplate: tstr, + costTemplate: tstr, + writeClass: "read" / "create" / "ensure" / "append" / "replace" / + "delete" / "custom", + canParticipateInAtomicGuard: bool, +} + +; effect-failure-body, effect-kind, authority-class, and core-type-ref are defined +; once in edict-common.cddl and assembled with this schema (EDICT-ABI-NODUP-001). + +; --- edict-authority-facts.cddl --- +; edict-authority-facts.cddl +; Canonical schema for the first compiler-context authority-facts document. +; Authoritative byte encoding: edict.canonical-cbor/v1. +; +; This schema is assembled with edict-common.cddl so source.digest uses the +; shared sha256-digest typed value. JSON is a review/input rendering: its +; `sha256:<64 hex>` source digest is projected to [`sha256`, 32 raw bytes] on +; the wire, and its fact arrays project to the coordinate-keyed maps below. + +authority-facts = { + apiVersion: "edict.authority-facts/v1", + source: authority-fact-source, + operationProfiles: { * tstr => authority-operation-profile-fact }, + effectWriteClasses: { * tstr => authority-write-class }, + budgets: { * tstr => authority-budget-fact }, +} + +authority-fact-source = { + kind: "lawpack" / "targetProfile", + coordinate: tstr, + digest: sha256-digest, +} + +; The map key is the source operation-profile coordinate. It is not repeated in +; the value, so a key and embedded coordinate cannot disagree. Allowed write +; classes are a canonical map-set: the class is the unique key and null is the +; unit marker. Canonical CBOR fixes key order without a second ordering rule. +authority-operation-profile-fact = { + core: tstr, + allowedWriteClasses: { * authority-write-class => null }, +} + +; The effectWriteClasses map key is the semantic effect coordinate. The budgets +; map key is the source budget coordinate. Canonical CBOR map-key uniqueness +; makes duplicate fact coordinates structurally unrepresentable. +authority-budget-fact = { + maxSteps: uint, + maxAllocatedBytes: uint, + maxOutputBytes: uint, +} + +; AuthorityFactsDocument v1 intentionally accepts only the write classes the +; current compiler model can consume. `custom` is the sole v1 custom spelling; +; arbitrary target-profile extension strings do not enter this compiler path. +authority-write-class = "none" / "read" / "create" / "ensure" / "append" / + "replace" / "delete" / "custom" + +; --- edict-target-ir.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-target-ir.cddl +; Canonical schema for the Edict-owned Target IR artifact envelope. +; Authoritative byte encoding: edict.canonical-cbor/v1. +; +; This schema is assembled with edict-common.cddl and edict-core.cddl. It +; deliberately reuses Core expressions, predicates, budgets, local references, +; obstruction reasons, and obstruction arms so the schema matches the value +; emitted by the canonical Target IR encoder rather than restating those types. +; It describes the structural shape of valid lowering-produced artifacts. The +; lowering and encoder contracts separately enforce semantic identifier rules +; and canonical ordering/deduplication for set-like values. + +; Target IR encoding rejects an empty target-profile coordinate before bytes +; exist, so this root tightens the shared structural resource-ref accordingly. +target-ir-resource-ref = { + id: tstr .regexp "(?s).+", + digest: sha256-digest, +} + +target-ir-artifact = { + kind: "targetIrArtifact", + domain: tstr, + targetProfile: target-ir-resource-ref, + sourceCoreCoordinate: tstr, + intents: { * tstr => target-ir-intent }, +} + +target-ir-intent = { + operationProfile: tstr, + inputConstraints: [* input-constraint], + coreEvaluationBudget: core-budget, + requirements: [* target-ir-requirement], + steps: [* target-ir-step], + result: core-expr, +} + +target-ir-requirement = { + id: tstr, + predicate: core-predicate, + onFailure: require-failure-arm, +} + +target-ir-step = { + id: tstr, + binding: local-ref, + effect: tstr, + targetIntrinsic: tstr, + input: core-expr, + obstructionFailures: [* failure-ident], + obstructionArms: { * failure-ident => obstruction-arm }, +} + + +; --- Echo provider-generated declarative contracts ----------------------- +; These roots validate provider semantic descriptions. They confer no Echo +; runtime authority and contain no package, component, or installation state. + +generated-artifact-profile = { + apiVersion: "echo.generated-artifact-profile/v1", + targetProfile: tstr, + types: { * tstr => echo-generated-type }, + operations: { * tstr => generated-operation }, +} + +echo-generated-type = echo-generated-string-alias / echo-generated-record +echo-generated-string-alias = { + kind: "coreStringAlias", + maxScalarValues: uint, + canonical: "raw-utf8", +} +echo-generated-record = { + kind: "record", + fields: [* echo-generated-record-field], +} +echo-generated-record-field = { name: tstr, type: tstr } + +generated-operation = { + inputType: tstr, + outputType: tstr, + effect: tstr, + operationProfile: tstr, + opticContract: tstr, + budget: tstr, + invocationKind: "mutation" / "observer", + implementation: { kind: "native" / "directAdapter", coordinate: tstr }, + obstructionMappings: { * tstr => tstr }, +} + +echo-provider-conformance-corpus = { + apiVersion: "echo.edict-provider.conformance-corpus/v1", + class: "declarative", + operations: { * tstr => null }, + capabilities: { * tstr => null }, + semanticEffects: { * tstr => null }, + cases: [], +} + +echo-provider-lawpack-compatibility = { + apiVersion: "echo.edict-provider.lawpack-compatibility/v1", + class: "declarative", + acceptedCoreAbi: { * tstr => null }, + acceptedTargetProfiles: { * tstr => null }, + semanticEffects: { * tstr => null }, +} + +echo-provider-lawpack-target-adapter = { + apiVersion: "echo.edict-provider.lawpack-target-adapter/v1", + class: "declarative", + targetProfile: tstr, + targetIrDomain: tstr, + effectImplementations: { * tstr => echo-effect-implementation }, +} + +echo-effect-implementation = echo-native-effect-implementation / echo-direct-effect-implementation +echo-native-effect-implementation = { + kind: "native", + capability: tstr, + writeClass: tstr, +} +echo-direct-effect-implementation = { + kind: "directAdapter", + adapter: tstr, + capability: tstr, + writeClass: tstr, +} + +echo-provider-lawpack-verifier = { + apiVersion: "echo.edict-provider.lawpack-verifier/v1", + class: "declarative", + operationObstructions: { * tstr => echo-operation-obstructions }, +} +echo-operation-obstructions = { + effect: tstr, + failureMappings: { * failure-ident => tstr }, +} + +echo-dpo-bundle = { + apiVersion: "echo.dpo.bundle/v1", + class: "declarative", + applicationModel: tstr, + readConsistency: tstr, + operationProfiles: { * tstr => null }, +} + +echo-dpo-cost = { + apiVersion: "echo.dpo.cost/v1", + class: "declarative", + capabilities: { * tstr => echo-cost-capability }, +} +echo-cost-capability = { + effect: tstr, + costTemplate: tstr, + semanticObligation: tstr, +} + +echo-dpo-footprint = { + apiVersion: "echo.dpo.footprint/v1", + class: "declarative", + capabilities: { * tstr => echo-footprint-capability }, +} +echo-footprint-capability = { + effect: tstr, + footprintTemplate: tstr, + semanticObligation: tstr, + writeClass: tstr, +} + +echo-span-ir = { + apiVersion: "echo.span-ir/v1", + class: "declarative", + domain: tstr, + targetProfile: tstr, + capabilities: { * tstr => null }, +} + +echo-dpo-lowerer = { + apiVersion: "echo.dpo.lowerer/v1", + class: "declarative", + acceptedCoreAbi: { * tstr => null }, + outputDomain: tstr, + targetProfile: tstr, + effectImplementations: { * tstr => echo-effect-implementation }, + opticContracts: { * tstr => tstr }, +} + +echo-dpo-obstructions = { + apiVersion: "echo.dpo.obstructions/v1", + class: "declarative", + effectFailures: { * tstr => { authorityClass: authority-class, payloadType: tstr } }, + domainObstructions: { * tstr => { authorityClass: authority-class, payloadSchema: tstr } }, +} + +echo-dpo-verifier = { + apiVersion: "echo.dpo.verifier/v1", + class: "declarative", + targetProfile: tstr, + targetIrDomain: tstr, + capabilities: { * tstr => null }, + operationProfiles: { * tstr => null }, + opticContracts: { * tstr => tstr }, +} + +echo-nonempty-tstr = tstr .regexp "(?s).+" + +generated-artifact = { + apiVersion: "echo.generated-artifact/v1", + profile: resource-ref, + operation: echo-nonempty-tstr, + mediaType: echo-nonempty-tstr, + bytes: bstr, +} + +review-payload = { + apiVersion: "echo.review-payload/v1", + authoritative: false, + subject: resource-ref, + mediaType: echo-nonempty-tstr, + bytes: bstr, +} + +verifier-report = { + apiVersion: "echo.verifier-report/v1", + targetIr: resource-ref, + outcome: "accepted" / "rejected", + diagnosticAbi: resource-ref, + diagnosticBytes: bstr, +} diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor new file mode 100644 index 0000000000000000000000000000000000000000..b3ca78618d56814e4c4ff166e45f966b30dc899b GIT binary patch literal 1733 zcmZuxeNYr-7{}6)B1H#ODr8K}$Y#+a3MeBGL7U{;0g^)ZcHiB5VRzr<-FNR!Q3Ogy z>zYClQb4JgQNljNP;o%~s4yUyOM)?VU_fz(Li+%#8EM+RgM(@I&wZX}f6w##*ggBC z8L}3@SWpNnBVIr@fC2tQD=L%4kcr|dtBGSF4-`_&DHb~Pg%>lItZNIt`)fzi*wXPM zt+!yz^3nbcg^L0mo$+(;wI7^yrkq!3i8Uj;4rl``WJrjORz!+HqKqUU5hKt?vJ#vh zJduN~X|Jk#zUmi1Ep4Y?!zs!wjz(MJn;E5Hgw5^b^&8uNg><~kU;4pwAZq98WH z^~zXSU>SSt(2Y*-{HVYln{&roi!VhqH&FZHkND#Ut1KEWMD zh7sZh7=6Oo-L#;yW={Qq_4MJ{OQ=fUAm*DH!iuIYpVZ^IqAC!$$z|WDXjUaw0Lg9| z`U31(;BFbM_-tlG(|7m$?+T~8%ekfZy&o>>HN{o6=a)S6#+wx*`!9$rqB=k zsG}0M{!?|u2sd~f*A_2Z5Lw*jz46)WC+oXcnu` zS+O7@Pb<3e!?|CUIixi;i>KS6deriCjfjorpU&j(6dtq zA1S@vySo+UAsJxT852&pGGq_(pnLk0i8ItM?P($9{*^_?c3gq$GFz%5O6r_hm8E}G z*6!RtXU&$G3-#mO8BL@`pnb0l$eCObZBmd~Ay{Q}=~9s(m}w>#ONg>U1)2pw0geL< zQKpY=qU}gR;x^r4d%z@A$TT3sJCip1Rc+mxcDZm@a-NrU`0)9!hUQ;fndY0F^}4Af zFp4FzmK_F3EYxpFQ)L-pGG=9H2}zn=LY%}P7D{}oDgc*K6Cb5#fMU$Z@JHkv7GD{t zwXTeHv?QHaym{cyjGFqLe*IwurNba=)VIpY0s^oIB`qP4iL(Pn)lZlnVb6eQT|B0K zeVn^xC|~e}Tl1D@J9b?k$FXMyk3Dy@?^;Sz%+JxkhZppH-Z%p7kMls%^90x!Odv-y zWHMGo|8oihUSsNxo)MkrZL1UZgjoWf`r+U^&-9-?*Ks*N-@E11+G~5Ocjx``cHMu@ C+TC^l literal 0 HcmV?d00001 diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor new file mode 100644 index 00000000..4464f53c --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor @@ -0,0 +1 @@ +ecaseseclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperationsga.b@1.tlcapabilitiesrecho.dpo@1.replaceosemanticEffectsntarget.replace \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor new file mode 100644 index 00000000..a703b6fc --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionx,echo.edict-provider.lawpack-compatibility/v1oacceptedCoreAbimedict.core/v1osemanticEffectsntarget.replacevacceptedTargetProfilesjecho.dpo@1 \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor new file mode 100644 index 00000000..a0887cb0 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor @@ -0,0 +1 @@ +etypesjcoordinateha.b@1.Idjdefinitionx!StringgeffectsiinputTypeha.b@1.Idjcoordinatentarget.replacejoutputTypema.b@1.ReceiptlguardSupportncostObligationstarget.replace.costneffectFailureshrejectedkpayloadTypewtarget.replace.rejectednauthorityClassndomainMappableneffectKindHintgreplacenexecutionClassgruntimentypeParameterssfootprintObligationxtarget.replace.footprinticonstantslobstructionsjcoordinatetdomain.WriteRejectedmpayloadSchemaxdomain.WriteRejected.PayloadnauthorityClassndomainMappablempureFunctionsqoperationProfiles \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor new file mode 100644 index 00000000..5a57d65b --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionx-echo.edict-provider.lawpack-target-adapter/v1mtargetProfilejecho.dpo@1ntargetIrDomainoecho.span-ir/v1ueffectImplementationsntarget.replacedkindfnativejcapabilityrecho.dpo@1.replacejwriteClassgreplace \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor new file mode 100644 index 00000000..a6d10bd7 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionx'echo.edict-provider.lawpack-verifier/v1uoperationObstructionsga.b@1.tfeffectntarget.replaceofailureMappingshrejectedtdomain.WriteRejected \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor new file mode 100644 index 00000000..4c13093f --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionrecho.dpo.bundle/v1oreadConsistencytapplication-snapshotpapplicationModelfatomicqoperationProfilesxcontinuum.profile.write/v1 \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor new file mode 100644 index 00000000..2242fed3 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionpecho.dpo.cost/v1lcapabilitiesrecho.dpo@1.replacefeffectntarget.replacelcostTemplatestarget.replace.costrsemanticObligationstarget.replace.cost \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor new file mode 100644 index 00000000..3118bbd0 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionuecho.dpo.footprint/v1lcapabilitiesrecho.dpo@1.replacefeffectntarget.replacejwriteClassgreplaceqfootprintTemplatextarget.replace.footprintrsemanticObligationxtarget.replace.footprint \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor new file mode 100644 index 00000000..3250617a --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor @@ -0,0 +1 @@ +japiVersionx"edict.target-profile.intrinsics/v1jintrinsicsrecho.dpo@1.replacejeffectKindgreplacejreturnTypema.b@1.ReceiptjwriteClassgreplacelcostTemplatestarget.replace.costlguardSupportmargumentTypesha.b@1.IdneffectFailureshrejectedkpayloadTypewtarget.replace.rejectednauthorityClassndomainMappablenintrinsicClassfeffectntypeParametersqfootprintTemplatextarget.replace.footprintxcanParticipateInAtomicGuard \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-ir.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-ir.cbor new file mode 100644 index 00000000..47cd6d6a --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-ir.cbor @@ -0,0 +1 @@ +eclasskdeclarativefdomainoecho.span-ir/v1japiVersionoecho.span-ir/v1lcapabilitiesrecho.dpo@1.replacemtargetProfilejecho.dpo@1 \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor new file mode 100644 index 00000000..102f1d90 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionsecho.dpo.lowerer/v1loutputDomainoecho.span-ir/v1mtargetProfilejecho.dpo@1nopticContractsxcontinuum.profile.write/v1mreplace-pointoacceptedCoreAbimedict.core/v1ueffectImplementationsntarget.replacedkindfnativejcapabilityrecho.dpo@1.replacejwriteClassgreplace \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor new file mode 100644 index 00000000..a15d8a30 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersionxecho.dpo.obstructions/v1neffectFailureswtarget.replace.rejectedkpayloadTypewtarget.replace.rejectednauthorityClassndomainMappablerdomainObstructionstdomain.WriteRejectedmpayloadSchemaxdomain.WriteRejected.PayloadnauthorityClassndomainMappable \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor new file mode 100644 index 00000000..f4445c6a --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor @@ -0,0 +1 @@ +hprofilesxcontinuum.profile.write/v1mopticTemplateiopticKindsaffectReintegrationlboundaryKindfaffectmsupportPolicyx&continuum.support.carry-or-obstruct/v1olossDispositionx#continuum.support.reject-on-loss/v1sapertureRequirementcrefxtarget.replace.footprintdkindxabstractFootprintObligationoeffectPredicatex'echo.dpo.operation-mode.replace-only/v1japiVersionx*edict.target-profile.operation-profiles/v1 \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor new file mode 100644 index 00000000..6fd4f838 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor @@ -0,0 +1 @@ +eclasskdeclarativejapiVersiontecho.dpo.verifier/v1lcapabilitiesrecho.dpo@1.replacemtargetProfilejecho.dpo@1nopticContractsxcontinuum.profile.write/v1mreplace-pointntargetIrDomainoecho.span-ir/v1qoperationProfilesxcontinuum.profile.write/v1 \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json new file mode 100644 index 00000000..708ab173 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json @@ -0,0 +1,338 @@ +{ + "apiVersion": "edict.provider-manifest/v1", + "providerAbi": "edict:target-provider@1.0.0", + "provider": { + "coordinate": "echo.edict-provider@1", + "digest": "sha256:af5be6b5670d559ba7a7bf5867ae51c0cdd7938fcaf147167640b50f1b27b688" + }, + "artifacts": [ + { + "role": "authority-facts.echo-dpo", + "artifactKind": "authorityFacts", + "resource": { + "coordinate": "echo.dpo-authority-facts@1", + "digest": "sha256:5c30871b115e82415980714281e250c2fda281afb4a4fe16c2917f93e86182a4" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "authority-facts.echo-lawpack", + "artifactKind": "authorityFacts", + "resource": { + "coordinate": "echo.dpo-lawpack-authority-facts@1", + "digest": "sha256:37591478584a88d3dc08a620873d803a2d6fcf5dc70767aae3587e5862ee99e9" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "generated-artifact-profile.echo-dpo-registration", + "artifactKind": "generatedArtifactProfile", + "resource": { + "coordinate": "echo.dpo.registration/v1", + "digest": "sha256:3377304d8634681821cd958427e0b8baccc37b7b08bfb342d988a08571eb83ab" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "lawpack.echo-dpo", + "artifactKind": "lawpack", + "resource": { + "coordinate": "echo.dpo-lawpack@1", + "digest": "sha256:47006be4c2b569f13759078c560fe508e158b429cd9d4c5e47d9a7ea86b983b2" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "lowerer.echo-dpo", + "artifactKind": "lowerer", + "resource": { + "coordinate": "echo.dpo.lowerer/component@1", + "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + }, + "source": { + "kind": "component", + "component": { + "coordinate": "echo.dpo.lowerer/component@1", + "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + } + } + }, + { + "role": "provenance.provider-generation", + "artifactKind": "generationProvenance", + "resource": { + "coordinate": "echo.edict-provider-generation-provenance@1", + "digest": "sha256:9c64b8526c8183f1bc82507fabf2d24627d51d048d9bf98df29cec56e8648d79" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "review.provider-generation", + "artifactKind": "reviewArtifact", + "resource": { + "coordinate": "echo.edict-provider-generation-review@1", + "digest": "sha256:7b055bdd6f7d40c05ccca2010c3bad7012533fcc634fc207758bb7ed61e8e5d6" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "schema.echo-provider-artifacts", + "artifactKind": "artifactSchema", + "resource": { + "coordinate": "echo.provider-artifacts.cddl@1", + "digest": "sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "target-profile.echo-dpo", + "artifactKind": "targetProfile", + "resource": { + "coordinate": "echo.dpo@1", + "digest": "sha256:f41df38156625a05c1ee8bce652ffddf04e71b54fe027eeab9d255d0d8322db0" + }, + "source": { + "kind": "generated", + "semanticSource": { + "coordinate": "echo.semantic-schema@1", + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" + }, + "generator": { + "coordinate": "echo-wesley-gen.provider-artifact-generator@1", + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + } + } + }, + { + "role": "verifier.echo-dpo", + "artifactKind": "verifier", + "resource": { + "coordinate": "echo.dpo.verifier/component@1", + "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + }, + "source": { + "kind": "component", + "component": { + "coordinate": "echo.dpo.verifier/component@1", + "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + } + } + } + ], + "schemaBindings": [ + { + "domain": "echo.dpo-lawpack.adapter.echo-dpo@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-target-adapter" + }, + { + "domain": "echo.dpo-lawpack.compatibility@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-compatibility" + }, + { + "domain": "echo.dpo-lawpack.exports@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-exports" + }, + { + "domain": "echo.dpo-lawpack.verifier@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-verifier" + }, + { + "domain": "echo.dpo.bundle/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-bundle" + }, + { + "domain": "echo.dpo.cost/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-cost" + }, + { + "domain": "echo.dpo.fixtures/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-conformance-corpus" + }, + { + "domain": "echo.dpo.footprint/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-footprint" + }, + { + "domain": "echo.dpo.intrinsics/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "intrinsics-document" + }, + { + "domain": "echo.dpo.lowerer/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-lowerer" + }, + { + "domain": "echo.dpo.obstructions/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-obstructions" + }, + { + "domain": "echo.dpo.operation-profiles/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "operation-profiles-document" + }, + { + "domain": "echo.dpo.verifier/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-verifier" + }, + { + "domain": "echo.generated-artifact-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact-profile" + }, + { + "domain": "echo.generated-artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact" + }, + { + "domain": "echo.review-payload/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "review-payload" + }, + { + "domain": "echo.span-ir/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-span-ir" + }, + { + "domain": "echo.verifier-report/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "verifier-report" + }, + { + "domain": "edict.authority-facts/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "authority-facts" + }, + { + "domain": "edict.core.module/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "core-module" + }, + { + "domain": "edict.lawpack/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-manifest" + }, + { + "domain": "edict.lowering-requirements/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lowering-requirements" + }, + { + "domain": "edict.target-ir.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "target-ir-artifact" + }, + { + "domain": "edict.target-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "target-profile-manifest" + } + ] +} diff --git a/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source b/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source new file mode 100644 index 00000000..87729c4c --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source @@ -0,0 +1,2785 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "apollo-parser" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "947e21ff51879f8a40d7519dfe619268de2afba4042a8a43878276de3cb910f0" +dependencies = [ + "memchr", + "rowan", + "thiserror 2.0.17", +] + +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "assert_cmd" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514" +dependencies = [ + "anstyle", + "bstr", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cap-fs-ext" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78e5a3368ae89b7cb68186411452b4b9fac8b41be9c19bf3f47c2d2c8e36e6b" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes 3.0.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "cap-primitives" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdadbd7c002d3a484b35243669abdae85a0ebaded5a61117169dc3400f9a7ff0" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes 3.0.1", + "ipnet", + "maybe-owned", + "rustix", + "rustix-linux-procfs", + "windows-sys 0.61.2", + "winx", +] + +[[package]] +name = "cap-std" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7281235d6e96d3544ca18bba9049be92f4190f8d923e3caef1b5f66cfa752608" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes 3.0.1", + "rustix", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cddl-cat" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0def7310489015a41757b6ae8a0126ad1d91c4a3f77089f862eea7c000638825" +dependencies = [ + "base64", + "ciborium", + "escape8259", + "float-ord", + "hex", + "nom", + "regex", + "serde", + "strum_macros", + "thiserror 1.0.69", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "clap_mangen" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ea63a92086df93893164221ad4f24142086d535b3a0957b9b9bea2dc86301" +dependencies = [ + "clap", + "roff", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "comfy-table" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" +dependencies = [ + "crossterm", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "document-features", + "parking_lot", + "rustix", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "echo-cas" +version = "0.1.0" +dependencies = [ + "blake3", + "thiserror 2.0.17", +] + +[[package]] +name = "echo-dind-harness" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "echo-dind-tests", + "echo-wasm-abi", + "hex", + "serde", + "serde_json", + "warp-core", +] + +[[package]] +name = "echo-dind-tests" +version = "0.1.0" +dependencies = [ + "bytes", + "echo-dry-tests", + "echo-wasm-abi", + "warp-core", +] + +[[package]] +name = "echo-dry-tests" +version = "0.1.0" +dependencies = [ + "blake3", + "bytes", + "echo-graph", + "warp-core", +] + +[[package]] +name = "echo-edict-canonical" +version = "0.1.0" +dependencies = [ + "hex", + "sha2", +] + +[[package]] +name = "echo-edict-provider-lowerer" +version = "0.1.0" +dependencies = [ + "echo-edict-canonical", + "hex", + "sha2", + "wit-bindgen 0.58.0", +] + +[[package]] +name = "echo-edict-provider-verifier" +version = "0.1.0" +dependencies = [ + "echo-edict-canonical", + "hex", + "sha2", + "wit-bindgen 0.58.0", +] + +[[package]] +name = "echo-file-aperture" +version = "0.1.0" +dependencies = [ + "blake3", + "thiserror 2.0.17", +] + +[[package]] +name = "echo-graph" +version = "0.1.0" +dependencies = [ + "anyhow", + "blake3", + "ciborium", + "serde", + "warp-core", +] + +[[package]] +name = "echo-registry-api" +version = "0.1.0" + +[[package]] +name = "echo-runtime-schema" +version = "0.1.0" +dependencies = [ + "ciborium", + "serde", +] + +[[package]] +name = "echo-scene-codec" +version = "0.1.0" +dependencies = [ + "echo-scene-port", + "hex", + "minicbor", + "rand 0.8.6", +] + +[[package]] +name = "echo-scene-port" +version = "0.1.0" +dependencies = [ + "hex", + "rand 0.8.6", + "serde_json", + "thiserror 2.0.17", +] + +[[package]] +name = "echo-trace" +version = "0.1.0" + +[[package]] +name = "echo-wasm-abi" +version = "0.1.0" +dependencies = [ + "blake3", + "ciborium", + "half", + "proptest", + "serde", + "serde-value", + "serde_json", + "thiserror 2.0.17", +] + +[[package]] +name = "echo-wesley-gen" +version = "0.1.0" +dependencies = [ + "anyhow", + "blake3", + "cap-fs-ext", + "cap-std", + "cddl-cat", + "ciborium", + "clap", + "echo-edict-canonical", + "hex", + "prettyplease", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "syn 2.0.111", + "warp-core", + "wesley-core", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "escape8259" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes 2.0.4", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", + "serde", + "serde_core", +] + +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "hdrhistogram" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "byteorder", + "num-traits", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "io-extras" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f" +dependencies = [ + "io-lifetimes 3.0.1", + "windows-sys 0.60.2", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + +[[package]] +name = "io-lifetimes" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96" + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "minicbor" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0452a60c1863c1f50b5f77cd295e8d2786849f35883f0b9e18e7e6e1b5691b0" +dependencies = [ + "minicbor-derive", +] + +[[package]] +name = "minicbor-derive" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2209fff77f705b00c737016a48e73733d7fbccb8b007194db148f03561fb70" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "ninelives" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb329d63297228258d6747b37dcaaf6d9daa83ea7473b6b5c248ce87e93219d" +dependencies = [ + "async-trait", + "futures", + "rand 0.9.3", + "tokio", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.111", +] + +[[package]] +name = "proc-macro2" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand 0.9.3", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "pulldown-cmark" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c41efbf8f90ac44de7f3a868f0867851d261b56291732d0cbf7cceaaeb55a6" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.3", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "roff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" + +[[package]] +name = "rowan" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" +dependencies = [ + "countme", + "hashbrown 0.14.5", + "rustc-hash 1.1.0", + "text-size", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "serde_json" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +dependencies = [ + "indexmap", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum_macros" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "hdrhistogram", + "indexmap", + "pin-project-lite", + "slab", + "sync_wrapper", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "warp-benches" +version = "0.1.0" +dependencies = [ + "blake3", + "bytes", + "criterion", + "echo-dry-tests", + "rayon", + "rustc-hash 2.1.1", + "warp-core", +] + +[[package]] +name = "warp-cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "assert_cmd", + "bytes", + "clap", + "comfy-table", + "echo-registry-api", + "echo-wasm-abi", + "hex", + "predicates", + "regex", + "serde", + "serde_json", + "tempfile", + "warp-core", +] + +[[package]] +name = "warp-core" +version = "0.1.1" +dependencies = [ + "blake3", + "bytemuck", + "bytes", + "echo-cas", + "echo-dry-tests", + "echo-registry-api", + "echo-runtime-schema", + "echo-wasm-abi", + "hex", + "proptest", + "rustc-hash 2.1.1", + "thiserror 1.0.69", + "warp-math", +] + +[[package]] +name = "warp-geom" +version = "0.1.0" +dependencies = [ + "warp-math", +] + +[[package]] +name = "warp-math" +version = "0.1.0" +dependencies = [ + "echo-wasm-abi", + "libm", + "serde", + "serde-value", +] + +[[package]] +name = "warp-wasm" +version = "0.1.0" +dependencies = [ + "blake3", + "console_error_panic_hook", + "echo-registry-api", + "echo-wasm-abi", + "js-sys", + "serde", + "serde-value", + "warp-core", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen 0.46.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.111", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a879a421bd17c528b74721b2abf4c62e8f1d1889c2ba8c3c50d02deaf2ce395" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f998ccc6e012f7b86865eb2a106c8a0422017a1a88977ce01a69f2244be2e57" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437970b35b1a85cfde9c74b2398352d8d653f3bd8e3a3db0c063ea8f5b4b36ff" +dependencies = [ + "bitflags", + "hashbrown 0.17.1", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "web-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wesley-core" +version = "0.3.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca44ae03bac1966eaa6d7660621160f10d3e6979bac26f5929a25a3829c1f4" +dependencies = [ + "apollo-parser", + "async-trait", + "chrono", + "hex", + "indexmap", + "ninelives", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "tower 0.4.13", + "yaml-rust2", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "wit-bindgen" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a43552cfa071f246cfd99e5dbb23710dfe7336b3259e09339818483359470749" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4738d1c9a78e97bc7f664bfafd5d8e67d7bb26faa5c41e6d628e8bbdad3ec351" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1130ce1f531bc9f9a75922244aa773bf5e2117fda1ef4a86b9f98d6b8135eb46" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease", + "syn 2.0.111", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07296369e4d598e7e79b64eef66f724d83324ea671bcf677d78fc5cf92604ae5" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.111", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a5e60173c413659c689f0581b0cf5d1a2404077568f9ffdce748a9eb2fc913" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e960732e824fab95099971a09e638979347c94ca48568d3c854c945729196947" +dependencies = [ + "anyhow", + "hashbrown 0.17.1", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "xtask" +version = "0.1.0" +dependencies = [ + "anyhow", + "blake3", + "bytes", + "clap", + "clap_mangen", + "hex", + "pulldown-cmark", + "same-file", + "serde", + "serde_json", + "sha2", + "time", + "warp-cli", + "warp-core", + "wasm-encoder", + "wasmparser", + "wit-component", + "wit-parser", +] + +[[package]] +name = "yaml-rust2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631a50d867fafb7093e709d75aaee9e0e0d5deb934021fcea25ac2fe09edc51e" +dependencies = [ + "arraydeque", + "hashlink", +] + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "zmij" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d" diff --git a/crates/echo-wesley-gen/assets/v1/repository/Cargo.toml.source b/crates/echo-wesley-gen/assets/v1/repository/Cargo.toml.source new file mode 100644 index 00000000..a763c35c --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/repository/Cargo.toml.source @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: Apache-2.0 +# © James Ross Ω FLYING•ROBOTS +[workspace] +members = [ + "crates/echo-runtime-schema", + "crates/warp-math", + "crates/warp-core", + + "crates/warp-wasm", + "crates/warp-cli", + "crates/warp-geom", + "crates/warp-benches", + "crates/echo-file-aperture", + "crates/echo-graph", + "crates/echo-dind-harness", + "crates/echo-dind-tests", + "crates/echo-wasm-abi", + "crates/echo-registry-api", + "crates/echo-edict-canonical", + "crates/echo-edict-provider-lowerer", + "crates/echo-edict-provider-verifier", + "crates/echo-wesley-gen", + "crates/echo-dry-tests", + "crates/echo-cas", + "crates/echo-scene-port", + "crates/echo-scene-codec", + "xtask", + "crates/echo-trace", +] +resolver = "2" + +[workspace.package] +license = "Apache-2.0" +repository = "https://github.com/flyingrobots/echo" +rust-version = "1.90.0" + +[workspace.dependencies] +echo-cas = { version = "0.1.0", path = "crates/echo-cas" } +echo-dind-tests = { version = "0.1.0", path = "crates/echo-dind-tests" } +echo-dry-tests = { version = "0.1.0", path = "crates/echo-dry-tests" } +echo-file-aperture = { version = "0.1.0", path = "crates/echo-file-aperture" } +echo-graph = { version = "0.1.0", path = "crates/echo-graph" } +echo-runtime-schema = { version = "0.1.0", path = "crates/echo-runtime-schema", default-features = false } +echo-registry-api = { version = "0.1.0", path = "crates/echo-registry-api" } +echo-edict-canonical = { version = "0.1.0", path = "crates/echo-edict-canonical" } +echo-scene-codec = { version = "0.1.0", path = "crates/echo-scene-codec" } +echo-scene-port = { version = "0.1.0", path = "crates/echo-scene-port" } +echo-wasm-abi = { version = "0.1.0", path = "crates/echo-wasm-abi" } +warp-math = { version = "0.1.0", path = "crates/warp-math" } +warp-core = { version = "0.1.1", path = "crates/warp-core" } + +# ── Workspace-wide lint policy ────────────────────────────────────── +# Maximum strictness. Crates opt in via `[lints] workspace = true`. +# Per-crate overrides go in that crate's `[lints]` table. +[workspace.lints.rust] +missing_docs = "deny" +rust_2018_idioms = "deny" +unused_must_use = "deny" +# deny (not forbid) so WASM/FFI crates can #![allow(unsafe_code)] locally +unsafe_code = "deny" + +[workspace.lints.clippy] +# Lint groups — all promoted to deny +all = { level = "deny", priority = -1 } +pedantic = { level = "deny", priority = -1 } +nursery = { level = "deny", priority = -1 } +cargo = { level = "deny", priority = -1 } +# Anti-pattern lints — explicit deny +unwrap_used = "deny" +expect_used = "deny" +panic = "deny" +todo = "deny" +unimplemented = "deny" +dbg_macro = "deny" +print_stdout = "deny" +print_stderr = "deny" +# Pedantic overrides — allow where too noisy for this codebase +must_use_candidate = "allow" +return_self_not_must_use = "allow" +unreadable_literal = "allow" +missing_const_for_fn = "allow" +suboptimal_flops = "allow" +redundant_pub_crate = "allow" +many_single_char_names = "allow" +module_name_repetitions = "allow" +use_self = "allow" +# Nursery overrides — too noisy or false-positive-prone +cognitive_complexity = "allow" +option_if_let_else = "allow" +significant_drop_tightening = "allow" +# Pedantic overrides — low signal-to-noise for this codebase +doc_markdown = "allow" +too_many_lines = "allow" +struct_excessive_bools = "allow" +too_long_first_doc_paragraph = "allow" +missing_errors_doc = "allow" +missing_panics_doc = "allow" +similar_names = "allow" +trivially_copy_pass_by_ref = "allow" +needless_collect = "allow" +manual_let_else = "allow" +needless_pass_by_value = "allow" +# cargo group overrides +multiple_crate_versions = "allow" + +[profile.release] +opt-level = "s" +lto = true +codegen-units = 1 +strip = true + +[profile.bench] +# Derive from release but optimize for throughput and faster builds +opt-level = 3 +lto = false +codegen-units = 16 +debug = true +strip = false diff --git a/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/Cargo.toml.source b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/Cargo.toml.source new file mode 100644 index 00000000..922f345e --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/Cargo.toml.source @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 +# © James Ross Ω FLYING•ROBOTS +[package] +name = "echo-edict-canonical" +version = "0.1.0" +edition = "2021" +rust-version = "1.90.0" +description = "Pure Echo implementation of Edict canonical CBOR and artifact digest framing." +license = "Apache-2.0" +repository = "https://github.com/flyingrobots/echo" +readme = "README.md" +keywords = ["echo", "edict", "cbor", "canonical", "deterministic"] +categories = ["encoding", "development-tools"] + +[dependencies] +hex = "0.4" +sha2 = "0.10" + +[lints] +workspace = true diff --git a/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source new file mode 100644 index 00000000..81cac630 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +//! Exact `edict.canonical-cbor/v1` values, bytes, and artifact digests. +//! +//! This crate is a pure compatibility boundary for the Edict-owned provider +//! contract. It deliberately does not reuse Echo's WASM ABI codec: that codec +//! admits a different value model. The implementation accepts only the +//! definite-length Edict v1 subset, enforces the published nesting bound, and +//! validates decoded bytes by exact canonical re-encoding. + +use std::collections::BTreeSet; +use std::fmt; +use std::str; + +use sha2::{Digest, Sha256}; + +/// Coordinate of the canonical encoding profile implemented by this module. +pub const EDICT_CANONICAL_CBOR_V1: &str = "edict.canonical-cbor/v1"; + +/// Domain marker at the head of every Edict v1 artifact digest frame. +pub const EDICT_DIGEST_FRAME_V1: &str = "edict.digest/v1"; + +/// Maximum child nesting depth accepted by the Edict v1 encoder and decoder. +/// +/// The root value is at depth zero. A scalar wrapped in exactly 128 containers +/// is accepted; one additional container is rejected. +pub const MAX_CANONICAL_NESTING_DEPTH_V1: usize = 128; + +/// Stable failure categories for Edict canonical values and byte streams. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CanonicalValueErrorKind { + /// A value or collection length is outside the supported value model. + UnsupportedValue, + /// An integer is outside the CBOR major-zero or major-one `u64` range. + InvalidInteger, + /// The byte stream ended before one complete value was decoded. + UnexpectedEof, + /// Bytes remained after one complete canonical value. + TrailingData, + /// The byte stream used an unsupported CBOR major or additional-info form. + UnsupportedCbor, + /// The decoded value did not re-encode to the exact supplied bytes. + NonCanonical, + /// The value exceeded the published 128-level nesting bound. + NestingLimitExceeded, + /// A map contained two keys with identical canonical encodings. + DuplicateMapKey, + /// A CBOR text string was not valid UTF-8. + InvalidUtf8, +} + +impl CanonicalValueErrorKind { + const fn label(self) -> &'static str { + match self { + Self::UnsupportedValue => "unsupported-value", + Self::InvalidInteger => "invalid-integer", + Self::UnexpectedEof => "unexpected-eof", + Self::TrailingData => "trailing-data", + Self::UnsupportedCbor => "unsupported-cbor", + Self::NonCanonical => "noncanonical", + Self::NestingLimitExceeded => "nesting-limit-exceeded", + Self::DuplicateMapKey => "duplicate-map-key", + Self::InvalidUtf8 => "invalid-utf8", + } + } +} + +/// Structured canonical-value failure with a stable kind and diagnostic detail. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CanonicalValueError { + kind: CanonicalValueErrorKind, + detail: String, +} + +impl CanonicalValueError { + /// Returns the stable machine-readable failure category. + #[must_use] + pub const fn kind(&self) -> CanonicalValueErrorKind { + self.kind + } + + /// Returns deterministic diagnostic detail for the failed boundary. + #[must_use] + pub fn detail(&self) -> &str { + &self.detail + } + + fn new(kind: CanonicalValueErrorKind, detail: impl Into) -> Self { + Self { + kind, + detail: detail.into(), + } + } +} + +impl fmt::Display for CanonicalValueError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "{}: {}", self.kind.label(), self.detail) + } +} + +impl std::error::Error for CanonicalValueError {} + +/// Value tree admitted by `edict.canonical-cbor/v1`. +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum CanonicalValueV1 { + /// CBOR null. + Null, + /// CBOR false or true. + Bool(bool), + /// CBOR major-zero or major-one integer stored in a convenient host type. + Integer(i128), + /// Definite-length byte string. + Bytes(Vec), + /// Definite-length UTF-8 text string, without Unicode normalization. + Text(String), + /// Definite-length ordered array. + Array(Vec), + /// Definite-length map sorted during encoding by canonical key bytes. + Map(Vec<(CanonicalValueV1, CanonicalValueV1)>), +} + +/// Encodes one value using the exact `edict.canonical-cbor/v1` byte contract. +/// +/// # Errors +/// +/// Returns a stable failure when an integer or collection cannot be represented, +/// a map repeats a canonical key, or the value exceeds the nesting bound. +pub fn encode_canonical_cbor_v1(value: &CanonicalValueV1) -> Result, CanonicalValueError> { + let mut output = Vec::new(); + encode_value(value, &mut output, 0)?; + Ok(output) +} + +/// Decodes and authenticates one `edict.canonical-cbor/v1` value. +/// +/// Decoding is followed by exact canonical re-encoding. This rejects +/// non-minimal integers and lengths, unsorted maps, and any other supported +/// value whose supplied bytes differ from the unique Edict encoding. +/// Successful decoding authenticates the encoding only: callers must still +/// validate the value against its owning CDDL root, and Echo must separately +/// admit any runtime artifact or authority. +/// +/// # Errors +/// +/// Returns a stable failure for malformed, unsupported, trailing, +/// noncanonical, duplicate-key, invalid-UTF-8, or over-nested input. +pub fn decode_canonical_cbor_v1(bytes: &[u8]) -> Result { + let mut decoder = Decoder::new(bytes); + let value = decoder.value(0)?; + if decoder.remaining() != 0 { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::TrailingData, + "canonical CBOR stream contains bytes after the first value", + )); + } + if encode_canonical_cbor_v1(&value)? != bytes { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::NonCanonical, + "decoded value does not re-encode to the supplied bytes", + )); + } + Ok(value) +} + +/// Computes an Edict v1 domain-framed SHA-256 digest for a canonical value. +/// +/// The returned review rendering is `sha256:<64 lowercase hex>`. The preimage +/// is canonical CBOR for `["edict.digest/v1", domain, value]`. Each tuple member +/// is encoded at its own root so digest framing does not consume the artifact's +/// 128-level nesting budget. +/// A digest binds bytes and a caller-selected domain; it does not prove the +/// owning CDDL root or grant Echo runtime authority. +/// +/// # Errors +/// +/// Returns a stable failure for an empty domain or an unencodable value. +pub fn digest_canonical_value_v1( + domain: &str, + value: &CanonicalValueV1, +) -> Result { + if domain.is_empty() { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedValue, + "canonical artifact digest domain is empty", + )); + } + + let mut preimage = vec![0x83]; + preimage.extend(encode_canonical_cbor_v1(&CanonicalValueV1::Text( + EDICT_DIGEST_FRAME_V1.to_owned(), + ))?); + preimage.extend(encode_canonical_cbor_v1(&CanonicalValueV1::Text( + domain.to_owned(), + ))?); + preimage.extend(encode_canonical_cbor_v1(value)?); + + Ok(format!("sha256:{}", hex::encode(Sha256::digest(preimage)))) +} + +fn encode_value( + value: &CanonicalValueV1, + output: &mut Vec, + depth: usize, +) -> Result<(), CanonicalValueError> { + check_depth(depth)?; + match value { + CanonicalValueV1::Null => output.push(0xf6), + CanonicalValueV1::Bool(false) => output.push(0xf4), + CanonicalValueV1::Bool(true) => output.push(0xf5), + CanonicalValueV1::Integer(value) => encode_integer(*value, output)?, + CanonicalValueV1::Bytes(bytes) => { + encode_type_value(2, usize_to_u64(bytes.len())?, output); + output.extend_from_slice(bytes); + } + CanonicalValueV1::Text(text) => { + encode_type_value(3, usize_to_u64(text.len())?, output); + output.extend_from_slice(text.as_bytes()); + } + CanonicalValueV1::Array(values) => { + check_container_depth(depth)?; + encode_type_value(4, usize_to_u64(values.len())?, output); + for value in values { + encode_value(value, output, depth + 1)?; + } + } + CanonicalValueV1::Map(entries) => { + check_container_depth(depth)?; + let mut encoded_entries = Vec::with_capacity(entries.len()); + let mut encoded_keys = BTreeSet::new(); + for (key, value) in entries { + let mut key_bytes = Vec::new(); + encode_value(key, &mut key_bytes, depth + 1)?; + if !encoded_keys.insert(key_bytes.clone()) { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::DuplicateMapKey, + "canonical CBOR map contains duplicate keys", + )); + } + encoded_entries.push((key_bytes, value)); + } + encoded_entries.sort_by(|(left, _), (right, _)| left.cmp(right)); + encode_type_value(5, usize_to_u64(encoded_entries.len())?, output); + for (key_bytes, value) in encoded_entries { + output.extend_from_slice(&key_bytes); + encode_value(value, output, depth + 1)?; + } + } + } + Ok(()) +} + +fn check_depth(depth: usize) -> Result<(), CanonicalValueError> { + if depth > MAX_CANONICAL_NESTING_DEPTH_V1 { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::NestingLimitExceeded, + format!( + "canonical value nesting exceeds maximum depth {MAX_CANONICAL_NESTING_DEPTH_V1}" + ), + )); + } + Ok(()) +} + +fn check_container_depth(depth: usize) -> Result<(), CanonicalValueError> { + if depth >= MAX_CANONICAL_NESTING_DEPTH_V1 { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::NestingLimitExceeded, + format!( + "canonical container nesting exceeds maximum depth {MAX_CANONICAL_NESTING_DEPTH_V1}" + ), + )); + } + Ok(()) +} + +fn encode_integer(value: i128, output: &mut Vec) -> Result<(), CanonicalValueError> { + if value >= 0 { + let value = u64::try_from(value).map_err(|_| { + CanonicalValueError::new( + CanonicalValueErrorKind::InvalidInteger, + "positive integer exceeds the canonical CBOR uint range", + ) + })?; + encode_type_value(0, value, output); + return Ok(()); + } + + let magnitude = (-1i128).checked_sub(value).ok_or_else(|| { + CanonicalValueError::new( + CanonicalValueErrorKind::InvalidInteger, + "negative integer cannot be converted to the canonical CBOR range", + ) + })?; + let magnitude = u64::try_from(magnitude).map_err(|_| { + CanonicalValueError::new( + CanonicalValueErrorKind::InvalidInteger, + "negative integer exceeds the canonical CBOR negative range", + ) + })?; + encode_type_value(1, magnitude, output); + Ok(()) +} + +fn encode_type_value(major: u8, value: u64, output: &mut Vec) { + let prefix = major << 5; + let bytes = value.to_be_bytes(); + match value { + 0..=23 => output.push(prefix | bytes[7]), + 24..=0xff => { + output.push(prefix | 0x18); + output.push(bytes[7]); + } + 0x100..=0xffff => { + output.push(prefix | 0x19); + output.extend_from_slice(&bytes[6..]); + } + 0x1_0000..=0xffff_ffff => { + output.push(prefix | 0x1a); + output.extend_from_slice(&bytes[4..]); + } + _ => { + output.push(prefix | 0x1b); + output.extend_from_slice(&bytes); + } + } +} + +fn usize_to_u64(value: usize) -> Result { + u64::try_from(value).map_err(|_| { + CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedValue, + "canonical collection length does not fit the CBOR uint range", + ) + }) +} + +fn checked_collection_length( + declared: u64, + remaining: u64, +) -> Result +where + HostLength: TryFrom, +{ + if declared > remaining { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnexpectedEof, + "canonical CBOR declared length exceeds the remaining bytes", + )); + } + + HostLength::try_from(declared).map_err(|_| { + CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedCbor, + "canonical CBOR collection length does not fit usize", + ) + }) +} + +struct Decoder<'a> { + bytes: &'a [u8], + position: usize, +} + +impl<'a> Decoder<'a> { + const fn new(bytes: &'a [u8]) -> Self { + Self { bytes, position: 0 } + } + + const fn remaining(&self) -> usize { + self.bytes.len() - self.position + } + + fn value(&mut self, depth: usize) -> Result { + check_depth(depth)?; + let initial = self.byte()?; + let major = initial >> 5; + let additional = initial & 0x1f; + match major { + 0 => Ok(CanonicalValueV1::Integer(i128::from( + self.argument(additional)?, + ))), + 1 => Ok(CanonicalValueV1::Integer( + -1 - i128::from(self.argument(additional)?), + )), + 2 => { + let length = self.length(additional)?; + Ok(CanonicalValueV1::Bytes(self.take(length)?.to_vec())) + } + 3 => { + let length = self.length(additional)?; + let bytes = self.take(length)?; + let text = str::from_utf8(bytes).map_err(|_| { + CanonicalValueError::new( + CanonicalValueErrorKind::InvalidUtf8, + "canonical CBOR text string is not valid UTF-8", + ) + })?; + Ok(CanonicalValueV1::Text(text.to_owned())) + } + 4 => { + check_container_depth(depth)?; + let length = self.length(additional)?; + let mut values = Vec::with_capacity(length); + for _ in 0..length { + values.push(self.value(depth + 1)?); + } + Ok(CanonicalValueV1::Array(values)) + } + 5 => { + check_container_depth(depth)?; + let length = self.length(additional)?; + let mut entries = Vec::with_capacity(length); + let mut encoded_keys = BTreeSet::new(); + for _ in 0..length { + let key = self.value(depth + 1)?; + let mut key_bytes = Vec::new(); + encode_value(&key, &mut key_bytes, depth + 1)?; + if !encoded_keys.insert(key_bytes) { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::DuplicateMapKey, + "canonical CBOR map contains duplicate keys", + )); + } + let value = self.value(depth + 1)?; + entries.push((key, value)); + } + Ok(CanonicalValueV1::Map(entries)) + } + 7 => match additional { + 20 => Ok(CanonicalValueV1::Bool(false)), + 21 => Ok(CanonicalValueV1::Bool(true)), + 22 => Ok(CanonicalValueV1::Null), + _ => Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedCbor, + "canonical CBOR simple value is unsupported", + )), + }, + _ => Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedCbor, + "canonical CBOR major type is unsupported", + )), + } + } + + fn argument(&mut self, additional: u8) -> Result { + match additional { + 0..=23 => Ok(u64::from(additional)), + 24 => Ok(u64::from(self.byte()?)), + 25 => Ok(u64::from(u16::from_be_bytes(self.take_array::<2>()?))), + 26 => Ok(u64::from(u32::from_be_bytes(self.take_array::<4>()?))), + 27 => Ok(u64::from_be_bytes(self.take_array::<8>()?)), + _ => Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedCbor, + "indefinite or reserved canonical CBOR length is unsupported", + )), + } + } + + fn length(&mut self, additional: u8) -> Result { + let declared = self.argument(additional)?; + let remaining = u64::try_from(self.remaining()).map_err(|_| { + CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedCbor, + "remaining canonical CBOR input does not fit the CBOR uint range", + ) + })?; + + checked_collection_length::(declared, remaining) + } + + fn byte(&mut self) -> Result { + let Some(value) = self.bytes.get(self.position).copied() else { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnexpectedEof, + "canonical CBOR expected another byte", + )); + }; + self.position += 1; + Ok(value) + } + + fn take(&mut self, length: usize) -> Result<&'a [u8], CanonicalValueError> { + let end = self.position.checked_add(length).ok_or_else(|| { + CanonicalValueError::new( + CanonicalValueErrorKind::UnexpectedEof, + "canonical CBOR length overflowed the input position", + ) + })?; + let Some(bytes) = self.bytes.get(self.position..end) else { + return Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnexpectedEof, + "canonical CBOR value extends past the input", + )); + }; + self.position = end; + Ok(bytes) + } + + fn take_array(&mut self) -> Result<[u8; LENGTH], CanonicalValueError> { + let mut output = [0u8; LENGTH]; + output.copy_from_slice(self.take(LENGTH)?); + Ok(output) + } +} + +#[cfg(test)] +mod tests { + use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind}; + + #[test] + fn declared_length_bounds_precede_host_width_conversion() { + assert_eq!( + checked_collection_length::(u64::MAX, u64::from(u32::MAX)), + Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnexpectedEof, + "canonical CBOR declared length exceeds the remaining bytes" + )) + ); + } +} diff --git a/crates/echo-wesley-gen/assets/v1/repository/crates/echo-wesley-gen/Cargo.toml.source b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-wesley-gen/Cargo.toml.source new file mode 100644 index 00000000..a72cd6dd --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-wesley-gen/Cargo.toml.source @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: Apache-2.0 +# © James Ross Ω FLYING•ROBOTS +[package] +name = "echo-wesley-gen" +version = "0.1.0" +default-run = "echo-wesley-gen" +edition = "2021" +rust-version = "1.90.0" +description = "Code generator for Echo: consumes Wesley IR (JSON) and emits Rust artifacts via syn/quote." +license = "Apache-2.0" +repository = "https://github.com/flyingrobots/echo" +readme = "README.md" +keywords = ["warp", "echo", "codegen", "wesley", "wasm"] +categories = ["development-tools", "command-line-utilities", "encoding", "wasm"] + +[dependencies] +anyhow = "1.0" +blake3 = "1.5" +cap-fs-ext = "=4.0.2" +cap-std = "=4.0.2" +cddl-cat = { version = "0.7.1", default-features = false, features = ["ciborium"] } +ciborium = "0.2.2" +clap = { version = "4.4", features = ["derive"] } +echo-edict-canonical = { workspace = true } +hex = "0.4" +proc-macro2 = "1.0" +quote = "1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +sha2 = "0.10" +syn = { version = "2.0", features = ["full", "extra-traits"] } +prettyplease = "0.2" +warp-core = { workspace = true } +wesley-core = "=0.3.0-alpha.1" + +[lints] +workspace = true diff --git a/crates/echo-wesley-gen/assets/v1/repository/rust-toolchain.toml.source b/crates/echo-wesley-gen/assets/v1/repository/rust-toolchain.toml.source new file mode 100644 index 00000000..b7348846 --- /dev/null +++ b/crates/echo-wesley-gen/assets/v1/repository/rust-toolchain.toml.source @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# © James Ross Ω FLYING•ROBOTS +[toolchain] +channel = "1.90.0" +components = ["rustfmt", "clippy"] diff --git a/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs b/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs index 4c1af810..6fe9964e 100644 --- a/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs +++ b/crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs @@ -18,13 +18,13 @@ use echo_wesley_gen::provider_review::generate_provider_generation_review_v1; use std::path::PathBuf; const SOURCE: &[u8] = - include_bytes!("../../../../schemas/edict-provider/echo-provider-semantics-v1.json"); + include_bytes!("../../assets/v1/edict-provider/echo-provider-semantics-v1.json"); const SETTINGS: &[u8] = - include_bytes!("../../../../schemas/edict-provider/generation-settings-v1.json"); + include_bytes!("../../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../../assets/v1/edict-provider/contracts/v1/manifest.json"); #[derive(Parser)] #[command( diff --git a/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs b/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs new file mode 100644 index 00000000..f02e24d5 --- /dev/null +++ b/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::print_stdout, clippy::print_stderr)] +//! Synchronizes exact package-local assets for the Echo Edict provider tools. + +use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; +use echo_wesley_gen::provider_corpus::{diff_exact_corpus_files_v1, ProviderArtifactCorpusFileV1}; +use echo_wesley_gen::provider_corpus_fs::{read_actual_corpus, write_corpus}; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::process::Command; + +const MAX_OWNER_FILE_BYTES: u64 = 32 * 1024 * 1024; +const MAX_OWNER_TOTAL_BYTES: usize = 64 * 1024 * 1024; + +#[derive(Clone, Copy)] +struct AssetSpec { + carrier: &'static str, + owner: &'static str, + corroborating_owner: Option<&'static str>, +} + +impl AssetSpec { + const fn new(carrier: &'static str, owner: &'static str) -> Self { + Self { + carrier, + owner, + corroborating_owner: None, + } + } + + const fn corroborated( + carrier: &'static str, + package_copy: &'static str, + authoritative_owner: &'static str, + ) -> Self { + Self { + carrier, + owner: authoritative_owner, + corroborating_owner: Some(package_copy), + } + } +} + +const ASSETS: [AssetSpec; 35] = [ + AssetSpec::new( + "edict-provider/contracts/v1/edict-provider-contracts.cddl", + "schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl", + ), + AssetSpec::new( + "edict-provider/contracts/v1/manifest.json", + "schemas/edict-provider/contracts/v1/manifest.json", + ), + AssetSpec::new( + "edict-provider/echo-provider-semantics-v1.json", + "schemas/edict-provider/echo-provider-semantics-v1.json", + ), + AssetSpec::new( + "edict-provider/generation-settings-v1.json", + "schemas/edict-provider/generation-settings-v1.json", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm", + "schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm", + "schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/components/verifier.echo-dpo.component.wasm", + "schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm", + "schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/evidence/provenance.provider-generation.json", + "schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json", + "schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/evidence/review.provider-generation.json", + "schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json", + "schemas/edict-provider/generated/v1/evidence/review.provider-generation.json", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor", + "schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor", + "schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor", + "schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor", + "schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/primary/generated-artifact-profile.echo-dpo-registration.cbor", + "schemas/edict-provider/package/v1/generated/primary/generated-artifact-profile.echo-dpo-registration.cbor", + "schemas/edict-provider/generated/v1/primary/generated-artifact-profile.echo-dpo-registration.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor", + "schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor", + "schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl", + "schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl", + "schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor", + "schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor", + "schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor", + "schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor", + "schemas/edict-provider/generated/v1/resources/resource.lawpack-compatibility.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor", + "schemas/edict-provider/generated/v1/resources/resource.lawpack-exports.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor", + "schemas/edict-provider/generated/v1/resources/resource.lawpack-target-adapter.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor", + "schemas/edict-provider/generated/v1/resources/resource.lawpack-verifier.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-bundle-profile.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-cost-algebra.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-footprint-algebra.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-intrinsics.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-ir.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-ir.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-ir.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-lowerer-contract.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-obstruction-taxonomy.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-operation-profiles.cbor", + ), + AssetSpec::corroborated( + "edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor", + "schemas/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor", + "schemas/edict-provider/generated/v1/resources/resource.target-verifier-contract.cbor", + ), + AssetSpec::new( + "edict-provider/package/v1/provider-manifest.echo.json", + "schemas/edict-provider/package/v1/provider-manifest.echo.json", + ), + AssetSpec::new("repository/Cargo.lock.source", "Cargo.lock"), + AssetSpec::new("repository/Cargo.toml.source", "Cargo.toml"), + AssetSpec::new( + "repository/crates/echo-edict-canonical/Cargo.toml.source", + "crates/echo-edict-canonical/Cargo.toml", + ), + AssetSpec::new( + "repository/crates/echo-edict-canonical/src/lib.rs.source", + "crates/echo-edict-canonical/src/lib.rs", + ), + AssetSpec::new( + "repository/crates/echo-wesley-gen/Cargo.toml.source", + "crates/echo-wesley-gen/Cargo.toml", + ), + AssetSpec::new( + "repository/rust-toolchain.toml.source", + "rust-toolchain.toml", + ), +]; + +#[derive(Parser)] +#[command( + author, + version, + about = "Synchronizes exact package-local Echo Edict provider assets" +)] +struct Args { + /// Replace the exact package-local carrier tree from its fixed owners. + #[arg(long)] + write: bool, + + /// Prove Cargo selects exactly the fixed carrier tree for its archive. + #[arg(long)] + check_package_list: bool, + + /// Repository root containing the fixed owner paths. + #[arg(long)] + workspace_root: Option, + + /// Override the carrier root, primarily for isolated check/write witnesses. + #[arg(long)] + assets_root: Option, +} + +fn main() -> Result<()> { + let args = Args::parse(); + let crate_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let workspace_root = match args.workspace_root { + Some(root) => root, + None => crate_root.join("../.."), + }; + let assets_root = args + .assets_root + .unwrap_or_else(|| crate_root.join("assets/v1")); + // Write mode intentionally permits a stale package copy so authoritative + // generated/component owners can break the regeneration cycle. Read-only + // check mode still requires every distribution copy to corroborate them. + let expected = load_expected_assets(&workspace_root, !args.write)?; + + if args.write { + write_corpus(&assets_root, &expected)?; + println!("Package-local provider assets synchronized"); + } else { + check_assets(&assets_root, &expected)?; + println!("Package-local provider assets are current"); + } + + if args.check_package_list { + check_package_list(&workspace_root, &expected)?; + println!("Cargo package selects the exact provider asset tree"); + } + Ok(()) +} + +fn load_expected_assets( + root: &Path, + require_corroboration: bool, +) -> Result> { + let mut files = Vec::with_capacity(ASSETS.len()); + let mut total_bytes = 0usize; + for spec in ASSETS { + let bytes = read_owner(root, spec.owner)?; + total_bytes = total_bytes + .checked_add(bytes.len()) + .ok_or_else(|| anyhow!("provider asset owner total byte length overflow"))?; + if total_bytes > MAX_OWNER_TOTAL_BYTES { + bail!("provider asset owners exceed total byte limit {MAX_OWNER_TOTAL_BYTES}"); + } + if require_corroboration { + let Some(corroborating_owner) = spec.corroborating_owner else { + files.push(ProviderArtifactCorpusFileV1::new(spec.carrier, &bytes)?); + continue; + }; + let corroborating_bytes = read_owner(root, corroborating_owner)?; + if bytes != corroborating_bytes { + bail!( + "provider asset owner {} differs from corroborating owner {}", + spec.owner, + corroborating_owner + ); + } + } + files.push(ProviderArtifactCorpusFileV1::new(spec.carrier, &bytes)?); + } + Ok(files) +} + +fn read_owner(root: &Path, relative_path: &str) -> Result> { + let path = root.join(relative_path); + let metadata = std::fs::symlink_metadata(&path) + .with_context(|| format!("failed to inspect provider asset owner {}", path.display()))?; + if metadata.file_type().is_symlink() || !metadata.is_file() { + bail!( + "provider asset owner is not a regular non-symlink file: {}", + path.display() + ); + } + if metadata.len() > MAX_OWNER_FILE_BYTES { + bail!( + "provider asset owner {} exceeds byte limit {MAX_OWNER_FILE_BYTES}", + path.display() + ); + } + let bytes = std::fs::read(&path) + .with_context(|| format!("failed to read provider asset owner {}", path.display()))?; + if bytes.len() as u64 != metadata.len() { + bail!( + "provider asset owner changed length while being read: {}", + path.display() + ); + } + Ok(bytes) +} + +fn check_assets(root: &Path, expected: &[ProviderArtifactCorpusFileV1]) -> Result<()> { + let actual = read_actual_corpus(root, expected)?; + let drift = diff_exact_corpus_files_v1(expected, &actual)?; + if drift.is_empty() { + return Ok(()); + } + + eprintln!("Package-local provider asset drift:"); + for entry in &drift { + eprintln!(" {}: {}", entry.kind().as_str(), entry.relative_path()); + } + bail!("package-local provider assets are not current") +} + +fn check_package_list( + workspace_root: &Path, + expected: &[ProviderArtifactCorpusFileV1], +) -> Result<()> { + let cargo: OsString = std::env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo")); + let manifest = workspace_root.join("crates/echo-wesley-gen/Cargo.toml"); + let output = Command::new(cargo) + .current_dir(workspace_root) + .arg("package") + .arg("--manifest-path") + .arg(&manifest) + .arg("--allow-dirty") + .arg("--list") + .output() + .context("failed to execute cargo package --list for echo-wesley-gen")?; + if !output.status.success() { + bail!( + "cargo package --list failed: {}", + String::from_utf8_lossy(&output.stderr).trim() + ); + } + + let stdout = String::from_utf8(output.stdout).context("cargo package list is not UTF-8")?; + let actual_assets = stdout + .lines() + .filter(|path| path.starts_with("assets/v1/")) + .map(str::to_owned) + .collect::>(); + let expected_assets = expected + .iter() + .map(|file| format!("assets/v1/{}", file.relative_path())) + .collect::>(); + if actual_assets != expected_assets { + bail!( + "cargo package provider asset inventory differs: expected {} entries, found {}", + expected_assets.len(), + actual_assets.len() + ); + } + Ok(()) +} + +#[cfg(test)] +#[allow(clippy::expect_used)] +mod tests { + use super::{load_expected_assets, ASSETS}; + use anyhow::Result; + use std::path::{Path, PathBuf}; + use std::sync::atomic::{AtomicU64, Ordering}; + + static NEXT_TEST_DIRECTORY: AtomicU64 = AtomicU64::new(0); + + #[test] + fn staged_write_uses_authority_while_strict_check_requires_package_corroboration() -> Result<()> + { + let sequence = NEXT_TEST_DIRECTORY.fetch_add(1, Ordering::Relaxed); + let root = std::env::temp_dir().join(format!( + "echo-provider-asset-authority-{}-{sequence}", + std::process::id() + )); + materialize_owner_fixture(&root)?; + + let generated = ASSETS + .iter() + .find(|spec| spec.carrier.ends_with("resource.target-ir.cbor")) + .copied() + .expect("fixed generated asset exists"); + let package_copy = root.join( + generated + .corroborating_owner + .expect("generated asset has a package corroboration"), + ); + std::fs::write(&package_copy, b"stale package copy")?; + + let strict = load_expected_assets(&root, true); + assert!(strict.is_err()); + let staged = load_expected_assets(&root, false)?; + let staged_file = staged + .iter() + .find(|file| file.relative_path() == generated.carrier) + .expect("staged carrier is present"); + assert_eq!( + staged_file.bytes(), + std::fs::read(root.join(generated.owner))? + ); + + std::fs::copy(root.join(generated.owner), &package_copy)?; + assert!(load_expected_assets(&root, true).is_ok()); + std::fs::remove_dir_all(root)?; + Ok(()) + } + + fn materialize_owner_fixture(root: &Path) -> Result<()> { + let source_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.."); + for spec in ASSETS { + copy_owner(&source_root, root, spec.owner)?; + if let Some(corroborating_owner) = spec.corroborating_owner { + copy_owner(&source_root, root, corroborating_owner)?; + } + } + Ok(()) + } + + fn copy_owner(source_root: &Path, target_root: &Path, relative: &str) -> Result<()> { + let target = target_root.join(relative); + if let Some(parent) = target.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::copy(source_root.join(relative), target)?; + Ok(()) + } +} diff --git a/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs b/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs index 5a0dd864..900ae2eb 100644 --- a/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs +++ b/crates/echo-wesley-gen/src/bin/echo-edict-provider-package.rs @@ -21,18 +21,18 @@ use echo_wesley_gen::provider_review::generate_provider_generation_review_v1; use std::path::PathBuf; const SOURCE: &[u8] = - include_bytes!("../../../../schemas/edict-provider/echo-provider-semantics-v1.json"); + include_bytes!("../../assets/v1/edict-provider/echo-provider-semantics-v1.json"); const SETTINGS: &[u8] = - include_bytes!("../../../../schemas/edict-provider/generation-settings-v1.json"); + include_bytes!("../../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../../assets/v1/edict-provider/contracts/v1/manifest.json"); const LOWERER: &[u8] = include_bytes!( - "../../../../schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm" + "../../assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm" ); const VERIFIER: &[u8] = include_bytes!( - "../../../../schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm" + "../../assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm" ); #[derive(Parser)] diff --git a/crates/echo-wesley-gen/src/main.rs b/crates/echo-wesley-gen/src/main.rs index efbb9584..8ee10072 100644 --- a/crates/echo-wesley-gen/src/main.rs +++ b/crates/echo-wesley-gen/src/main.rs @@ -2132,7 +2132,7 @@ mod wesley_core_version_pinned { let exact_dependency = format!("wesley-core = \"={WESLEY_CORE_VERSION}\""); assert!( - include_str!("../Cargo.toml") + include_str!("../assets/v1/repository/crates/echo-wesley-gen/Cargo.toml.source") .lines() .any(|line| line.trim() == exact_dependency), "Wesley provenance must match the exact wesley-core dependency" diff --git a/crates/echo-wesley-gen/src/provider_artifacts.rs b/crates/echo-wesley-gen/src/provider_artifacts.rs index 4bb48026..c52afb72 100644 --- a/crates/echo-wesley-gen/src/provider_artifacts.rs +++ b/crates/echo-wesley-gen/src/provider_artifacts.rs @@ -29,9 +29,10 @@ use crate::provider_contract_pack::{ }; use crate::provider_generation::ProviderGenerationInputV1; use crate::provider_semantics::{ - ArtifactResourceDeclaration, ArtifactResourceProvision, AuthorityClass, - AuthorityFactSourceKind, EffectKindHint, ExecutionClass, GeneratedArtifactDeclaration, - GeneratedArtifactKind, LawpackVerifierDeclaration, OpticKind, ProviderSemanticSourceV1, + generated_resource_root, ArtifactResourceDeclaration, ArtifactResourceProvision, + AuthorityClass, AuthorityFactSourceKind, EffectKindHint, ExecutionClass, + GeneratedArtifactDeclaration, GeneratedArtifactKind, LawpackVerifierDeclaration, OpticKind, + ProviderSemanticSourceV1, }; const SCHEMA_ROLE: &str = "schema.echo-provider-artifacts"; @@ -898,30 +899,13 @@ fn required_generated_roots(source: &ProviderSemanticSourceV1) -> Vec<&str> { } fn resource_root(role: &str) -> Result<&'static str, ProviderArtifactGenerationError> { - let root = match role { - "resource.conformance-corpus" => "echo-provider-conformance-corpus", - "resource.lawpack-compatibility" => "echo-provider-lawpack-compatibility", - "resource.lawpack-exports" => "lawpack-exports", - "resource.lawpack-target-adapter" => "echo-provider-lawpack-target-adapter", - "resource.lawpack-verifier" => "echo-provider-lawpack-verifier", - "resource.target-bundle-profile" => "echo-dpo-bundle", - "resource.target-cost-algebra" => "echo-dpo-cost", - "resource.target-footprint-algebra" => "echo-dpo-footprint", - "resource.target-intrinsics" => "intrinsics-document", - "resource.target-ir" => "echo-span-ir", - "resource.target-lowerer-contract" => "echo-dpo-lowerer", - "resource.target-obstruction-taxonomy" => "echo-dpo-obstructions", - "resource.target-operation-profiles" => "operation-profiles-document", - "resource.target-verifier-contract" => "echo-dpo-verifier", - _ => { - return Err(ProviderArtifactGenerationError::new( - ProviderArtifactGenerationErrorKind::ResourceClosureMismatch, - role, - "generated-resource-root", - )); - } - }; - Ok(root) + generated_resource_root(role).ok_or_else(|| { + ProviderArtifactGenerationError::new( + ProviderArtifactGenerationErrorKind::ResourceClosureMismatch, + role, + "generated-resource-root", + ) + }) } fn resource_edict_contract(role: &str) -> Option<&'static str> { diff --git a/crates/echo-wesley-gen/src/provider_corpus.rs b/crates/echo-wesley-gen/src/provider_corpus.rs index 4202a026..46d13814 100644 --- a/crates/echo-wesley-gen/src/provider_corpus.rs +++ b/crates/echo-wesley-gen/src/provider_corpus.rs @@ -350,19 +350,25 @@ pub fn build_provider_generator_source_bundle_v1( pub fn checked_provider_generator_source_bundle_v1( ) -> Result { let sources: [(&str, &[u8]); 17] = [ - ("Cargo.lock", include_bytes!("../../../Cargo.lock")), - ("Cargo.toml", include_bytes!("../../../Cargo.toml")), + ( + "Cargo.lock", + include_bytes!("../assets/v1/repository/Cargo.lock.source"), + ), + ( + "Cargo.toml", + include_bytes!("../assets/v1/repository/Cargo.toml.source"), + ), ( "crates/echo-edict-canonical/Cargo.toml", - include_bytes!("../../echo-edict-canonical/Cargo.toml"), + include_bytes!("../assets/v1/repository/crates/echo-edict-canonical/Cargo.toml.source"), ), ( "crates/echo-edict-canonical/src/lib.rs", - include_bytes!("../../echo-edict-canonical/src/lib.rs"), + include_bytes!("../assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source"), ), ( "crates/echo-wesley-gen/Cargo.toml", - include_bytes!("../Cargo.toml"), + include_bytes!("../assets/v1/repository/crates/echo-wesley-gen/Cargo.toml.source"), ), ( "crates/echo-wesley-gen/src/bin/echo-edict-provider-artifacts.rs", @@ -410,7 +416,7 @@ pub fn checked_provider_generator_source_bundle_v1( ), ( "rust-toolchain.toml", - include_bytes!("../../../rust-toolchain.toml"), + include_bytes!("../assets/v1/repository/rust-toolchain.toml.source"), ), ]; let mut files = Vec::with_capacity(sources.len()); @@ -482,7 +488,7 @@ impl ProviderArtifactCorpusV1 { } } -/// Loads the exact checked 22-file #652 corpus from compile-time repository bytes. +/// Loads the current checked 22-file provider corpus introduced by #652. /// /// This is an explicit source boundary for later package assembly. It performs /// no filesystem, registry, environment, process, clock, or network discovery. @@ -497,133 +503,133 @@ pub fn checked_provider_artifact_corpus_v1( ( "evidence/provenance.provider-generation.json", include_bytes!( - "../../../schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json" + "../assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json" ), ), ( "evidence/review.provider-generation.json", include_bytes!( - "../../../schemas/edict-provider/generated/v1/evidence/review.provider-generation.json" + "../assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json" ), ), ( "primary/authority-facts.echo-dpo.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor" + "../assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor" ), ), ( "primary/authority-facts.echo-lawpack.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor" + "../assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor" ), ), ( "primary/generated-artifact-profile.echo-dpo-registration.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/primary/generated-artifact-profile.echo-dpo-registration.cbor" + "../assets/v1/edict-provider/package/v1/generated/primary/generated-artifact-profile.echo-dpo-registration.cbor" ), ), ( "primary/lawpack.echo-dpo.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor" + "../assets/v1/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor" ), ), ( "primary/schema.echo-provider-artifacts.cddl", include_bytes!( - "../../../schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl" + "../assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl" ), ), ( "primary/target-profile.echo-dpo.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor" + "../assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor" ), ), ( "resources/resource.conformance-corpus.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor" ), ), ( "resources/resource.lawpack-compatibility.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-compatibility.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor" ), ), ( "resources/resource.lawpack-exports.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-exports.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor" ), ), ( "resources/resource.lawpack-target-adapter.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-target-adapter.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor" ), ), ( "resources/resource.lawpack-verifier.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.lawpack-verifier.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor" ), ), ( "resources/resource.target-bundle-profile.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-bundle-profile.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor" ), ), ( "resources/resource.target-cost-algebra.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-cost-algebra.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor" ), ), ( "resources/resource.target-footprint-algebra.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-footprint-algebra.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor" ), ), ( "resources/resource.target-intrinsics.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-intrinsics.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor" ), ), ( "resources/resource.target-ir.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-ir.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-ir.cbor" ), ), ( "resources/resource.target-lowerer-contract.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-lowerer-contract.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor" ), ), ( "resources/resource.target-obstruction-taxonomy.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-obstruction-taxonomy.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor" ), ), ( "resources/resource.target-operation-profiles.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-operation-profiles.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor" ), ), ( "resources/resource.target-verifier-contract.cbor", include_bytes!( - "../../../schemas/edict-provider/generated/v1/resources/resource.target-verifier-contract.cbor" + "../assets/v1/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor" ), ), ]; diff --git a/crates/echo-wesley-gen/src/provider_package.rs b/crates/echo-wesley-gen/src/provider_package.rs index d7f1178a..b1aa7256 100644 --- a/crates/echo-wesley-gen/src/provider_package.rs +++ b/crates/echo-wesley-gen/src/provider_package.rs @@ -48,7 +48,7 @@ const PROVIDER_MANIFEST_COORDINATE_V1: &str = "echo.edict-provider-manifest@1"; const SEMANTIC_SOURCE_COORDINATE_V1: &str = "echo.semantic-schema@1"; const GENERATOR_COORDINATE_V1: &str = "echo-wesley-gen.provider-artifact-generator@1"; const EXPECTED_ARTIFACT_COUNT: usize = 10; -const EXPECTED_SCHEMA_BINDING_COUNT: usize = 9; +const EXPECTED_SCHEMA_BINDING_COUNT: usize = 24; const EXPECTED_MEMBER_COUNT: usize = 24; const EXPECTED_FILE_COUNT: usize = 25; const MAX_COMPONENT_BYTES: usize = 16 * 1024 * 1024; @@ -367,7 +367,7 @@ pub struct ProviderManifestV1 { pub provider: ProviderManifestResourceRefV1, /// Ten exact generated/component artifact routes. pub artifacts: Vec, - /// Nine exact immutable schema-domain bindings. + /// Twenty-four exact immutable schema-domain bindings. pub schema_bindings: Vec, } @@ -1757,8 +1757,38 @@ fn artifact_specs() -> [ArtifactSpec; EXPECTED_ARTIFACT_COUNT] { fn schema_binding_specs() -> [(&'static str, &'static str); EXPECTED_SCHEMA_BINDING_COUNT] { [ + ( + "echo.dpo-lawpack.adapter.echo-dpo@1", + "echo-provider-lawpack-target-adapter", + ), + ( + "echo.dpo-lawpack.compatibility@1", + "echo-provider-lawpack-compatibility", + ), + ("echo.dpo-lawpack.exports@1", "lawpack-exports"), + ( + "echo.dpo-lawpack.verifier@1", + "echo-provider-lawpack-verifier", + ), + ("echo.dpo.bundle/v1", "echo-dpo-bundle"), + ("echo.dpo.cost/v1", "echo-dpo-cost"), + ("echo.dpo.fixtures/v1", "echo-provider-conformance-corpus"), + ("echo.dpo.footprint/v1", "echo-dpo-footprint"), + ("echo.dpo.intrinsics/v1", "intrinsics-document"), + ("echo.dpo.lowerer/v1", "echo-dpo-lowerer"), + ("echo.dpo.obstructions/v1", "echo-dpo-obstructions"), + ( + "echo.dpo.operation-profiles/v1", + "operation-profiles-document", + ), + ("echo.dpo.verifier/v1", "echo-dpo-verifier"), + ( + "echo.generated-artifact-profile/v1", + "generated-artifact-profile", + ), ("echo.generated-artifact/v1", "generated-artifact"), ("echo.review-payload/v1", "review-payload"), + ("echo.span-ir/v1", "echo-span-ir"), ("echo.verifier-report/v1", "verifier-report"), ("edict.authority-facts/v1", "authority-facts"), ("edict.core.module/v1", "core-module"), diff --git a/crates/echo-wesley-gen/src/provider_semantics.rs b/crates/echo-wesley-gen/src/provider_semantics.rs index 858f808d..491bae3f 100644 --- a/crates/echo-wesley-gen/src/provider_semantics.rs +++ b/crates/echo-wesley-gen/src/provider_semantics.rs @@ -3435,6 +3435,28 @@ fn validate_invocation_schema_bindings( .iter() .map(|input| input.domain.as_str()) .collect::>(); + let mut owner_bindings = source + .generated_artifacts + .iter() + .filter_map(|artifact| { + generated_artifact_owner_schema(artifact.kind) + .map(|(domain, root)| (artifact.role.as_str(), domain, root)) + }) + .collect::>(); + owner_bindings.extend( + source + .artifact_resources + .iter() + .filter(|resource| resource.provision == ArtifactResourceProvision::Generated) + .filter_map(|resource| { + generated_resource_root(&resource.role) + .map(|root| (resource.role.as_str(), resource.coordinate.as_str(), root)) + }), + ); + let owner_domains = owner_bindings + .iter() + .map(|(_, domain, _)| *domain) + .collect::>(); for output in &source.invocation_outputs { let (expected_domain, _) = expected_output_contract(output.kind); if output.domain != expected_domain { @@ -3449,6 +3471,7 @@ fn validate_invocation_schema_bindings( for binding in &source.schema_bindings { if !output_domains.contains(binding.domain.as_str()) && !input_domains.contains(binding.domain.as_str()) + && !owner_domains.contains(binding.domain.as_str()) { return Err(ProviderSemanticSourceError::new( ProviderSemanticSourceErrorKind::UnexpectedSchemaBinding, @@ -3474,6 +3497,23 @@ fn validate_invocation_schema_bindings( } } + for (role, domain, expected_root) in owner_bindings { + let Some(binding) = bindings.get(domain) else { + return Err(ProviderSemanticSourceError::new( + ProviderSemanticSourceErrorKind::MissingSchemaBinding, + role, + domain, + )); + }; + if binding.root_rule != expected_root { + return Err(ProviderSemanticSourceError::new( + ProviderSemanticSourceErrorKind::SchemaRootMismatch, + role, + &binding.root_rule, + )); + } + } + let artifact_roles = source .generated_artifacts .iter() @@ -3555,6 +3595,48 @@ fn expected_output_contract(kind: InvocationOutputKind) -> (&'static str, &'stat } } +const fn generated_artifact_owner_schema( + kind: GeneratedArtifactKind, +) -> Option<(&'static str, &'static str)> { + match kind { + GeneratedArtifactKind::Lawpack => Some(("edict.lawpack/v1", "lawpack-manifest")), + GeneratedArtifactKind::TargetProfile => { + Some(("edict.target-profile/v1", "target-profile-manifest")) + } + GeneratedArtifactKind::AuthorityFacts => { + Some(("edict.authority-facts/v1", "authority-facts")) + } + GeneratedArtifactKind::GeneratedArtifactProfile => Some(( + "echo.generated-artifact-profile/v1", + "generated-artifact-profile", + )), + GeneratedArtifactKind::ProviderManifest + | GeneratedArtifactKind::ReviewArtifact + | GeneratedArtifactKind::GenerationProvenance + | GeneratedArtifactKind::ArtifactSchema => None, + } +} + +pub(crate) fn generated_resource_root(role: &str) -> Option<&'static str> { + match role { + "resource.conformance-corpus" => Some("echo-provider-conformance-corpus"), + "resource.lawpack-compatibility" => Some("echo-provider-lawpack-compatibility"), + "resource.lawpack-exports" => Some("lawpack-exports"), + "resource.lawpack-target-adapter" => Some("echo-provider-lawpack-target-adapter"), + "resource.lawpack-verifier" => Some("echo-provider-lawpack-verifier"), + "resource.target-bundle-profile" => Some("echo-dpo-bundle"), + "resource.target-cost-algebra" => Some("echo-dpo-cost"), + "resource.target-footprint-algebra" => Some("echo-dpo-footprint"), + "resource.target-intrinsics" => Some("intrinsics-document"), + "resource.target-ir" => Some("echo-span-ir"), + "resource.target-lowerer-contract" => Some("echo-dpo-lowerer"), + "resource.target-obstruction-taxonomy" => Some("echo-dpo-obstructions"), + "resource.target-operation-profiles" => Some("operation-profiles-document"), + "resource.target-verifier-contract" => Some("echo-dpo-verifier"), + _ => None, + } +} + const fn expected_input_domain(kind: InvocationInputKind) -> &'static str { match kind { InvocationInputKind::Core => "edict.core.module/v1", @@ -3605,6 +3687,7 @@ fn expected_schema_root(domain: &str) -> Option<&'static str> { "edict.lowering-requirements/v1" => Some("lowering-requirements"), "edict.target-profile/v1" => Some("target-profile-manifest"), "edict.target-ir.artifact/v1" => Some("target-ir-artifact"), + "echo.generated-artifact-profile/v1" => Some("generated-artifact-profile"), "echo.generated-artifact/v1" => Some("generated-artifact"), "echo.review-payload/v1" => Some("review-payload"), "echo.verifier-report/v1" => Some("verifier-report"), diff --git a/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs b/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs index 95cbe824..481d754f 100644 --- a/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs +++ b/crates/echo-wesley-gen/tests/provider_artifact_corpus.rs @@ -29,14 +29,12 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::atomic::{AtomicU64, Ordering}; -const SOURCE: &[u8] = - include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); -const SETTINGS: &[u8] = - include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const SOURCE: &[u8] = include_bytes!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = include_bytes!("../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); const GENERATOR_SOURCE_PATHS: [&str; 17] = [ "Cargo.lock", @@ -625,7 +623,7 @@ fn check_mode_classifies_a_non_regular_expected_leaf_without_following_it() { #[test] fn checked_first_corpus_matches_the_renderer_without_missing_or_extra_files() { let corpus_root = - Path::new(env!("CARGO_MANIFEST_DIR")).join("../../schemas/edict-provider/generated/v1"); + Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/v1/edict-provider/package/v1/generated"); let output = Command::new(env!("CARGO_BIN_EXE_echo-edict-provider-artifacts")) .arg("--check") .arg("--out") diff --git a/crates/echo-wesley-gen/tests/provider_canonical_contract.rs b/crates/echo-wesley-gen/tests/provider_canonical_contract.rs index 7bcedf5f..cac8c6f0 100644 --- a/crates/echo-wesley-gen/tests/provider_canonical_contract.rs +++ b/crates/echo-wesley-gen/tests/provider_canonical_contract.rs @@ -12,9 +12,9 @@ use echo_wesley_gen::provider_contract_pack::{ }; const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); fn text(value: &str) -> CanonicalValueV1 { CanonicalValueV1::Text(value.to_owned()) diff --git a/crates/echo-wesley-gen/tests/provider_contract_pack.rs b/crates/echo-wesley-gen/tests/provider_contract_pack.rs index e66f3601..98d98a18 100644 --- a/crates/echo-wesley-gen/tests/provider_contract_pack.rs +++ b/crates/echo-wesley-gen/tests/provider_contract_pack.rs @@ -9,9 +9,9 @@ use echo_wesley_gen::provider_contract_pack::{ use serde_json::Value; const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); const DOMAIN_ROOTS: [(&str, &str); 6] = [ ("edict.authority-facts/v1", "authority-facts"), ("edict.core.module/v1", "core-module"), diff --git a/crates/echo-wesley-gen/tests/provider_generation_input.rs b/crates/echo-wesley-gen/tests/provider_generation_input.rs index d32db651..f9bc0610 100644 --- a/crates/echo-wesley-gen/tests/provider_generation_input.rs +++ b/crates/echo-wesley-gen/tests/provider_generation_input.rs @@ -11,14 +11,12 @@ use echo_wesley_gen::provider_semantics::ProviderSemanticSourceErrorKind; use serde_json::{json, Value}; use wesley_core::compute_generation_artifact_digest_v1; -const SOURCE: &[u8] = - include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); -const SETTINGS: &[u8] = - include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const SOURCE: &[u8] = include_bytes!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = include_bytes!("../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); fn build( source: &[u8], diff --git a/crates/echo-wesley-gen/tests/provider_generation_provenance.rs b/crates/echo-wesley-gen/tests/provider_generation_provenance.rs index 93a41030..9b145437 100644 --- a/crates/echo-wesley-gen/tests/provider_generation_provenance.rs +++ b/crates/echo-wesley-gen/tests/provider_generation_provenance.rs @@ -23,14 +23,12 @@ use wesley_core::{ GenerationProvenanceManifestV1, }; -const SOURCE: &[u8] = - include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); -const SETTINGS: &[u8] = - include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const SOURCE: &[u8] = include_bytes!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = include_bytes!("../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); const GENERATOR_COORDINATE: &str = "echo-wesley-gen.provider-artifact-generator@1"; const GENERATOR_VERSION: &str = "0.1.0"; diff --git a/crates/echo-wesley-gen/tests/provider_generation_review.rs b/crates/echo-wesley-gen/tests/provider_generation_review.rs index 108f7d94..f3ceacbb 100644 --- a/crates/echo-wesley-gen/tests/provider_generation_review.rs +++ b/crates/echo-wesley-gen/tests/provider_generation_review.rs @@ -24,14 +24,12 @@ use wesley_core::{ compute_generation_artifact_digest_v1, GenerationContractErrorKind, GenerationReviewV1, }; -const SOURCE: &[u8] = - include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); -const SETTINGS: &[u8] = - include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const SOURCE: &[u8] = include_bytes!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = include_bytes!("../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); const GENERATOR_COORDINATE: &str = "echo-wesley-gen.provider-artifact-generator@1"; const GENERATOR_VERSION: &str = "0.1.0"; diff --git a/crates/echo-wesley-gen/tests/provider_package.rs b/crates/echo-wesley-gen/tests/provider_package.rs index 61b0bc65..1c9f0330 100644 --- a/crates/echo-wesley-gen/tests/provider_package.rs +++ b/crates/echo-wesley-gen/tests/provider_package.rs @@ -30,18 +30,17 @@ use echo_wesley_gen::provider_review::{ }; use wesley_core::{compute_generation_artifact_digest_v1, GenerationContractErrorKind}; -const SOURCE: &[u8] = - include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); -const SETTINGS: &[u8] = - include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const SOURCE: &[u8] = include_bytes!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = include_bytes!("../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); -const LOWERER: &[u8] = - include_bytes!("../../../schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); +const LOWERER: &[u8] = include_bytes!( + "../assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm" +); const VERIFIER: &[u8] = include_bytes!( - "../../../schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm" + "../assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm" ); fn admitted_pack() -> AdmittedProviderContractPackV1 { @@ -125,7 +124,7 @@ fn checked_materials_assemble_one_digest_locked_provider_package() { assert_eq!(package.members().len(), 24); assert_eq!(package.files().len(), 25); assert_eq!(package.manifest().artifacts.len(), 10); - assert_eq!(package.manifest().schema_bindings.len(), 9); + assert_eq!(package.manifest().schema_bindings.len(), 24); assert_eq!( package .manifest() @@ -185,7 +184,7 @@ fn checked_materials_assemble_one_digest_locked_provider_package() { } #[test] -fn package_generated_members_are_the_exact_checked_652_corpus() { +fn package_generated_members_equal_the_current_checked_provider_corpus() { let package = assemble(false); let checked = checked_provider_artifact_corpus_v1() .expect("checked #652 provider artifact corpus is an exact bounded value"); diff --git a/crates/echo-wesley-gen/tests/provider_package_assets.rs b/crates/echo-wesley-gen/tests/provider_package_assets.rs new file mode 100644 index 00000000..cdb32216 --- /dev/null +++ b/crates/echo-wesley-gen/tests/provider_package_assets.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::expect_used, clippy::panic)] +//! Exact owner/carrier and Cargo-archive witnesses for provider package assets. + +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; +use std::sync::atomic::{AtomicU64, Ordering}; + +const EXPECTED_ASSET_FILE_COUNT: usize = 35; +static NEXT_TEMP_DIRECTORY: AtomicU64 = AtomicU64::new(0); + +struct TestDirectory(PathBuf); + +impl TestDirectory { + fn new(label: &str) -> Self { + let sequence = NEXT_TEMP_DIRECTORY.fetch_add(1, Ordering::Relaxed); + let path = std::env::temp_dir().join(format!( + "echo-provider-assets-{label}-{}-{sequence}", + std::process::id() + )); + if path.exists() { + std::fs::remove_dir_all(&path).expect("stale asset test directory is removable"); + } + Self(path) + } + + fn path(&self) -> &Path { + &self.0 + } +} + +impl Drop for TestDirectory { + fn drop(&mut self) { + drop(std::fs::remove_dir_all(&self.0)); + } +} + +fn run_assets(arguments: &[&str]) -> Output { + Command::new(env!("CARGO_BIN_EXE_echo-edict-provider-assets")) + .args(arguments) + .output() + .expect("provider asset synchronizer executes") +} + +fn count_files(path: &Path) -> usize { + std::fs::read_dir(path) + .expect("asset directory is readable") + .map(|entry| entry.expect("asset entry is readable")) + .map(|entry| { + let file_type = entry.file_type().expect("asset entry type is readable"); + if file_type.is_dir() { + count_files(&entry.path()) + } else { + usize::from(file_type.is_file()) + } + }) + .sum() +} + +#[test] +fn fixed_assets_match_their_current_owners_and_cargo_archive() { + let checked = run_assets(&["--check-package-list"]); + assert!( + checked.status.success(), + "provider asset/archive check failed:\n{}", + String::from_utf8_lossy(&checked.stderr) + ); +} + +#[test] +fn asset_check_reports_drift_without_repair_and_write_restores_exact_bytes() { + let directory = TestDirectory::new("check-write"); + let assets_root = directory.path().join("v1"); + let assets_root_text = assets_root.to_string_lossy(); + + let written = run_assets(&["--write", "--assets-root", &assets_root_text]); + assert!( + written.status.success(), + "provider asset write failed:\n{}", + String::from_utf8_lossy(&written.stderr) + ); + assert_eq!(count_files(&assets_root), EXPECTED_ASSET_FILE_COUNT); + + let changed_path = assets_root.join("repository/rust-toolchain.toml.source"); + std::fs::write(&changed_path, b"tampered toolchain") + .expect("asset carrier is deliberately changed"); + let checked = run_assets(&["--assets-root", &assets_root_text]); + assert!(!checked.status.success()); + assert!(String::from_utf8_lossy(&checked.stderr) + .contains("changed: repository/rust-toolchain.toml.source")); + assert_eq!( + std::fs::read(&changed_path).expect("changed carrier remains readable"), + b"tampered toolchain" + ); + + let restored = run_assets(&["--write", "--assets-root", &assets_root_text]); + assert!( + restored.status.success(), + "provider asset restore failed:\n{}", + String::from_utf8_lossy(&restored.stderr) + ); + let final_check = run_assets(&["--assets-root", &assets_root_text]); + assert!( + final_check.status.success(), + "restored provider assets do not check:\n{}", + String::from_utf8_lossy(&final_check.stderr) + ); +} diff --git a/crates/echo-wesley-gen/tests/provider_package_corpus.rs b/crates/echo-wesley-gen/tests/provider_package_corpus.rs index d1423082..b84ea99b 100644 --- a/crates/echo-wesley-gen/tests/provider_package_corpus.rs +++ b/crates/echo-wesley-gen/tests/provider_package_corpus.rs @@ -11,9 +11,9 @@ use std::sync::atomic::{AtomicU64, Ordering}; use sha2::{Digest as _, Sha256}; const EXPECTED_PROVIDER_DIGEST: &str = - "sha256:cf0147bea65cdfa7d426dc11a0eeab8f3ac889bfb3daa14f3d6b05ccd80f2d6e"; + "sha256:af5be6b5670d559ba7a7bf5867ae51c0cdd7938fcaf147167640b50f1b27b688"; const EXPECTED_MANIFEST_RAW_SHA256: &str = - "2ddc03d00a9ce9e3c29d74064e90458ede1aa08a0845bbe984d555710967c29b"; + "b7f3113c21cf50780d59b8d9d2a2829a1d185e7dc7b1eba4aa8a37d7bd820dad"; const PACKAGE_PATHS: [&str; 25] = [ "components/lowerer.echo-dpo.component.wasm", @@ -234,7 +234,7 @@ fn generation_refuses_unexpected_entries_before_writing_package_members() { #[test] fn checked_provider_package_matches_the_current_renderer() { let package_root = - Path::new(env!("CARGO_MANIFEST_DIR")).join("../../schemas/edict-provider/package/v1"); + Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/v1/edict-provider/package/v1"); let checked = run_package(&package_root, true); assert!( diff --git a/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs b/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs index 9cc0a105..48bfa3c6 100644 --- a/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs +++ b/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs @@ -19,14 +19,12 @@ use echo_wesley_gen::provider_generation::{ use serde_json::{json, Value}; use wesley_core::{compute_generation_artifact_digest_v1, GenerationContractErrorKind}; -const SOURCE: &[u8] = - include_bytes!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); -const SETTINGS: &[u8] = - include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const SOURCE: &[u8] = include_bytes!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); +const SETTINGS: &[u8] = include_bytes!("../assets/v1/edict-provider/generation-settings-v1.json"); const CONTRACT_CDDL: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = - include_bytes!("../../../schemas/edict-provider/contracts/v1/manifest.json"); + include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); const PRIMARY_ROLES: [&str; 6] = [ "authority-facts.echo-dpo", diff --git a/crates/echo-wesley-gen/tests/provider_semantic_source.rs b/crates/echo-wesley-gen/tests/provider_semantic_source.rs index 2d69038f..32f5f3fb 100644 --- a/crates/echo-wesley-gen/tests/provider_semantic_source.rs +++ b/crates/echo-wesley-gen/tests/provider_semantic_source.rs @@ -12,8 +12,7 @@ use echo_wesley_gen::provider_semantics::{ }; use serde_json::{json, Value}; -const SOURCE: &str = - include_str!("../../../schemas/edict-provider/echo-provider-semantics-v1.json"); +const SOURCE: &str = include_str!("../assets/v1/edict-provider/echo-provider-semantics-v1.json"); fn source_value() -> Value { serde_json::from_str(SOURCE).expect("checked source fixture is JSON") @@ -558,8 +557,38 @@ fn checked_echo_provider_semantic_source_validates() { .map(|binding| (binding.domain.as_str(), binding.root_rule.as_str())) .collect::>(), vec![ + ( + "echo.dpo-lawpack.adapter.echo-dpo@1", + "echo-provider-lawpack-target-adapter", + ), + ( + "echo.dpo-lawpack.compatibility@1", + "echo-provider-lawpack-compatibility", + ), + ("echo.dpo-lawpack.exports@1", "lawpack-exports"), + ( + "echo.dpo-lawpack.verifier@1", + "echo-provider-lawpack-verifier", + ), + ("echo.dpo.bundle/v1", "echo-dpo-bundle"), + ("echo.dpo.cost/v1", "echo-dpo-cost"), + ("echo.dpo.fixtures/v1", "echo-provider-conformance-corpus",), + ("echo.dpo.footprint/v1", "echo-dpo-footprint"), + ("echo.dpo.intrinsics/v1", "intrinsics-document"), + ("echo.dpo.lowerer/v1", "echo-dpo-lowerer"), + ("echo.dpo.obstructions/v1", "echo-dpo-obstructions"), + ( + "echo.dpo.operation-profiles/v1", + "operation-profiles-document", + ), + ("echo.dpo.verifier/v1", "echo-dpo-verifier"), + ( + "echo.generated-artifact-profile/v1", + "generated-artifact-profile", + ), ("echo.generated-artifact/v1", "generated-artifact"), ("echo.review-payload/v1", "review-payload"), + ("echo.span-ir/v1", "echo-span-ir"), ("echo.verifier-report/v1", "verifier-report"), ("edict.authority-facts/v1", "authority-facts"), ("edict.core.module/v1", "core-module"), @@ -571,6 +600,82 @@ fn checked_echo_provider_semantic_source_validates() { ); } +#[test] +fn generated_artifacts_require_their_owner_schema_bindings() { + assert_failure_tuple( + |source| { + let bindings = source["schemaBindings"] + .as_array_mut() + .expect("schema bindings"); + let index = bindings + .iter() + .position(|binding| { + binding["domain"] == Value::String("echo.generated-artifact-profile/v1".into()) + }) + .expect("generated-artifact-profile binding"); + bindings.remove(index); + }, + ( + ProviderSemanticSourceErrorKind::MissingSchemaBinding, + "generated-artifact-profile.echo-dpo-registration", + "echo.generated-artifact-profile/v1", + ), + ); + assert_failure_tuple( + |source| { + let bindings = source["schemaBindings"] + .as_array_mut() + .expect("schema bindings"); + let index = bindings + .iter() + .position(|binding| { + binding["domain"] == Value::String("echo.dpo.fixtures/v1".into()) + }) + .expect("generated resource binding"); + bindings.remove(index); + }, + ( + ProviderSemanticSourceErrorKind::MissingSchemaBinding, + "resource.conformance-corpus", + "echo.dpo.fixtures/v1", + ), + ); + assert_failure_tuple( + |source| { + let binding = source["schemaBindings"] + .as_array_mut() + .expect("schema bindings") + .iter_mut() + .find(|binding| { + binding["domain"] == Value::String("echo.generated-artifact-profile/v1".into()) + }) + .expect("generated-artifact-profile binding"); + binding["rootRule"] = Value::String("wrong-profile-root".into()); + }, + ( + ProviderSemanticSourceErrorKind::SchemaRootMismatch, + "echo.generated-artifact-profile/v1", + "wrong-profile-root", + ), + ); + assert_failure_tuple( + |source| { + let binding = source["schemaBindings"] + .as_array_mut() + .expect("schema bindings") + .iter_mut() + .find(|binding| binding["domain"] == Value::String("echo.dpo.fixtures/v1".into())) + .expect("generated resource binding"); + binding["rootRule"] = Value::String("wrong-resource-root".into()); + }, + ( + ProviderSemanticSourceErrorKind::SchemaRootMismatch, + "resource.conformance-corpus", + "wrong-resource-root", + ), + ); +} + #[test] fn set_like_source_reordering_preserves_validated_semantics() { let mut ordered = source_value(); diff --git a/det-policy.yaml b/det-policy.yaml index ad32875a..5053da41 100644 --- a/det-policy.yaml +++ b/det-policy.yaml @@ -46,7 +46,7 @@ crates: echo-edict-provider-artifacts: class: DET_CRITICAL owner_role: "Tooling Engineer" - paths: ["crates/echo-wesley-gen/src/provider_*.rs", "crates/echo-wesley-gen/src/bin/echo-edict-provider-*.rs", "crates/echo-wesley-gen/tests/provider_*.rs", "schemas/edict-provider/**"] + paths: ["crates/echo-wesley-gen/src/provider_*.rs", "crates/echo-wesley-gen/src/bin/echo-edict-provider-*.rs", "crates/echo-wesley-gen/tests/provider_*.rs", "crates/echo-wesley-gen/assets/v1/**", "schemas/edict-provider/**"] echo-edict-provider-lowerer: class: DET_CRITICAL owner_role: "Tooling Engineer" diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index e22fb942..e9b683f4 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -189,9 +189,10 @@ install a package, admit an operation, or authorize a runtime consequence. The #655 package identity is an Echo-owned, versioned canonical-CBOR closure, not a hash of the completed JSON manifest. It binds the manifest role and coordinate, exact API and provider ABI, ten sorted semantic/component routes, -nine sorted schema bindings, and raw exact-byte hashes for all 24 non-manifest -members. The derived manifest carries that root and has its own independent raw -content identity. Canonical-CBOR routes preserve their Edict domain-framed +24 sorted schema bindings—nine invocation domains, the generated artifact +profile, and 14 generated-resource domains—and raw exact-byte hashes for all 24 +non-manifest members. The derived manifest carries that root and has its own +independent raw content identity. Canonical-CBOR routes preserve their Edict domain-framed artifact digests while the package member table preserves raw occurrences, so neither proposition impersonates the other. Admission requires the caller's external provider pin and exact-reproduces packaged Wesley provenance/review. @@ -199,14 +200,34 @@ That boundary still proves only the distribution occurrence: the Edict-owned schema registry and component host must separately admit roots, bytes, attestations, imports, exports, and WIT types before guest execution. -The checked distribution is a self-contained 25-file publication: the exact -22-file #652 corpus under `generated/`, the exact lowerer and verifier under +The checked distribution is a self-contained 25-file publication: the current +22-file provider corpus introduced by #652 under `generated/`, the exact lowerer and verifier under `components/`, and the derived manifest. Publication refuses before filesystem access if the generated members are not byte-identical to the checked source corpus. Its check mode inventories the exact tree through retained no-follow directory capabilities and reports drift without repair. This distribution copy is a release occurrence, not a second semantic authority. +Native readiness is a later, independent crossing pinned to Edict revision +`c75c3f550d049485ba00eae0dc272c6dd6aca11f`. The exact manifest constructs the +immutable schema registry; all five canonical primaries and 14 generated +resources validate under their owning roots; every lawpack/target-profile field +is bound to the expected coordinate and independently recomputed domain-framed +digest; adjacent primary references agree; and both exact components pass host +preflight before both request kinds are validated. No guest is invoked. These +proofs establish schema, identity-graph, component-contract, and request +readiness only. They still do not install, authorize, schedule, execute, commit, +observe, or receipt anything in Echo. + +The publishable Rust crate uses a separate 35-file package-local carrier tree +for exact repository sources and provider bytes that would otherwise live above +the crate root. Carrier locations never replace the logical authored paths in +generation provenance. Generated artifacts and components remain authoritative; +their package copies are corroborating release occurrences. This distinction +permits staged regeneration without allowing a stale package to block the +carrier update required to rebuild that package. Final checks require owner, +carrier, package copy, and Cargo archive inventory to agree exactly. + The target-profile lowerer and verifier resources are generated declarative contract documents. They do not select executable implementations. The package manifest separately binds the exact provider-owned components and their frozen diff --git a/schemas/edict-provider/README.md b/schemas/edict-provider/README.md index ddaae11c..cd0ff450 100644 --- a/schemas/edict-provider/README.md +++ b/schemas/edict-provider/README.md @@ -190,8 +190,9 @@ output is distinct from #652's build-time `reviewArtifact`. The package closure contains the 22 generated files plus the exact lowerer and verifier components. Its Echo-owned provider digest binds the typed manifest -routes, the nine domain-to-root bindings, and raw SHA-256 of all 24 physical -members without hashing the derived manifest into itself. The five routed +routes, 24 domain-to-root bindings (nine invocation domains, the generated +artifact profile, and 14 generated-resource domains), and raw SHA-256 of all 24 +physical members without hashing the derived manifest into itself. The five routed canonical-CBOR artifacts use their Edict domain-framed identities in the manifest, while CDDL, Wesley JSON evidence, and components use raw exact-byte identities. Pure digest admission also rebinds the generated routes to the @@ -201,10 +202,25 @@ compatibility proof and not Echo runtime installation or authority. The exact 25-file distribution is checked under [`package/v1/`](package/README.md). Its dedicated publisher first requires its -22 `generated/` members to equal the checked #652 corpus byte-for-byte, then +22 `generated/` members to equal the current checked provider corpus introduced +by #652 byte-for-byte, then writes only the two exact components, those generated members, and the derived manifest. Run `echo-edict-provider-package --check` to report drift without creating, deleting, or rewriting package files. +The isolated Edict c75 host gate then consumes that exact checked package. It +constructs all 24 native schema bindings, validates the five canonical primaries +and 14 generated resources, proves every owner field names the expected exact +resource digest, prepares both components, and obtains both opaque request +proofs without guest invocation. Schema-valid resource substitution, reference +swaps, authority-source disagreement, and malformed contract material fail +before execution. This does not grant Echo runtime authority. + +The crate-local `assets/v1/` tree is an exact publication carrier for the same +provider bytes plus the repository sources needed for generator provenance. +Carrier paths are physical packaging details only; authored logical source paths +remain unchanged. `echo-edict-provider-assets --check-package-list` proves +owner/carrier/package agreement and exact Cargo archive selection. + All generated files are derived artifacts. Their digests and review renderings must never be copied back into this file as authored semantic facts. diff --git a/schemas/edict-provider/echo-provider-semantics-v1.json b/schemas/edict-provider/echo-provider-semantics-v1.json index 717e7eee..6b52ada5 100644 --- a/schemas/edict-provider/echo-provider-semantics-v1.json +++ b/schemas/edict-provider/echo-provider-semantics-v1.json @@ -555,6 +555,90 @@ } ], "schemaBindings": [ + { + "domain": "echo.dpo-lawpack.adapter.echo-dpo@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-target-adapter" + }, + { + "domain": "echo.dpo-lawpack.compatibility@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-compatibility" + }, + { + "domain": "echo.dpo-lawpack.exports@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-exports" + }, + { + "domain": "echo.dpo-lawpack.verifier@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-verifier" + }, + { + "domain": "echo.dpo.bundle/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-bundle" + }, + { + "domain": "echo.dpo.cost/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-cost" + }, + { + "domain": "echo.dpo.fixtures/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-conformance-corpus" + }, + { + "domain": "echo.dpo.footprint/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-footprint" + }, + { + "domain": "echo.dpo.intrinsics/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "intrinsics-document" + }, + { + "domain": "echo.dpo.lowerer/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-lowerer" + }, + { + "domain": "echo.dpo.obstructions/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-obstructions" + }, + { + "domain": "echo.dpo.operation-profiles/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "operation-profiles-document" + }, + { + "domain": "echo.dpo.verifier/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-verifier" + }, + { + "domain": "echo.generated-artifact-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact-profile" + }, { "domain": "echo.generated-artifact/v1", "schemaRole": "schema.echo-provider-artifacts", @@ -567,6 +651,12 @@ "format": "selfContainedCddlV1", "rootRule": "review-payload" }, + { + "domain": "echo.span-ir/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-span-ir" + }, { "domain": "echo.verifier-report/v1", "schemaRole": "schema.echo-provider-artifacts", diff --git a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json index 90602d7f..425401f7 100644 --- a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json index e341b270..3e8c6a48 100644 --- a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:f61cfc7e1d32b1fb75188cc23ca25df852ed50059d3858d716ce136908ea7eae","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:86d7daf0639a8879199f6f0a57acf7cb935a99fa40bd48afc652e3afcffaf304","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/README.md b/schemas/edict-provider/package/README.md index f58e7325..f52cad03 100644 --- a/schemas/edict-provider/package/README.md +++ b/schemas/edict-provider/package/README.md @@ -12,7 +12,7 @@ distribution. Its inventory is fixed at 25 files: The manifest never inventories itself. Its `provider.digest` names an Echo-owned, domain-framed canonical-CBOR closure over the manifest contract, -routes, schema bindings, and raw identities of all 24 non-manifest members. +routes, 24 schema bindings, and raw identities of all 24 non-manifest members. The manifest file has a separate raw content identity. Regenerate the package only from the repository root: @@ -30,7 +30,22 @@ cargo +1.90.0 run --locked -p echo-wesley-gen \ ``` The publisher fails before filesystem access unless every packaged -`generated/` member is byte-identical to the checked #652 corpus. The checked +`generated/` member is byte-identical to the current checked provider corpus +introduced by #652. The checked package proves a reproducible distribution occurrence. It does not by itself prove Edict schema admission, component-host readiness, Echo installation, runtime authority, invocation, execution, commitment, observation, or receipt. + +The separate isolated Edict c75 host gate binds this exact manifest, constructs +all 24 schema bindings, validates every canonical primary and generated +resource, proves the field-level resource identity graph, prepares both exact +components, and validates both request kinds without invoking guest code. Run +it from the repository root with: + +```bash +scripts/verify-edict-provider-host-v1.sh +``` + +The package-local archive carriers are checked independently with +`echo-edict-provider-assets --check-package-list`; carrier paths never replace +the original logical source identities recorded in generation provenance. diff --git a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json index 90602d7f..425401f7 100644 --- a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json index e341b270..3e8c6a48 100644 --- a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json +++ b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:793852c4e1e497bc3b9033439169f4edbe431495a4b1879d5e1d73645cfa9568","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:f61cfc7e1d32b1fb75188cc23ca25df852ed50059d3858d716ce136908ea7eae","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:86d7daf0639a8879199f6f0a57acf7cb935a99fa40bd48afc652e3afcffaf304","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/provider-manifest.echo.json b/schemas/edict-provider/package/v1/provider-manifest.echo.json index fd3dfa86..708ab173 100644 --- a/schemas/edict-provider/package/v1/provider-manifest.echo.json +++ b/schemas/edict-provider/package/v1/provider-manifest.echo.json @@ -3,7 +3,7 @@ "providerAbi": "edict:target-provider@1.0.0", "provider": { "coordinate": "echo.edict-provider@1", - "digest": "sha256:cf0147bea65cdfa7d426dc11a0eeab8f3ac889bfb3daa14f3d6b05ccd80f2d6e" + "digest": "sha256:af5be6b5670d559ba7a7bf5867ae51c0cdd7938fcaf147167640b50f1b27b688" }, "artifacts": [ { @@ -17,11 +17,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -36,11 +36,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -55,11 +55,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -74,11 +74,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -102,17 +102,17 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:ca526fb8690d86565d71c2af0d043e062b281b51df9a41ddb8375d6fbc606efc" + "digest": "sha256:9c64b8526c8183f1bc82507fabf2d24627d51d048d9bf98df29cec56e8648d79" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -121,17 +121,17 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:9044f199975f74b83f6702204385cbd7a979ee29afd26f2dbcb8bbe5b3946c6f" + "digest": "sha256:7b055bdd6f7d40c05ccca2010c3bad7012533fcc634fc207758bb7ed61e8e5d6" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -146,11 +146,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -165,11 +165,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:4305d5c0e14f9e83fcaee44d3ccc66a545fc060e409f00f407487b2592078902" + "digest": "sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:67b2be5f74a866b02ca96b666a060b3efd238da20b24a90820ebe8567b09d3cc" + "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" } } }, @@ -190,6 +190,90 @@ } ], "schemaBindings": [ + { + "domain": "echo.dpo-lawpack.adapter.echo-dpo@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-target-adapter" + }, + { + "domain": "echo.dpo-lawpack.compatibility@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-compatibility" + }, + { + "domain": "echo.dpo-lawpack.exports@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "lawpack-exports" + }, + { + "domain": "echo.dpo-lawpack.verifier@1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-lawpack-verifier" + }, + { + "domain": "echo.dpo.bundle/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-bundle" + }, + { + "domain": "echo.dpo.cost/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-cost" + }, + { + "domain": "echo.dpo.fixtures/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-provider-conformance-corpus" + }, + { + "domain": "echo.dpo.footprint/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-footprint" + }, + { + "domain": "echo.dpo.intrinsics/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "intrinsics-document" + }, + { + "domain": "echo.dpo.lowerer/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-lowerer" + }, + { + "domain": "echo.dpo.obstructions/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-obstructions" + }, + { + "domain": "echo.dpo.operation-profiles/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "operation-profiles-document" + }, + { + "domain": "echo.dpo.verifier/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-dpo-verifier" + }, + { + "domain": "echo.generated-artifact-profile/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "generated-artifact-profile" + }, { "domain": "echo.generated-artifact/v1", "schemaRole": "schema.echo-provider-artifacts", @@ -202,6 +286,12 @@ "format": "selfContainedCddlV1", "rootRule": "review-payload" }, + { + "domain": "echo.span-ir/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "echo-span-ir" + }, { "domain": "echo.verifier-report/v1", "schemaRole": "schema.echo-provider-artifacts", diff --git a/scripts/tests/classify_changes.test.cjs b/scripts/tests/classify_changes.test.cjs index a6545826..8684577f 100644 --- a/scripts/tests/classify_changes.test.cjs +++ b/scripts/tests/classify_changes.test.cjs @@ -142,7 +142,7 @@ test('every workspace member has an explicit non-catch-all policy path', () => { ); assert.match( policyYaml, - /echo-edict-provider-artifacts:\n\s+class: DET_CRITICAL\n\s+owner_role: "Tooling Engineer"\n\s+paths: \[.*"schemas\/edict-provider\/\*\*"\]\n/, + /echo-edict-provider-artifacts:\n\s+class: DET_CRITICAL\n\s+owner_role: "Tooling Engineer"\n\s+paths: \[.*"crates\/echo-wesley-gen\/assets\/v1\/\*\*".*"schemas\/edict-provider\/\*\*"\]\n/, ); assert.match(policyYaml, /echo-runtime-schema:\n\s+class: DET_CRITICAL\n/); assert.match(policyYaml, /echo-file-aperture:\n\s+class: DET_IMPORTANT\n/); diff --git a/scripts/verify-edict-provider-host-v1.sh b/scripts/verify-edict-provider-host-v1.sh index 799721f9..06aa895f 100755 --- a/scripts/verify-edict-provider-host-v1.sh +++ b/scripts/verify-edict-provider-host-v1.sh @@ -44,6 +44,12 @@ ECHO_PROVIDER_LOWERER_COMPONENT="$component" \ --locked \ --test host_contract +CARGO_TARGET_DIR="$HOST_TARGET_DIR" \ + cargo +1.94.0 test \ + --manifest-path "$MANIFEST" \ + --locked \ + --test package_contract + CARGO_TARGET_DIR="$HOST_TARGET_DIR" \ cargo +1.94.0 test \ --manifest-path "$MANIFEST" \ diff --git a/tests/edict-provider-host-v1/Cargo.lock b/tests/edict-provider-host-v1/Cargo.lock index d0f223da..a386a14e 100644 --- a/tests/edict-provider-host-v1/Cargo.lock +++ b/tests/edict-provider-host-v1/Cargo.lock @@ -355,6 +355,7 @@ dependencies = [ "edict-provider-host-wasmtime", "edict-provider-schema", "edict-syntax", + "serde_json", "sha2", ] diff --git a/tests/edict-provider-host-v1/Cargo.toml b/tests/edict-provider-host-v1/Cargo.toml index 567d8f16..886083e3 100644 --- a/tests/edict-provider-host-v1/Cargo.toml +++ b/tests/edict-provider-host-v1/Cargo.toml @@ -16,6 +16,7 @@ resolver = "2" edict-provider-host-wasmtime = { git = "https://github.com/flyingrobots/edict", rev = "c75c3f550d049485ba00eae0dc272c6dd6aca11f" } edict-provider-schema = { git = "https://github.com/flyingrobots/edict", rev = "c75c3f550d049485ba00eae0dc272c6dd6aca11f" } edict-syntax = { git = "https://github.com/flyingrobots/edict", rev = "c75c3f550d049485ba00eae0dc272c6dd6aca11f" } +serde_json = "=1.0.150" sha2 = "=0.10.9" [lints.rust] diff --git a/tests/edict-provider-host-v1/tests/package_contract.rs b/tests/edict-provider-host-v1/tests/package_contract.rs new file mode 100644 index 00000000..972c585d --- /dev/null +++ b/tests/edict-provider-host-v1/tests/package_contract.rs @@ -0,0 +1,1312 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)] +//! Edict-native pre-execution readiness witness for the checked Echo package. + +use std::collections::BTreeMap; +use std::fmt::Write as _; +use std::sync::Arc; + +use edict_provider_host_wasmtime::{ + ProviderComponentHost, ProviderHostFailureKind, ProviderHostPhase, ResolvedProviderComponent, +}; +use edict_provider_schema::{ + ProviderArtifactSchemaRegistry, ProviderSchemaRegistryFailureKind, + ResolvedProviderSchemaArtifact, +}; +use edict_syntax::{ + bind_target_provider_manifest, compile_to_core, decode_canonical_cbor, encode_canonical_cbor, + encode_core_module, encode_target_ir_artifact, lower_with_builtin_lowerer, parse_module, + select_provider_component, validate_provider_lowering_request, + validate_provider_verification_request, BuiltinLowererRequest, BuiltinTargetLowerer, + CanonicalValue, CompilerContext, CoreBudget, CoreModule, ProviderArtifact, + ProviderArtifactBinding, ProviderArtifactSchemaValidator, ProviderArtifactSource, + ProviderBoundArtifact, ProviderDigest, ProviderDigestAlgorithm, ProviderInvocationKind, + ProviderInvocationValidationFailureKind, ProviderLoweringInvocationContract, + ProviderLoweringOutputKind, ProviderLoweringOutputRequest, ProviderLoweringRequest, + ProviderResourceRef, ProviderResponseLimits, ProviderSchemaFormat, ProviderSemanticInput, + ProviderSemanticInputBinding, ProviderSemanticInputKind, + ProviderVerificationInvocationContract, ProviderVerificationOutputKind, + ProviderVerificationOutputRequest, ProviderVerificationRequest, ResourceRef, + TargetEffectLowering, TargetIrLoweringFacts, TargetProviderManifest, WriteClass, + AUTHORITY_FACTS_API_VERSION, CORE_DIGEST_FRAME, CORE_MODULE_DIGEST_DOMAIN, + ECHO_DPO_TARGET_PROFILE, ECHO_SPAN_IR_DOMAIN, PROVIDER_LAWPACK_ARTIFACT_DOMAIN, + TARGET_IR_ARTIFACT_DIGEST_DOMAIN, TARGET_PROFILE_API_VERSION, TARGET_PROVIDER_PROTOCOL_VERSION, +}; +use sha2::{Digest as _, Sha256}; + +const ECHO_SOURCE: &str = "package a.b@1;\n\ + type Input = { id: String, };\n\ + type Receipt = { id: String, };\n\ + type Output = { id: String, };\n\ + intent t(input: Input) returns Output\n\ + profile p.effectful\n\ + basis none\n\ + budget <= p.tiny {\n\ + let receipt: Receipt = target.replace(input.id)\n\ + else { rejected(reason) => domain.WriteRejected };\n\ + return { id: input.id };\n\ + }"; + +const SCHEMA_ROLE: &str = "schema.echo-provider-artifacts"; +const GENERATED_ARTIFACT_PROFILE_DOMAIN: &str = "echo.generated-artifact-profile/v1"; +const GENERATED_ARTIFACT_PROFILE_ROLE: &str = "generated-artifact-profile.echo-dpo-registration"; +const LOWERABILITY_DOMAIN: &str = "edict.lowering-requirements/v1"; +const LOWERER_ROLE: &str = "lowerer.echo-dpo"; +const TARGET_IR_ROLE: &str = "target-ir.echo-dpo"; +const VERIFIER_ROLE: &str = "verifier.echo-dpo"; +const VERIFIER_REPORT_DOMAIN: &str = "echo.verifier-report/v1"; +const VERIFIER_REPORT_ROLE: &str = "verifier-report.echo-dpo"; +const EXPECTED_SCHEMA_BINDING_COUNT: usize = 24; + +const MANIFEST_BYTES: &[u8] = + include_bytes!("../../../schemas/edict-provider/package/v1/provider-manifest.echo.json"); +const SCHEMA_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl" +); +const GENERATED_ARTIFACT_PROFILE_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/primary/generated-artifact-profile.echo-dpo-registration.cbor" +); +const LAWPACK_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor" +); +const TARGET_PROFILE_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor" +); +const TARGET_AUTHORITY_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor" +); +const LAWPACK_AUTHORITY_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor" +); +const LOWERER_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm" +); +const VERIFIER_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm" +); + +struct RoutedCanonicalArtifact { + role: &'static str, + domain: &'static str, + root: &'static str, + bytes: &'static [u8], +} + +const ROUTED_CANONICAL_ARTIFACTS: &[RoutedCanonicalArtifact] = &[ + RoutedCanonicalArtifact { + role: "authority-facts.echo-dpo", + domain: AUTHORITY_FACTS_API_VERSION, + root: "authority-facts", + bytes: TARGET_AUTHORITY_BYTES, + }, + RoutedCanonicalArtifact { + role: "authority-facts.echo-lawpack", + domain: AUTHORITY_FACTS_API_VERSION, + root: "authority-facts", + bytes: LAWPACK_AUTHORITY_BYTES, + }, + RoutedCanonicalArtifact { + role: GENERATED_ARTIFACT_PROFILE_ROLE, + domain: GENERATED_ARTIFACT_PROFILE_DOMAIN, + root: "generated-artifact-profile", + bytes: GENERATED_ARTIFACT_PROFILE_BYTES, + }, + RoutedCanonicalArtifact { + role: "lawpack.echo-dpo", + domain: PROVIDER_LAWPACK_ARTIFACT_DOMAIN, + root: "lawpack-manifest", + bytes: LAWPACK_BYTES, + }, + RoutedCanonicalArtifact { + role: "target-profile.echo-dpo", + domain: TARGET_PROFILE_API_VERSION, + root: "target-profile-manifest", + bytes: TARGET_PROFILE_BYTES, + }, +]; + +struct GeneratedResourceFixture { + path: &'static str, + domain: &'static str, + root: &'static str, + bytes: &'static [u8], +} + +const GENERATED_RESOURCE_FIXTURES: &[GeneratedResourceFixture] = &[ + GeneratedResourceFixture { + path: "resource.conformance-corpus.cbor", + domain: "echo.dpo.fixtures/v1", + root: "echo-provider-conformance-corpus", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.lawpack-compatibility.cbor", + domain: "echo.dpo-lawpack.compatibility@1", + root: "echo-provider-lawpack-compatibility", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.lawpack-compatibility.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.lawpack-exports.cbor", + domain: "echo.dpo-lawpack.exports@1", + root: "lawpack-exports", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.lawpack-exports.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.lawpack-target-adapter.cbor", + domain: "echo.dpo-lawpack.adapter.echo-dpo@1", + root: "echo-provider-lawpack-target-adapter", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.lawpack-target-adapter.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.lawpack-verifier.cbor", + domain: "echo.dpo-lawpack.verifier@1", + root: "echo-provider-lawpack-verifier", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.lawpack-verifier.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-bundle-profile.cbor", + domain: "echo.dpo.bundle/v1", + root: "echo-dpo-bundle", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-bundle-profile.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-cost-algebra.cbor", + domain: "echo.dpo.cost/v1", + root: "echo-dpo-cost", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-cost-algebra.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-footprint-algebra.cbor", + domain: "echo.dpo.footprint/v1", + root: "echo-dpo-footprint", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-footprint-algebra.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-intrinsics.cbor", + domain: "echo.dpo.intrinsics/v1", + root: "intrinsics-document", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-intrinsics.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-ir.cbor", + domain: "echo.span-ir/v1", + root: "echo-span-ir", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-ir.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-lowerer-contract.cbor", + domain: "echo.dpo.lowerer/v1", + root: "echo-dpo-lowerer", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-lowerer-contract.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-obstruction-taxonomy.cbor", + domain: "echo.dpo.obstructions/v1", + root: "echo-dpo-obstructions", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-obstruction-taxonomy.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-operation-profiles.cbor", + domain: "echo.dpo.operation-profiles/v1", + root: "operation-profiles-document", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-operation-profiles.cbor" + ), + }, + GeneratedResourceFixture { + path: "resource.target-verifier-contract.cbor", + domain: "echo.dpo.verifier/v1", + root: "echo-dpo-verifier", + bytes: include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/resources/resource.target-verifier-contract.cbor" + ), + }, +]; + +#[derive(Clone, Copy)] +struct GeneratedResourceMaterial<'a> { + coordinate: &'a str, + domain: &'a str, + bytes: &'a [u8], +} + +struct OwnerResourceReference<'a> { + expected_coordinate: &'static str, + reference: &'a CanonicalValue, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum PackageIdentityFailure { + ReferenceMalformed, + ConflictingOwnerReference, + FieldReferenceMismatch, + DuplicateMaterial, + CoordinateClosureMismatch, + DigestMismatch, + PrimaryReferenceMismatch, + AuthoritySourceMismatch, +} + +fn checked_manifest() -> TargetProviderManifest { + serde_json::from_slice(MANIFEST_BYTES) + .expect("the checked package manifest is exact typed Edict JSON") +} + +fn required_domains(manifest: &TargetProviderManifest) -> Vec<&str> { + manifest + .schema_bindings + .iter() + .map(|binding| binding.domain.as_str()) + .collect() +} + +fn declared_package_registry(manifest: &TargetProviderManifest) -> ProviderArtifactSchemaRegistry { + let proof = bind_target_provider_manifest(manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + ProviderArtifactSchemaRegistry::from_manifest( + &proof, + [ResolvedProviderSchemaArtifact { + role: SCHEMA_ROLE.to_owned(), + bytes: Arc::<[u8]>::from(SCHEMA_BYTES), + }], + required_domains(manifest), + ) + .expect("every currently declared package schema binding compiles") +} + +fn package_registry(manifest: &TargetProviderManifest) -> ProviderArtifactSchemaRegistry { + let proof = bind_target_provider_manifest(manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + let mut required = required_domains(manifest); + required.push(GENERATED_ARTIFACT_PROFILE_DOMAIN); + required.sort_unstable(); + required.dedup(); + ProviderArtifactSchemaRegistry::from_manifest( + &proof, + [ResolvedProviderSchemaArtifact { + role: SCHEMA_ROLE.to_owned(), + bytes: Arc::<[u8]>::from(SCHEMA_BYTES), + }], + required, + ) + .expect("every routed canonical primary has an owning package schema binding") +} + +fn hex(bytes: &[u8]) -> String { + let mut output = String::with_capacity(bytes.len() * 2); + for byte in bytes { + write!(&mut output, "{byte:02x}").expect("writing hexadecimal to String cannot fail"); + } + output +} + +fn raw_digest(bytes: &[u8]) -> String { + format!("sha256:{}", hex(&Sha256::digest(bytes))) +} + +fn provider_digest(domain: &str, canonical_bytes: &[u8]) -> ProviderDigest { + decode_canonical_cbor(canonical_bytes).expect("artifact is canonical CBOR"); + let mut framed = vec![0x83]; + framed + .extend(encode_canonical_cbor(&text(CORE_DIGEST_FRAME)).expect("digest frame tag encodes")); + framed.extend(encode_canonical_cbor(&text(domain)).expect("digest domain encodes")); + framed.extend_from_slice(canonical_bytes); + ProviderDigest { + algorithm: ProviderDigestAlgorithm::Sha256, + bytes: Sha256::digest(framed).to_vec(), + } +} + +fn rendered_provider_digest(digest: &ProviderDigest) -> String { + assert_eq!(digest.algorithm, ProviderDigestAlgorithm::Sha256); + format!("sha256:{}", hex(&digest.bytes)) +} + +fn bound_artifact(coordinate: &str, domain: &str, bytes: &[u8]) -> ProviderBoundArtifact { + ProviderBoundArtifact { + reference: ProviderResourceRef { + coordinate: coordinate.to_owned(), + digest: provider_digest(domain, bytes), + }, + artifact: ProviderArtifact { + domain: domain.to_owned(), + bytes: bytes.to_vec(), + }, + } +} + +fn artifact_binding(bound: &ProviderBoundArtifact) -> ProviderArtifactBinding { + ProviderArtifactBinding { + reference: bound.reference.clone(), + domain: bound.artifact.domain.clone(), + } +} + +fn text(value: &str) -> CanonicalValue { + CanonicalValue::Text(value.to_owned()) +} + +fn map(entries: impl IntoIterator) -> CanonicalValue { + CanonicalValue::Map( + entries + .into_iter() + .map(|(key, value)| (text(key), value)) + .collect(), + ) +} + +fn lowerability_bytes() -> Vec { + encode_canonical_cbor(&map([ + ("apiVersion", text(LOWERABILITY_DOMAIN)), + ("operationProfile", text("continuum.profile.write/v1")), + ( + "semanticEffects", + CanonicalValue::Array(vec![map([ + ("coordinate", text("target.replace")), + ("writeClass", text("replace")), + ( + "guardKinds", + CanonicalValue::Array(vec![text("precommit-atomic")]), + ), + ( + "obstructionCoordinates", + CanonicalValue::Array(vec![text("rejected")]), + ), + ( + "footprintObligations", + CanonicalValue::Array(vec![text("target.replace.footprint")]), + ), + ( + "costObligations", + CanonicalValue::Array(vec![text("target.replace.cost")]), + ), + ])]), + ), + ( + "requiredWriteClasses", + CanonicalValue::Array(vec![text("replace")]), + ), + ( + "guardKinds", + CanonicalValue::Array(vec![text("precommit-atomic")]), + ), + ("atomicity", text("atomic")), + ("postconditionSupport", CanonicalValue::Bool(true)), + ( + "obstructionCoordinates", + CanonicalValue::Array(vec![text("rejected")]), + ), + ( + "footprintObligations", + CanonicalValue::Array(vec![text("target.replace.footprint")]), + ), + ( + "costObligations", + CanonicalValue::Array(vec![text("target.replace.cost")]), + ), + ("opticContract", text("replace-point")), + ])) + .expect("lowerability facts encode canonically") +} + +fn echo_core() -> CoreModule { + let context = CompilerContext::new() + .with_operation_profile("p.effectful", "continuum.profile.write/v1") + .with_operation_profile_write_classes("p.effectful", [WriteClass::Replace]) + .with_effect_write_class("target.replace", WriteClass::Replace) + .with_budget( + "p.tiny", + CoreBudget { + max_steps: 8, + max_allocated_bytes: 1024, + max_output_bytes: 256, + }, + ); + let module = parse_module(ECHO_SOURCE).expect("Echo source parses"); + compile_to_core(&module, &context).expect("Echo source compiles to Core") +} + +fn semantic_input( + role: &str, + kind: ProviderSemanticInputKind, + coordinate: &str, + domain: &str, + bytes: &[u8], +) -> ProviderSemanticInput { + ProviderSemanticInput { + role: role.to_owned(), + kind, + artifact: bound_artifact(coordinate, domain, bytes), + } +} + +fn semantic_inputs() -> Vec { + let lowerability = lowerability_bytes(); + vec![ + semantic_input( + "authority-facts.echo-dpo", + ProviderSemanticInputKind::AuthorityFacts, + "echo.dpo-authority-facts@1", + AUTHORITY_FACTS_API_VERSION, + TARGET_AUTHORITY_BYTES, + ), + semantic_input( + "authority-facts.echo-lawpack", + ProviderSemanticInputKind::AuthorityFacts, + "echo.dpo-lawpack-authority-facts@1", + AUTHORITY_FACTS_API_VERSION, + LAWPACK_AUTHORITY_BYTES, + ), + semantic_input( + "lawpack.echo-dpo", + ProviderSemanticInputKind::Lawpack, + "echo.dpo-lawpack@1", + PROVIDER_LAWPACK_ARTIFACT_DOMAIN, + LAWPACK_BYTES, + ), + semantic_input( + "lowerability.echo-dpo", + ProviderSemanticInputKind::LowerabilityFacts, + "echo.dpo-lowerability@1", + LOWERABILITY_DOMAIN, + &lowerability, + ), + ] +} + +fn lowering_request( + core: &CoreModule, +) -> (ProviderLoweringInvocationContract, ProviderLoweringRequest) { + let core_bytes = encode_core_module(core).expect("Core module encodes canonically"); + let core_artifact = bound_artifact("a.b@1", CORE_MODULE_DIGEST_DOMAIN, &core_bytes); + let target_profile = bound_artifact( + ECHO_DPO_TARGET_PROFILE, + TARGET_PROFILE_API_VERSION, + TARGET_PROFILE_BYTES, + ); + let semantic_inputs = semantic_inputs(); + let contract = ProviderLoweringInvocationContract { + core: artifact_binding(&core_artifact), + target_profile: artifact_binding(&target_profile), + semantic_inputs: semantic_inputs + .iter() + .map(|input| ProviderSemanticInputBinding { + role: input.role.clone(), + kind: input.kind.clone(), + artifact: artifact_binding(&input.artifact), + }) + .collect(), + }; + let request = ProviderLoweringRequest { + protocol_version: TARGET_PROVIDER_PROTOCOL_VERSION, + core: core_artifact, + target_profile, + semantic_inputs, + requested_outputs: vec![ProviderLoweringOutputRequest { + role: TARGET_IR_ROLE.to_owned(), + kind: ProviderLoweringOutputKind::TargetIr, + domain: TARGET_IR_ARTIFACT_DIGEST_DOMAIN.to_owned(), + }], + limits: response_limits(), + }; + (contract, request) +} + +fn oracle_target_ir(core: &CoreModule, target_profile: ResourceRef) -> Vec { + let facts = TargetIrLoweringFacts { + target_profile, + target_ir_domain: ECHO_SPAN_IR_DOMAIN.to_owned(), + operation_profiles: vec!["continuum.profile.write/v1".to_owned()], + obstruction_coordinates: vec!["rejected".to_owned()], + effect_lowerings: vec![TargetEffectLowering { + effect: "target.replace".to_owned(), + target_intrinsic: "echo.dpo@1.replace".to_owned(), + }], + }; + let report = lower_with_builtin_lowerer( + BuiltinTargetLowerer::EchoDpo, + BuiltinLowererRequest { + core, + facts: &facts, + }, + ) + .expect("Edict's built-in Echo lowerer accepts the exact fixture"); + let artifact = report + .artifact + .expect("the exact fixture lowers to Target IR"); + encode_target_ir_artifact(&artifact).expect("oracle Target IR encodes canonically") +} + +fn verification_request( + core: &CoreModule, + target_ir_bytes: &[u8], +) -> ( + ProviderVerificationInvocationContract, + ProviderVerificationRequest, +) { + let core_bytes = encode_core_module(core).expect("Core module encodes canonically"); + let core_artifact = bound_artifact("a.b@1", CORE_MODULE_DIGEST_DOMAIN, &core_bytes); + let target_profile = bound_artifact( + ECHO_DPO_TARGET_PROFILE, + TARGET_PROFILE_API_VERSION, + TARGET_PROFILE_BYTES, + ); + let target_ir = bound_artifact( + "echo.target-ir@1", + TARGET_IR_ARTIFACT_DIGEST_DOMAIN, + target_ir_bytes, + ); + let semantic_inputs = semantic_inputs(); + let contract = ProviderVerificationInvocationContract { + core: artifact_binding(&core_artifact), + target_profile: artifact_binding(&target_profile), + target_ir: artifact_binding(&target_ir), + semantic_inputs: semantic_inputs + .iter() + .map(|input| ProviderSemanticInputBinding { + role: input.role.clone(), + kind: input.kind.clone(), + artifact: artifact_binding(&input.artifact), + }) + .collect(), + }; + let request = ProviderVerificationRequest { + protocol_version: TARGET_PROVIDER_PROTOCOL_VERSION, + core: core_artifact, + target_profile, + target_ir, + semantic_inputs, + requested_outputs: vec![ProviderVerificationOutputRequest { + role: VERIFIER_REPORT_ROLE.to_owned(), + kind: ProviderVerificationOutputKind::VerifierReport, + domain: VERIFIER_REPORT_DOMAIN.to_owned(), + }], + limits: response_limits(), + }; + (contract, request) +} + +const fn response_limits() -> ProviderResponseLimits { + ProviderResponseLimits { + max_output_count: 8, + max_diagnostic_count: 8, + max_total_response_bytes: 64 * 1024, + } +} + +fn routed_resource<'a>(manifest: &'a TargetProviderManifest, role: &str) -> &'a ResourceRef { + &manifest + .artifacts + .iter() + .find(|artifact| artifact.role == role) + .expect("the package contains every required routed role") + .resource +} + +fn assert_bound_matches_routed( + manifest: &TargetProviderManifest, + role: &str, + bound: &ProviderBoundArtifact, +) { + let routed = routed_resource(manifest, role); + assert_eq!(bound.reference.coordinate, routed.coordinate); + assert_eq!( + Some(rendered_provider_digest(&bound.reference.digest).as_str()), + routed.digest.as_deref() + ); +} + +fn assert_request_semantics_are_package_routed( + manifest: &TargetProviderManifest, + target_profile: &ProviderBoundArtifact, + inputs: &[ProviderSemanticInput], +) { + assert_bound_matches_routed(manifest, "target-profile.echo-dpo", target_profile); + for role in [ + "authority-facts.echo-dpo", + "authority-facts.echo-lawpack", + "lawpack.echo-dpo", + ] { + let input = inputs + .iter() + .find(|input| input.role == role) + .expect("the exact request carries every routed semantic input"); + assert_bound_matches_routed(manifest, role, &input.artifact); + } +} + +fn assert_schema_binding(manifest: &TargetProviderManifest, domain: &str, root: &str) { + let binding = manifest + .schema_bindings + .iter() + .find(|binding| binding.domain == domain) + .expect("every canonical package member has an exact owning schema binding"); + assert_eq!(binding.schema_role, SCHEMA_ROLE); + assert_eq!(binding.format, ProviderSchemaFormat::SelfContainedCddlV1); + assert_eq!(binding.root_rule, root); +} + +fn map_field<'a>(value: &'a CanonicalValue, field: &str) -> Option<&'a CanonicalValue> { + let CanonicalValue::Map(entries) = value else { + return None; + }; + entries.iter().find_map(|(key, value)| match key { + CanonicalValue::Text(key) if key == field => Some(value), + _ => None, + }) +} + +fn map_field_mut<'a>(value: &'a mut CanonicalValue, field: &str) -> Option<&'a mut CanonicalValue> { + let CanonicalValue::Map(entries) = value else { + return None; + }; + entries.iter_mut().find_map(|(key, value)| match key { + CanonicalValue::Text(key) if key == field => Some(value), + _ => None, + }) +} + +fn required_field<'a>( + value: &'a CanonicalValue, + field: &str, +) -> Result<&'a CanonicalValue, PackageIdentityFailure> { + map_field(value, field).ok_or(PackageIdentityFailure::ReferenceMalformed) +} + +fn required_singleton(value: &CanonicalValue) -> Result<&CanonicalValue, PackageIdentityFailure> { + let CanonicalValue::Array(values) = value else { + return Err(PackageIdentityFailure::ReferenceMalformed); + }; + let [value] = values.as_slice() else { + return Err(PackageIdentityFailure::CoordinateClosureMismatch); + }; + Ok(value) +} + +fn typed_digest_bytes(value: &CanonicalValue) -> Result<&[u8], PackageIdentityFailure> { + let CanonicalValue::Array(parts) = value else { + return Err(PackageIdentityFailure::ReferenceMalformed); + }; + let [CanonicalValue::Text(algorithm), CanonicalValue::Bytes(bytes)] = parts.as_slice() else { + return Err(PackageIdentityFailure::ReferenceMalformed); + }; + if algorithm != "sha256" || bytes.len() != 32 { + return Err(PackageIdentityFailure::ReferenceMalformed); + } + Ok(bytes) +} + +fn embedded_resource_ref(value: &CanonicalValue) -> Result<(&str, &[u8]), PackageIdentityFailure> { + let CanonicalValue::Text(coordinate) = required_field(value, "id")? else { + return Err(PackageIdentityFailure::ReferenceMalformed); + }; + let digest = typed_digest_bytes(required_field(value, "digest")?)?; + Ok((coordinate, digest)) +} + +fn insert_owner_reference( + closure: &mut BTreeMap>, + reference: &CanonicalValue, +) -> Result<(), PackageIdentityFailure> { + let (coordinate, digest) = embedded_resource_ref(reference)?; + if let Some(existing) = closure.get(coordinate) { + if existing != digest { + return Err(PackageIdentityFailure::ConflictingOwnerReference); + } + } else { + closure.insert(coordinate.to_owned(), digest.to_vec()); + } + Ok(()) +} + +fn owner_generated_resource_closure( + lawpack: &CanonicalValue, + target_profile: &CanonicalValue, +) -> Result>, PackageIdentityFailure> { + let target_adapters = required_field(lawpack, "targetAdapters")?; + let target_adapter = required_singleton(target_adapters)?; + let lawpack_verifier = required_field(lawpack, "verifier")?; + let mut closure = BTreeMap::new(); + for owner in [ + OwnerResourceReference { + expected_coordinate: "echo.dpo-lawpack.exports@1", + reference: required_field(lawpack, "exports")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.span-ir/v1", + reference: required_field(target_adapter, "acceptedTargetIr")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo-lawpack.adapter.echo-dpo@1", + reference: required_field(target_adapter, "adapter")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo-lawpack.verifier@1", + reference: required_field(lawpack_verifier, "ruleset")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo-lawpack.compatibility@1", + reference: required_field(lawpack, "compatibility")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.fixtures/v1", + reference: required_field(lawpack, "conformanceFixtureCorpus")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.intrinsics/v1", + reference: required_field(target_profile, "intrinsics")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.operation-profiles/v1", + reference: required_field(target_profile, "operationProfiles")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.footprint/v1", + reference: required_field(target_profile, "footprintAlgebra")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.cost/v1", + reference: required_field(target_profile, "costAlgebra")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.span-ir/v1", + reference: required_field(target_profile, "targetIr")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.obstructions/v1", + reference: required_field(target_profile, "obstructionTaxonomy")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.verifier/v1", + reference: required_field(target_profile, "verifier")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.lowerer/v1", + reference: required_field(target_profile, "lowerer")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.bundle/v1", + reference: required_field(target_profile, "bundleProfile")?, + }, + OwnerResourceReference { + expected_coordinate: "echo.dpo.fixtures/v1", + reference: required_field(target_profile, "conformanceFixtureCorpus")?, + }, + ] { + let (coordinate, _) = embedded_resource_ref(owner.reference)?; + if coordinate != owner.expected_coordinate { + return Err(PackageIdentityFailure::FieldReferenceMismatch); + } + insert_owner_reference(&mut closure, owner.reference)?; + } + Ok(closure) +} + +fn validate_generated_resource_identity_closure<'a>( + lawpack: &CanonicalValue, + target_profile: &CanonicalValue, + materials: impl IntoIterator>, +) -> Result<(), PackageIdentityFailure> { + let owner_closure = owner_generated_resource_closure(lawpack, target_profile)?; + let mut material_closure = BTreeMap::new(); + for material in materials { + let digest = provider_digest(material.domain, material.bytes).bytes; + if material_closure + .insert(material.coordinate.to_owned(), digest) + .is_some() + { + return Err(PackageIdentityFailure::DuplicateMaterial); + } + } + if owner_closure.len() != material_closure.len() + || owner_closure + .keys() + .zip(material_closure.keys()) + .any(|(owner, material)| owner != material) + { + return Err(PackageIdentityFailure::CoordinateClosureMismatch); + } + if material_closure + .iter() + .any(|(coordinate, digest)| owner_closure.get(coordinate) != Some(digest)) + { + return Err(PackageIdentityFailure::DigestMismatch); + } + Ok(()) +} + +fn embedded_ref_matches_routed( + manifest: &TargetProviderManifest, + role: &str, + reference: &CanonicalValue, +) -> Result<(), PackageIdentityFailure> { + let (coordinate, digest) = embedded_resource_ref(reference)?; + let routed = routed_resource(manifest, role); + if coordinate != routed.coordinate + || Some(format!("sha256:{}", hex(digest)).as_str()) != routed.digest.as_deref() + { + return Err(PackageIdentityFailure::PrimaryReferenceMismatch); + } + Ok(()) +} + +fn authority_source_matches_routed( + manifest: &TargetProviderManifest, + facts: &CanonicalValue, + expected_kind: &str, + expected_role: &str, +) -> Result<(), PackageIdentityFailure> { + let source = required_field(facts, "source")?; + let CanonicalValue::Text(kind) = required_field(source, "kind")? else { + return Err(PackageIdentityFailure::ReferenceMalformed); + }; + let CanonicalValue::Text(coordinate) = required_field(source, "coordinate")? else { + return Err(PackageIdentityFailure::ReferenceMalformed); + }; + let digest = typed_digest_bytes(required_field(source, "digest")?)?; + let routed = routed_resource(manifest, expected_role); + if kind != expected_kind + || coordinate != &routed.coordinate + || Some(format!("sha256:{}", hex(digest)).as_str()) != routed.digest.as_deref() + { + return Err(PackageIdentityFailure::AuthoritySourceMismatch); + } + Ok(()) +} + +fn validate_adjacent_primary_identity_edges( + manifest: &TargetProviderManifest, + lawpack: &CanonicalValue, + target_profile: &CanonicalValue, + target_authority: &CanonicalValue, + lawpack_authority: &CanonicalValue, +) -> Result<(), PackageIdentityFailure> { + let generated_profiles = required_field(target_profile, "generatedArtifactProfiles")?; + embedded_ref_matches_routed( + manifest, + GENERATED_ARTIFACT_PROFILE_ROLE, + required_singleton(generated_profiles)?, + )?; + let target_adapters = required_field(lawpack, "targetAdapters")?; + let target_adapter = required_singleton(target_adapters)?; + embedded_ref_matches_routed( + manifest, + "target-profile.echo-dpo", + required_field(target_adapter, "acceptedTargetProfile")?, + )?; + authority_source_matches_routed( + manifest, + target_authority, + "targetProfile", + "target-profile.echo-dpo", + )?; + authority_source_matches_routed(manifest, lawpack_authority, "lawpack", "lawpack.echo-dpo") +} + +fn exact_generated_resource_materials() -> impl Iterator> +{ + GENERATED_RESOURCE_FIXTURES + .iter() + .map(|fixture| GeneratedResourceMaterial { + coordinate: fixture.domain, + domain: fixture.domain, + bytes: fixture.bytes, + }) +} + +fn assert_routed_canonical_artifacts( + manifest: &TargetProviderManifest, + registry: &ProviderArtifactSchemaRegistry, +) { + for fixture in ROUTED_CANONICAL_ARTIFACTS { + assert_schema_binding(manifest, fixture.domain, fixture.root); + let value = decode_canonical_cbor(fixture.bytes) + .expect("the routed package artifact is exact canonical CBOR"); + registry + .validate_canonical_value(fixture.domain, &value) + .expect("the routed package artifact satisfies its owning root"); + let expected = rendered_provider_digest(&provider_digest(fixture.domain, fixture.bytes)); + assert_eq!( + routed_resource(manifest, fixture.role).digest.as_deref(), + Some(expected.as_str()) + ); + } +} + +fn assert_generated_resources( + manifest: &TargetProviderManifest, + registry: &ProviderArtifactSchemaRegistry, +) { + for fixture in GENERATED_RESOURCE_FIXTURES { + assert_schema_binding(manifest, fixture.domain, fixture.root); + let value = decode_canonical_cbor(fixture.bytes) + .unwrap_or_else(|error| panic!("{} is not canonical: {error}", fixture.path)); + registry + .validate_canonical_value(fixture.domain, &value) + .unwrap_or_else(|error| { + panic!( + "{} does not satisfy {}: {error:?}", + fixture.path, fixture.root + ); + }); + } +} + +#[test] +fn checked_package_is_ready_for_edict_before_guest_execution() { + let manifest = checked_manifest(); + let proof = bind_target_provider_manifest(&manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + let registry = package_registry(&manifest); + assert_eq!( + manifest.schema_bindings.len(), + EXPECTED_SCHEMA_BINDING_COUNT + ); + assert_eq!(registry.bindings().len(), EXPECTED_SCHEMA_BINDING_COUNT); + assert_routed_canonical_artifacts(&manifest, ®istry); + assert_generated_resources(&manifest, ®istry); + let lawpack = decode_canonical_cbor(LAWPACK_BYTES).expect("lawpack is canonical"); + let target_profile = + decode_canonical_cbor(TARGET_PROFILE_BYTES).expect("target profile is canonical"); + let target_authority = + decode_canonical_cbor(TARGET_AUTHORITY_BYTES).expect("target facts are canonical"); + let lawpack_authority = + decode_canonical_cbor(LAWPACK_AUTHORITY_BYTES).expect("lawpack facts are canonical"); + validate_generated_resource_identity_closure( + &lawpack, + &target_profile, + exact_generated_resource_materials(), + ) + .expect("the exact 14-resource owner union binds every domain-framed digest"); + validate_adjacent_primary_identity_edges( + &manifest, + &lawpack, + &target_profile, + &target_authority, + &lawpack_authority, + ) + .expect("the exact package primary identity graph is closed"); + + let host = ProviderComponentHost::new().expect("the deterministic host configures"); + let lowerer = select_provider_component(&proof, LOWERER_ROLE, ProviderInvocationKind::Lowering) + .expect("the checked package selects its lowerer"); + let lowerer = ResolvedProviderComponent::new(lowerer, Arc::<[u8]>::from(LOWERER_BYTES)); + let _prepared_lowerer = host + .prepare(&lowerer) + .expect("the exact packaged lowerer passes Edict preflight"); + let verifier = + select_provider_component(&proof, VERIFIER_ROLE, ProviderInvocationKind::Verification) + .expect("the checked package selects its verifier"); + let verifier = ResolvedProviderComponent::new(verifier, Arc::<[u8]>::from(VERIFIER_BYTES)); + let _prepared_verifier = host + .prepare(&verifier) + .expect("the exact packaged verifier passes Edict preflight"); + + let core = echo_core(); + let (lowering_contract, lowering_request) = lowering_request(&core); + assert_request_semantics_are_package_routed( + &manifest, + &lowering_request.target_profile, + &lowering_request.semantic_inputs, + ); + let _lowering_proof = + validate_provider_lowering_request(®istry, &lowering_contract, &lowering_request) + .expect("the exact lowerer request has an Edict validation proof"); + + let target_ir = oracle_target_ir( + &core, + routed_resource(&manifest, "target-profile.echo-dpo").clone(), + ); + let (verification_contract, verification_request) = verification_request(&core, &target_ir); + assert_request_semantics_are_package_routed( + &manifest, + &verification_request.target_profile, + &verification_request.semantic_inputs, + ); + let _verification_proof = validate_provider_verification_request( + ®istry, + &verification_contract, + &verification_request, + ) + .expect("the exact verifier request has an Edict validation proof"); +} + +#[test] +fn schema_valid_resource_replacement_cannot_cross_the_exact_owner_digest() { + let manifest = checked_manifest(); + let registry = package_registry(&manifest); + let mut replacement = decode_canonical_cbor( + GENERATED_RESOURCE_FIXTURES + .iter() + .find(|fixture| fixture.domain == "echo.dpo.cost/v1") + .expect("the cost resource fixture exists") + .bytes, + ) + .expect("the exact cost resource is canonical"); + let capabilities = map_field_mut(&mut replacement, "capabilities") + .expect("the cost resource carries capabilities"); + let CanonicalValue::Map(capabilities) = capabilities else { + panic!("cost capabilities must be a map"); + }; + let capability = &mut capabilities + .first_mut() + .expect("the exact cost resource carries one capability") + .1; + *map_field_mut(capability, "costTemplate").expect("the cost capability has a template") = + text("schema-valid-but-different"); + registry + .validate_canonical_value("echo.dpo.cost/v1", &replacement) + .expect("the replacement deliberately preserves the owning CDDL shape"); + let replacement_bytes = + encode_canonical_cbor(&replacement).expect("the replacement encodes canonically"); + let exact_cost_bytes = GENERATED_RESOURCE_FIXTURES + .iter() + .find(|fixture| fixture.domain == "echo.dpo.cost/v1") + .expect("the cost resource fixture exists") + .bytes; + assert_ne!(replacement_bytes, exact_cost_bytes); + + let lawpack = decode_canonical_cbor(LAWPACK_BYTES).expect("lawpack is canonical"); + let target_profile = + decode_canonical_cbor(TARGET_PROFILE_BYTES).expect("target profile is canonical"); + let materials = GENERATED_RESOURCE_FIXTURES + .iter() + .map(|fixture| GeneratedResourceMaterial { + coordinate: fixture.domain, + domain: fixture.domain, + bytes: if fixture.domain == "echo.dpo.cost/v1" { + &replacement_bytes + } else { + fixture.bytes + }, + }); + let error = validate_generated_resource_identity_closure(&lawpack, &target_profile, materials) + .expect_err("schema validity cannot replace the exact owner-bound resource identity"); + assert_eq!(error, PackageIdentityFailure::DigestMismatch); +} + +#[test] +fn schema_valid_lawpack_reference_mismatch_fails_identity_closure() { + let manifest = checked_manifest(); + let registry = declared_package_registry(&manifest); + let mut lawpack = decode_canonical_cbor(LAWPACK_BYTES).expect("lawpack is canonical"); + let exports = map_field_mut(&mut lawpack, "exports").expect("lawpack carries exports"); + let digest = map_field_mut(exports, "digest").expect("exports reference carries a digest"); + let CanonicalValue::Array(parts) = digest else { + panic!("exports digest must be typed"); + }; + let Some(CanonicalValue::Bytes(bytes)) = parts.get_mut(1) else { + panic!("exports digest must carry raw bytes"); + }; + bytes[0] ^= 1; + let changed_bytes = + encode_canonical_cbor(&lawpack).expect("changed lawpack encodes canonically"); + let changed_lawpack = + decode_canonical_cbor(&changed_bytes).expect("changed lawpack remains canonical"); + registry + .validate_canonical_value(PROVIDER_LAWPACK_ARTIFACT_DOMAIN, &changed_lawpack) + .expect("the mismatching reference deliberately preserves the lawpack CDDL shape"); + let target_profile = + decode_canonical_cbor(TARGET_PROFILE_BYTES).expect("target profile is canonical"); + let error = validate_generated_resource_identity_closure( + &changed_lawpack, + &target_profile, + exact_generated_resource_materials(), + ) + .expect_err("schema-valid reference bytes cannot replace the exact resource digest"); + assert_eq!(error, PackageIdentityFailure::DigestMismatch); +} + +#[test] +fn schema_valid_reference_swap_cannot_hide_behind_union_equality() { + let manifest = checked_manifest(); + let registry = declared_package_registry(&manifest); + let mut lawpack = decode_canonical_cbor(LAWPACK_BYTES).expect("lawpack is canonical"); + let exports = map_field(&lawpack, "exports") + .expect("lawpack carries exports") + .clone(); + let compatibility = map_field(&lawpack, "compatibility") + .expect("lawpack carries compatibility") + .clone(); + *map_field_mut(&mut lawpack, "exports").expect("lawpack carries exports") = compatibility; + *map_field_mut(&mut lawpack, "compatibility").expect("lawpack carries compatibility") = exports; + let changed_bytes = + encode_canonical_cbor(&lawpack).expect("swapped lawpack encodes canonically"); + let changed_lawpack = + decode_canonical_cbor(&changed_bytes).expect("swapped lawpack remains canonical"); + registry + .validate_canonical_value(PROVIDER_LAWPACK_ARTIFACT_DOMAIN, &changed_lawpack) + .expect("the field swap deliberately preserves the lawpack CDDL shape"); + let target_profile = + decode_canonical_cbor(TARGET_PROFILE_BYTES).expect("target profile is canonical"); + let error = validate_generated_resource_identity_closure( + &changed_lawpack, + &target_profile, + exact_generated_resource_materials(), + ) + .expect_err("coordinate-union equality cannot erase semantic field ownership"); + assert_eq!(error, PackageIdentityFailure::FieldReferenceMismatch); +} + +#[test] +fn schema_valid_authority_source_mismatch_fails_primary_identity_closure() { + let manifest = checked_manifest(); + let registry = declared_package_registry(&manifest); + let lawpack = decode_canonical_cbor(LAWPACK_BYTES).expect("lawpack is canonical"); + let target_profile = + decode_canonical_cbor(TARGET_PROFILE_BYTES).expect("target profile is canonical"); + let mut target_authority = + decode_canonical_cbor(TARGET_AUTHORITY_BYTES).expect("target facts are canonical"); + let source = + map_field_mut(&mut target_authority, "source").expect("target facts carry a source"); + *map_field_mut(source, "coordinate").expect("authority source carries a coordinate") = + text("echo.dpo@1.schema-valid-mismatch"); + let changed_bytes = encode_canonical_cbor(&target_authority) + .expect("changed authority facts encode canonically"); + let changed_target_authority = + decode_canonical_cbor(&changed_bytes).expect("changed authority facts remain canonical"); + registry + .validate_canonical_value(AUTHORITY_FACTS_API_VERSION, &changed_target_authority) + .expect("the mismatching source deliberately preserves the authority-facts CDDL shape"); + let lawpack_authority = + decode_canonical_cbor(LAWPACK_AUTHORITY_BYTES).expect("lawpack facts are canonical"); + let error = validate_adjacent_primary_identity_edges( + &manifest, + &lawpack, + &target_profile, + &changed_target_authority, + &lawpack_authority, + ) + .expect_err("schema-valid authority facts cannot change their exact subject identity"); + assert_eq!(error, PackageIdentityFailure::AuthoritySourceMismatch); +} + +#[test] +fn malformed_manifest_fails_before_component_selection() { + let mut manifest = checked_manifest(); + manifest.provider_abi = "edict:target-provider@invalid".to_owned(); + let report = bind_target_provider_manifest(&manifest) + .expect_err("an invalid provider ABI cannot produce an Edict manifest proof"); + assert!(report.failures.iter().any(|failure| { + failure.kind == edict_syntax::ProviderManifestValidationFailureKind::InvalidProviderAbi + })); +} + +#[test] +fn malformed_schema_fails_before_component_selection() { + let mut manifest = checked_manifest(); + let malformed_schema: &[u8] = b"this is not CDDL"; + let schema = manifest + .artifacts + .iter_mut() + .find(|artifact| artifact.role == SCHEMA_ROLE) + .expect("the package routes its schema artifact"); + schema.resource.digest = Some(raw_digest(malformed_schema)); + let proof = bind_target_provider_manifest(&manifest) + .expect("the coherently rebound malformed schema remains a typed manifest"); + let required = required_domains(&manifest); + let error = ProviderArtifactSchemaRegistry::from_manifest( + &proof, + [ResolvedProviderSchemaArtifact { + role: SCHEMA_ROLE.to_owned(), + bytes: Arc::<[u8]>::from(malformed_schema), + }], + required, + ) + .expect_err("malformed schema bytes cannot produce an Edict registry"); + assert_eq!( + error.kind(), + ProviderSchemaRegistryFailureKind::SchemaCompileFailed + ); +} + +#[test] +fn malformed_component_fails_during_preflight() { + let mut manifest = checked_manifest(); + let mut malformed_component = LOWERER_BYTES.to_vec(); + malformed_component[0] ^= 1; + let digest = raw_digest(&malformed_component); + let lowerer = manifest + .artifacts + .iter_mut() + .find(|artifact| artifact.role == LOWERER_ROLE) + .expect("the package routes its lowerer component"); + lowerer.resource.digest = Some(digest.clone()); + match &mut lowerer.source { + ProviderArtifactSource::Component { component } => { + component.digest = Some(digest); + } + ProviderArtifactSource::Generated { .. } => panic!("lowerer source must be a component"), + } + let proof = bind_target_provider_manifest(&manifest) + .expect("the coherently rebound component remains a typed manifest"); + let selected = + select_provider_component(&proof, LOWERER_ROLE, ProviderInvocationKind::Lowering) + .expect("the coherently rebound lowerer still selects"); + let resolved = ResolvedProviderComponent::new(selected, Arc::<[u8]>::from(malformed_component)); + let host = ProviderComponentHost::new().expect("the deterministic host configures"); + let error = host + .prepare(&resolved) + .expect_err("malformed component bytes cannot pass Edict preflight"); + assert_eq!(error.kind(), ProviderHostFailureKind::ComponentDecodeFailed); + assert_eq!(error.phase(), ProviderHostPhase::Preflight); +} + +#[test] +fn malformed_artifact_fails_before_component_execution() { + let manifest = checked_manifest(); + let proof = bind_target_provider_manifest(&manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + let required = required_domains(&manifest); + let registry = ProviderArtifactSchemaRegistry::from_manifest( + &proof, + [ResolvedProviderSchemaArtifact { + role: SCHEMA_ROLE.to_owned(), + bytes: Arc::<[u8]>::from(SCHEMA_BYTES), + }], + required, + ) + .expect("the exact manifest bindings produce an Edict registry"); + let core = echo_core(); + let (mut contract, mut request) = lowering_request(&core); + let malformed = + encode_canonical_cbor(&CanonicalValue::Null).expect("null has canonical CBOR bytes"); + let target_profile = bound_artifact( + ECHO_DPO_TARGET_PROFILE, + TARGET_PROFILE_API_VERSION, + &malformed, + ); + contract.target_profile = artifact_binding(&target_profile); + request.target_profile = target_profile; + + let report = validate_provider_lowering_request(®istry, &contract, &request) + .expect_err("schema-invalid target profile cannot produce an invocation proof"); + assert!(report.failures.iter().any(|failure| { + failure.kind == ProviderInvocationValidationFailureKind::ArtifactSchemaMismatch + })); +} From 1779af2d524e68f38ee203f755eea00d81079b77 Mon Sep 17 00:00:00 2001 From: James Ross Date: Thu, 16 Jul 2026 14:58:35 -0700 Subject: [PATCH 5/6] Harden provider package review boundaries --- CHANGELOG.md | 12 ++--- crates/echo-edict-canonical/README.md | 6 ++- crates/echo-edict-canonical/src/lib.rs | 41 +++++++++++++++++- .../tests/canonical_contract.rs | 39 ++++++++++++++++- crates/echo-edict-provider-verifier/README.md | 4 +- .../lowerer.echo-dpo.component.wasm | Bin 130679 -> 131156 bytes .../verifier.echo-dpo.component.wasm | Bin 188736 -> 189213 bytes .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../package/v1/provider-manifest.echo.json | 30 ++++++------- .../echo-edict-canonical/src/lib.rs.source | 41 +++++++++++++++++- .../src/bin/echo-edict-provider-assets.rs | 38 ++++++++++++++-- .../tests/provider_package_corpus.rs | 4 +- det-policy.yaml | 2 +- .../edict-provider/components/v1/README.md | 8 ++-- .../v1/lowerer.echo-dpo.component.wasm | Bin 130679 -> 131156 bytes .../v1/verifier.echo-dpo.component.wasm | Bin 188736 -> 189213 bytes .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../lowerer.echo-dpo.component.wasm | Bin 130679 -> 131156 bytes .../verifier.echo-dpo.component.wasm | Bin 188736 -> 189213 bytes .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../package/v1/provider-manifest.echo.json | 30 ++++++------- scripts/tests/classify_changes.test.cjs | 2 +- xtask/src/provider_lowerer_component.rs | 4 +- 26 files changed, 213 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661ed01a..5b1fa85f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,8 @@ all fail closed through structured errors. This is package-occurrence authentication only; Edict schema/component preflight and Echo runtime installation remain separate authority crossings. A dedicated publisher now - checks that all 22 generated members exactly reproduce the checked #652 - corpus before writing the two components and derived manifest as a + checks that all 22 generated members exactly reproduce the current checked + provider corpus introduced by #652 before writing the two components and derived manifest as a self-contained 25-file distribution. Its capability-oriented filesystem boundary refuses invalid expected inventories before resolving the root, bounds actual-tree enumeration and expected-byte reads, never opens an @@ -86,8 +86,8 @@ predicate, input-constraint, require-failure, and Core-value shapes before separating malformed artifacts from well-formed unsupported semantics, and one admitted diagnostic-ABI identity now binds both the target profile and - every emitted report. The 188,736-byte checked component has SHA-256 - `e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b` + every emitted report. The 189,213-byte checked component has SHA-256 + `c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07` and reproduces byte-for-byte across independently provisioned designated `linux/amd64` builders. The isolated pinned Edict host preflights the exact request artifacts and declared output schema, invokes that checked component, @@ -100,7 +100,9 @@ canonical CBOR and domain-framed digest contracts as a publishable `0.1.0` leaf. `echo-wesley-gen` retains its existing compatibility surface through a re-export, while executable provider components use the same codec without - depending on generator or Wesley APIs. + depending on generator or Wesley APIs. Its decoder now applies a 65,536-node + host materialization ceiling, charging map keys and values separately and + rejecting oversized direct containers before reserving their storage. - `echo-wesley-gen` now checks in the first exact 22-file Edict provider artifact corpus: five canonical-CBOR primaries, fourteen canonical-CBOR resources, the self-contained CDDL, Wesley provenance JSON, and diff --git a/crates/echo-edict-canonical/README.md b/crates/echo-edict-canonical/README.md index 5e663009..ad218d67 100644 --- a/crates/echo-edict-canonical/README.md +++ b/crates/echo-edict-canonical/README.md @@ -15,7 +15,11 @@ definite-length byte and UTF-8 text strings, arrays, and maps. Encoding sorts maps by canonical key bytes and rejects duplicate canonical keys. Decoding rejects indefinite-length, tagged, floating-point, simple, non-minimal, trailing, malformed, duplicate-key, and noncanonical inputs. Both directions -enforce Edict's exact 128-container nesting boundary. +enforce Edict's exact 128-container nesting boundary. Decoding additionally +caps one materialized value tree at 65,536 nodes, charging map keys and values +separately and rejecting oversized direct container cardinalities before host +allocation. That node ceiling is an Echo host resource bound, not a new Edict +byte-identity claim. Failures expose stable `CanonicalValueErrorKind` values rather than Rust debug spellings. The implementation is deterministic and pure: it performs no diff --git a/crates/echo-edict-canonical/src/lib.rs b/crates/echo-edict-canonical/src/lib.rs index 81cac630..ada72fd8 100644 --- a/crates/echo-edict-canonical/src/lib.rs +++ b/crates/echo-edict-canonical/src/lib.rs @@ -26,6 +26,14 @@ pub const EDICT_DIGEST_FRAME_V1: &str = "edict.digest/v1"; /// is accepted; one additional container is rejected. pub const MAX_CANONICAL_NESTING_DEPTH_V1: usize = 128; +/// Maximum number of value nodes materialized by one canonical decode. +/// +/// The root counts as one node. Array members, map keys, and map values each +/// count separately. This is an Echo host resource bound rather than part of +/// the Edict canonical byte identity; it prevents compact collection headers +/// from amplifying into unbounded host allocations before admission. +pub const MAX_CANONICAL_DECODE_NODES_V1: usize = 65_536; + /// Stable failure categories for Edict canonical values and byte streams. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum CanonicalValueErrorKind { @@ -360,11 +368,16 @@ where struct Decoder<'a> { bytes: &'a [u8], position: usize, + remaining_nodes: usize, } impl<'a> Decoder<'a> { const fn new(bytes: &'a [u8]) -> Self { - Self { bytes, position: 0 } + Self { + bytes, + position: 0, + remaining_nodes: MAX_CANONICAL_DECODE_NODES_V1, + } } const fn remaining(&self) -> usize { @@ -372,6 +385,7 @@ impl<'a> Decoder<'a> { } fn value(&mut self, depth: usize) -> Result { + self.charge_nodes(1)?; check_depth(depth)?; let initial = self.byte()?; let major = initial >> 5; @@ -401,6 +415,7 @@ impl<'a> Decoder<'a> { 4 => { check_container_depth(depth)?; let length = self.length(additional)?; + self.ensure_nodes_available(length)?; let mut values = Vec::with_capacity(length); for _ in 0..length { values.push(self.value(depth + 1)?); @@ -410,6 +425,8 @@ impl<'a> Decoder<'a> { 5 => { check_container_depth(depth)?; let length = self.length(additional)?; + let child_nodes = length.checked_mul(2).ok_or_else(node_budget_error)?; + self.ensure_nodes_available(child_nodes)?; let mut entries = Vec::with_capacity(length); let mut encoded_keys = BTreeSet::new(); for _ in 0..length { @@ -469,6 +486,21 @@ impl<'a> Decoder<'a> { checked_collection_length::(declared, remaining) } + fn ensure_nodes_available(&self, required: usize) -> Result<(), CanonicalValueError> { + if required > self.remaining_nodes { + return Err(node_budget_error()); + } + Ok(()) + } + + fn charge_nodes(&mut self, count: usize) -> Result<(), CanonicalValueError> { + self.remaining_nodes = self + .remaining_nodes + .checked_sub(count) + .ok_or_else(node_budget_error)?; + Ok(()) + } + fn byte(&mut self) -> Result { let Some(value) = self.bytes.get(self.position).copied() else { return Err(CanonicalValueError::new( @@ -504,6 +536,13 @@ impl<'a> Decoder<'a> { } } +fn node_budget_error() -> CanonicalValueError { + CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedValue, + "canonical CBOR decoded node budget exceeded", + ) +} + #[cfg(test)] mod tests { use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind}; diff --git a/crates/echo-edict-canonical/tests/canonical_contract.rs b/crates/echo-edict-canonical/tests/canonical_contract.rs index 1e095f0e..a3ff2cbb 100644 --- a/crates/echo-edict-canonical/tests/canonical_contract.rs +++ b/crates/echo-edict-canonical/tests/canonical_contract.rs @@ -5,7 +5,8 @@ use echo_edict_canonical::{ decode_canonical_cbor_v1, digest_canonical_value_v1, encode_canonical_cbor_v1, - CanonicalValueErrorKind, CanonicalValueV1, MAX_CANONICAL_NESTING_DEPTH_V1, + CanonicalValueErrorKind, CanonicalValueV1, MAX_CANONICAL_DECODE_NODES_V1, + MAX_CANONICAL_NESTING_DEPTH_V1, }; fn text(value: &str) -> CanonicalValueV1 { @@ -267,3 +268,39 @@ fn unsupported_cbor_and_digest_domains_fail_closed() { digest_canonical_value_v1("test.second/v1", &value).expect("second digest computes") ); } + +#[test] +fn decoded_node_budget_rejects_compact_container_amplification_before_reserve() { + let node_limit = u32::try_from(MAX_CANONICAL_DECODE_NODES_V1) + .expect("canonical decode-node limit fits the CBOR u32 length form"); + + let mut array = vec![0x9a]; + array.extend_from_slice(&node_limit.to_be_bytes()); + array.resize(array.len() + MAX_CANONICAL_DECODE_NODES_V1, 0xf6); + let array_error = decode_canonical_cbor_v1(&array) + .expect_err("an array that exhausts the child-node budget rejects before reserve"); + assert_eq!( + array_error.kind(), + CanonicalValueErrorKind::UnsupportedValue + ); + assert_eq!( + array_error.detail(), + "canonical CBOR decoded node budget exceeded" + ); + + let map_entries = node_limit / 2; + let mut map = vec![0xb9]; + map.extend_from_slice( + &u16::try_from(map_entries) + .expect("half the canonical decode-node limit fits the CBOR u16 length form") + .to_be_bytes(), + ); + map.resize(map.len() + MAX_CANONICAL_DECODE_NODES_V1, 0xf6); + let map_error = decode_canonical_cbor_v1(&map) + .expect_err("a map that exhausts the key/value-node budget rejects before reserve"); + assert_eq!(map_error.kind(), CanonicalValueErrorKind::UnsupportedValue); + assert_eq!( + map_error.detail(), + "canonical CBOR decoded node budget exceeded" + ); +} diff --git a/crates/echo-edict-provider-verifier/README.md b/crates/echo-edict-provider-verifier/README.md index 5a58ccd0..879124d5 100644 --- a/crates/echo-edict-provider-verifier/README.md +++ b/crates/echo-edict-provider-verifier/README.md @@ -21,9 +21,9 @@ target profile's diagnostic ABI and every emitted report consume one shared admitted identity. The `wasm32` guest adapter vendors Edict's exact frozen `edict:target-provider/verifier@1.0.0` WIT world and performs only exhaustive -transport-to-model conversion. Its reproducibly built 188,736-byte checked +transport-to-model conversion. Its reproducibly built 189,213-byte checked component has SHA-256 -`e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b`. +`c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07`. Component identity and admitted host replay remain separate propositions: the pinned Edict host preflights the request artifacts and declared output schema, invokes the checked component, then admits and manifests each returned accepted diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm index a85ae30a7ae2c25c4fa087952b53072333f352c5..41259f86ea5848dc81e8d597ee1093cdfaea7491 100644 GIT binary patch delta 6420 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
h7C4@HQEL;wH) delta 5979 zcmb7I3vg7`8NUD7O?H#rB^yjMBFfzb(*y(wj}3zk=7Kyzz+j=Hmd;pFR2HN{QBzyp z*dmicgaDBfEy{{ajT&h**v&ZTtSzGf0xmRYT4|fk;52rk#+mR?VeI#xb2bkjqh@Av z?*BOd`~2s>x1-v7_PnQgQij;^am$p9F(UiJ&ZOmwSx#@~_GO;8#J{$+jP?GfC(zrG zthOA>q3Kpn$M%BL6GUIf_Ial#145z*Vxvf}egg?-+jMn{Aa=CjF3iRhSW{8#F1_1!IaWmYZI>+~!i$9>!VP4~isHXJD)-H#6PX|s z34dbCEGj1Pe1UxJdb&IadYq!R2-f@-W{5KRR5{I%J7&{wWpEC;Wx*V(q#Swo94d?n zhc#Et30N#?4~59aQ?aX&N}=3htzIm!!EIZPXS!wihxs%^DATrPTBWW6&@)S2LC^)$ z1E4Dd$j%7XY7CDMY{aia(p>mF{|G}6KZ!lu~|qDV$g(4B1N3ZZ*e+XZZ4;Va@TyykT=bx zJlR)HQzvG#OYW%c34Zj5swUer8&(L1q9IhDvkz+)R#corYeQ~%bUrN`t@03zIyup> z-*#guvaE;&LmVKz(Qv?a%f%HGLN(r3LDxluosH75;Y6`3SZX2c{8Usb@}MazY6ps4 zRw*-JzwI}|g#2Fx-A-A`ZY-)m`~wBD#IK8YaAvdEooSE}>|u8R;FK-U%k`qn_V+uN zb}BC#$_BmPzeP7te!$}@(>PQ}mRx%SEsR0(Fgv?gSfzr+B7N+=P~L~V{r)o^0muLz zOHQ$c6J*)L0NB}#2^I-h1PQhqv@i}<4cQ)uvW1c1VcrZA5D$(X;^MO9j7l1dAgrjQ zCFGTFRMG>b-hpz=3U1J+VZ4QNnCp1v1Tqoiv|Sl?+7jrMs}|9yh;qf1B;z}L$>}#C zp!LIW7a#pNA#$j(vT%lca}n9G3@39P`;HtgV)uldJKeH%QsY!=h4f<*O=b#m3V*

9xpqVpj-|txfl7^VW}O&{Q9gJhEk=AQ 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 Im^bjh0Oq$q;s5{u delta 5979 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 diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json index 425401f7..9fac25c1 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json index 3e8c6a48..50655456 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:86d7daf0639a8879199f6f0a57acf7cb935a99fa40bd48afc652e3afcffaf304","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:53d9fbfaab7b8c736411f756253acb781ac1262fad7cf26e83e24a23b3a8ffdb","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json index 708ab173..fcecb4e1 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json @@ -3,7 +3,7 @@ "providerAbi": "edict:target-provider@1.0.0", "provider": { "coordinate": "echo.edict-provider@1", - "digest": "sha256:af5be6b5670d559ba7a7bf5867ae51c0cdd7938fcaf147167640b50f1b27b688" + "digest": "sha256:18763560111cad22317a79dec57165affe148c4bb27f92707dbdf4b1cce07f2a" }, "artifacts": [ { @@ -21,7 +21,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -40,7 +40,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -59,7 +59,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -78,7 +78,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -87,13 +87,13 @@ "artifactKind": "lowerer", "resource": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + "digest": "sha256:4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + "digest": "sha256:4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee" } } }, @@ -102,7 +102,7 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:9c64b8526c8183f1bc82507fabf2d24627d51d048d9bf98df29cec56e8648d79" + "digest": "sha256:d7422a0d7496f2d14b5c346965c9b70c86d217ea6fbae13f34accf5b1f593be8" }, "source": { "kind": "generated", @@ -112,7 +112,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -121,7 +121,7 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:7b055bdd6f7d40c05ccca2010c3bad7012533fcc634fc207758bb7ed61e8e5d6" + "digest": "sha256:7afab7a4adcf4ad42343450002dd53eb71234df43636b8949f246474058ceec0" }, "source": { "kind": "generated", @@ -131,7 +131,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -150,7 +150,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -169,7 +169,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -178,13 +178,13 @@ "artifactKind": "verifier", "resource": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + "digest": "sha256:c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + "digest": "sha256:c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07" } } } diff --git a/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source index 81cac630..ada72fd8 100644 --- a/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source +++ b/crates/echo-wesley-gen/assets/v1/repository/crates/echo-edict-canonical/src/lib.rs.source @@ -26,6 +26,14 @@ pub const EDICT_DIGEST_FRAME_V1: &str = "edict.digest/v1"; /// is accepted; one additional container is rejected. pub const MAX_CANONICAL_NESTING_DEPTH_V1: usize = 128; +/// Maximum number of value nodes materialized by one canonical decode. +/// +/// The root counts as one node. Array members, map keys, and map values each +/// count separately. This is an Echo host resource bound rather than part of +/// the Edict canonical byte identity; it prevents compact collection headers +/// from amplifying into unbounded host allocations before admission. +pub const MAX_CANONICAL_DECODE_NODES_V1: usize = 65_536; + /// Stable failure categories for Edict canonical values and byte streams. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum CanonicalValueErrorKind { @@ -360,11 +368,16 @@ where struct Decoder<'a> { bytes: &'a [u8], position: usize, + remaining_nodes: usize, } impl<'a> Decoder<'a> { const fn new(bytes: &'a [u8]) -> Self { - Self { bytes, position: 0 } + Self { + bytes, + position: 0, + remaining_nodes: MAX_CANONICAL_DECODE_NODES_V1, + } } const fn remaining(&self) -> usize { @@ -372,6 +385,7 @@ impl<'a> Decoder<'a> { } fn value(&mut self, depth: usize) -> Result { + self.charge_nodes(1)?; check_depth(depth)?; let initial = self.byte()?; let major = initial >> 5; @@ -401,6 +415,7 @@ impl<'a> Decoder<'a> { 4 => { check_container_depth(depth)?; let length = self.length(additional)?; + self.ensure_nodes_available(length)?; let mut values = Vec::with_capacity(length); for _ in 0..length { values.push(self.value(depth + 1)?); @@ -410,6 +425,8 @@ impl<'a> Decoder<'a> { 5 => { check_container_depth(depth)?; let length = self.length(additional)?; + let child_nodes = length.checked_mul(2).ok_or_else(node_budget_error)?; + self.ensure_nodes_available(child_nodes)?; let mut entries = Vec::with_capacity(length); let mut encoded_keys = BTreeSet::new(); for _ in 0..length { @@ -469,6 +486,21 @@ impl<'a> Decoder<'a> { checked_collection_length::(declared, remaining) } + fn ensure_nodes_available(&self, required: usize) -> Result<(), CanonicalValueError> { + if required > self.remaining_nodes { + return Err(node_budget_error()); + } + Ok(()) + } + + fn charge_nodes(&mut self, count: usize) -> Result<(), CanonicalValueError> { + self.remaining_nodes = self + .remaining_nodes + .checked_sub(count) + .ok_or_else(node_budget_error)?; + Ok(()) + } + fn byte(&mut self) -> Result { let Some(value) = self.bytes.get(self.position).copied() else { return Err(CanonicalValueError::new( @@ -504,6 +536,13 @@ impl<'a> Decoder<'a> { } } +fn node_budget_error() -> CanonicalValueError { + CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedValue, + "canonical CBOR decoded node budget exceeded", + ) +} + #[cfg(test)] mod tests { use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind}; diff --git a/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs b/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs index f02e24d5..6ca0f91b 100644 --- a/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs +++ b/crates/echo-wesley-gen/src/bin/echo-edict-provider-assets.rs @@ -364,11 +364,24 @@ fn check_package_list( .iter() .map(|file| format!("assets/v1/{}", file.relative_path())) .collect::>(); + check_package_asset_inventory(actual_assets, expected_assets) +} + +fn check_package_asset_inventory( + mut actual_assets: Vec, + mut expected_assets: Vec, +) -> Result<()> { + actual_assets.sort_unstable(); + expected_assets.sort_unstable(); if actual_assets != expected_assets { bail!( - "cargo package provider asset inventory differs: expected {} entries, found {}", + "cargo package provider asset inventory differs: expected {} entries, found {}\n\ + expected paths:\n {}\n\ + actual paths:\n {}", expected_assets.len(), - actual_assets.len() + actual_assets.len(), + expected_assets.join("\n "), + actual_assets.join("\n ") ); } Ok(()) @@ -377,13 +390,32 @@ fn check_package_list( #[cfg(test)] #[allow(clippy::expect_used)] mod tests { - use super::{load_expected_assets, ASSETS}; + use super::{check_package_asset_inventory, load_expected_assets, ASSETS}; use anyhow::Result; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicU64, Ordering}; static NEXT_TEST_DIRECTORY: AtomicU64 = AtomicU64::new(0); + #[test] + fn package_asset_inventory_ignores_listing_order_and_names_exact_drift() { + let expected = vec!["assets/v1/alpha".to_owned(), "assets/v1/bravo".to_owned()]; + check_package_asset_inventory( + vec!["assets/v1/bravo".to_owned(), "assets/v1/alpha".to_owned()], + expected.clone(), + ) + .expect("Cargo listing order does not change the selected asset inventory"); + + let error = check_package_asset_inventory( + vec!["assets/v1/alpha".to_owned(), "assets/v1/charlie".to_owned()], + expected, + ) + .expect_err("same-length asset substitution reports exact paths"); + let detail = error.to_string(); + assert!(detail.contains("assets/v1/bravo")); + assert!(detail.contains("assets/v1/charlie")); + } + #[test] fn staged_write_uses_authority_while_strict_check_requires_package_corroboration() -> Result<()> { diff --git a/crates/echo-wesley-gen/tests/provider_package_corpus.rs b/crates/echo-wesley-gen/tests/provider_package_corpus.rs index b84ea99b..1ed2ccb9 100644 --- a/crates/echo-wesley-gen/tests/provider_package_corpus.rs +++ b/crates/echo-wesley-gen/tests/provider_package_corpus.rs @@ -11,9 +11,9 @@ use std::sync::atomic::{AtomicU64, Ordering}; use sha2::{Digest as _, Sha256}; const EXPECTED_PROVIDER_DIGEST: &str = - "sha256:af5be6b5670d559ba7a7bf5867ae51c0cdd7938fcaf147167640b50f1b27b688"; + "sha256:18763560111cad22317a79dec57165affe148c4bb27f92707dbdf4b1cce07f2a"; const EXPECTED_MANIFEST_RAW_SHA256: &str = - "b7f3113c21cf50780d59b8d9d2a2829a1d185e7dc7b1eba4aa8a37d7bd820dad"; + "6ef8c85d552d7026cdbfd40681bcb14938719003277cdf5f9b37851e1a7e21b4"; const PACKAGE_PATHS: [&str; 25] = [ "components/lowerer.echo-dpo.component.wasm", diff --git a/det-policy.yaml b/det-policy.yaml index 5053da41..55fa0230 100644 --- a/det-policy.yaml +++ b/det-policy.yaml @@ -46,7 +46,7 @@ crates: echo-edict-provider-artifacts: class: DET_CRITICAL owner_role: "Tooling Engineer" - paths: ["crates/echo-wesley-gen/src/provider_*.rs", "crates/echo-wesley-gen/src/bin/echo-edict-provider-*.rs", "crates/echo-wesley-gen/tests/provider_*.rs", "crates/echo-wesley-gen/assets/v1/**", "schemas/edict-provider/**"] + paths: [".gitattributes", "crates/echo-wesley-gen/src/provider_*.rs", "crates/echo-wesley-gen/src/bin/echo-edict-provider-*.rs", "crates/echo-wesley-gen/tests/provider_*.rs", "crates/echo-wesley-gen/assets/v1/**", "schemas/edict-provider/**"] echo-edict-provider-lowerer: class: DET_CRITICAL owner_role: "Tooling Engineer" diff --git a/schemas/edict-provider/components/v1/README.md b/schemas/edict-provider/components/v1/README.md index a36c394d..d63a0dc4 100644 --- a/schemas/edict-provider/components/v1/README.md +++ b/schemas/edict-provider/components/v1/README.md @@ -22,8 +22,8 @@ is componentized with `wit-component` 0.251.0. The source WIT is the exact 7,392-byte Edict contract with SHA-256 `2971fe44def7e51d5271dfc0f04f3088aa58754cffdc847681a587605aac749e`. -The checked component is 130,679 bytes with SHA-256 -`03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e`. +The checked component is 131,156 bytes with SHA-256 +`4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee`. Its sole contract attestation is the top-level custom section `edict:target-provider-contract` containing `edict:target-provider/lowerer@1.0.0`. Its only imports are the frozen WIT's @@ -34,9 +34,9 @@ capability imports. `verifier.echo-dpo.component.wasm` implements `edict:target-provider/verifier@1.0.0`. It uses the same immutable builder, authenticated Rust/Cargo identities, frozen WIT bytes, path-remapping law, and -`wit-component` version recorded above. Its checked component is 188,736 bytes +`wit-component` version recorded above. Its checked component is 189,213 bytes with SHA-256 -`e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b`. +`c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07`. Its sole contract attestation is the top-level custom section `edict:target-provider-contract` containing `edict:target-provider/verifier@1.0.0`. Its only imports are the frozen WIT's diff --git a/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm b/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm index a85ae30a7ae2c25c4fa087952b53072333f352c5..41259f86ea5848dc81e8d597ee1093cdfaea7491 100644 GIT binary patch delta 6420 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
h7C4@HQEL;wH) delta 5979 zcmb7I3vg7`8NUD7O?H#rB^yjMBFfzb(*y(wj}3zk=7Kyzz+j=Hmd;pFR2HN{QBzyp z*dmicgaDBfEy{{ajT&h**v&ZTtSzGf0xmRYT4|fk;52rk#+mR?VeI#xb2bkjqh@Av z?*BOd`~2s>x1-v7_PnQgQij;^am$p9F(UiJ&ZOmwSx#@~_GO;8#J{$+jP?GfC(zrG zthOA>q3Kpn$M%BL6GUIf_Ial#145z*Vxvf}egg?-+jMn{Aa=CjF3iRhSW{8#F1_1!IaWmYZI>+~!i$9>!VP4~isHXJD)-H#6PX|s z34dbCEGj1Pe1UxJdb&IadYq!R2-f@-W{5KRR5{I%J7&{wWpEC;Wx*V(q#Swo94d?n zhc#Et30N#?4~59aQ?aX&N}=3htzIm!!EIZPXS!wihxs%^DATrPTBWW6&@)S2LC^)$ z1E4Dd$j%7XY7CDMY{aia(p>mF{|G}6KZ!lu~|qDV$g(4B1N3ZZ*e+XZZ4;Va@TyykT=bx zJlR)HQzvG#OYW%c34Zj5swUer8&(L1q9IhDvkz+)R#corYeQ~%bUrN`t@03zIyup> z-*#guvaE;&LmVKz(Qv?a%f%HGLN(r3LDxluosH75;Y6`3SZX2c{8Usb@}MazY6ps4 zRw*-JzwI}|g#2Fx-A-A`ZY-)m`~wBD#IK8YaAvdEooSE}>|u8R;FK-U%k`qn_V+uN zb}BC#$_BmPzeP7te!$}@(>PQ}mRx%SEsR0(Fgv?gSfzr+B7N+=P~L~V{r)o^0muLz zOHQ$c6J*)L0NB}#2^I-h1PQhqv@i}<4cQ)uvW1c1VcrZA5D$(X;^MO9j7l1dAgrjQ zCFGTFRMG>b-hpz=3U1J+VZ4QNnCp1v1Tqoiv|Sl?+7jrMs}|9yh;qf1B;z}L$>}#C zp!LIW7a#pNA#$j(vT%lca}n9G3@39P`;HtgV)uldJKeH%QsY!=h4f<*O=b#m3V*

9xpqVpj-|txfl7^VW}O&{Q9gJhEk=AQ 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 Im^bjh0Oq$q;s5{u delta 5979 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 diff --git a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json index 425401f7..9fac25c1 100644 --- a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json index 3e8c6a48..50655456 100644 --- a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:86d7daf0639a8879199f6f0a57acf7cb935a99fa40bd48afc652e3afcffaf304","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:53d9fbfaab7b8c736411f756253acb781ac1262fad7cf26e83e24a23b3a8ffdb","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm index a85ae30a7ae2c25c4fa087952b53072333f352c5..41259f86ea5848dc81e8d597ee1093cdfaea7491 100644 GIT binary patch delta 6420 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
h7C4@HQEL;wH) delta 5979 zcmb7I3vg7`8NUD7O?H#rB^yjMBFfzb(*y(wj}3zk=7Kyzz+j=Hmd;pFR2HN{QBzyp z*dmicgaDBfEy{{ajT&h**v&ZTtSzGf0xmRYT4|fk;52rk#+mR?VeI#xb2bkjqh@Av z?*BOd`~2s>x1-v7_PnQgQij;^am$p9F(UiJ&ZOmwSx#@~_GO;8#J{$+jP?GfC(zrG zthOA>q3Kpn$M%BL6GUIf_Ial#145z*Vxvf}egg?-+jMn{Aa=CjF3iRhSW{8#F1_1!IaWmYZI>+~!i$9>!VP4~isHXJD)-H#6PX|s z34dbCEGj1Pe1UxJdb&IadYq!R2-f@-W{5KRR5{I%J7&{wWpEC;Wx*V(q#Swo94d?n zhc#Et30N#?4~59aQ?aX&N}=3htzIm!!EIZPXS!wihxs%^DATrPTBWW6&@)S2LC^)$ z1E4Dd$j%7XY7CDMY{aia(p>mF{|G}6KZ!lu~|qDV$g(4B1N3ZZ*e+XZZ4;Va@TyykT=bx zJlR)HQzvG#OYW%c34Zj5swUer8&(L1q9IhDvkz+)R#corYeQ~%bUrN`t@03zIyup> z-*#guvaE;&LmVKz(Qv?a%f%HGLN(r3LDxluosH75;Y6`3SZX2c{8Usb@}MazY6ps4 zRw*-JzwI}|g#2Fx-A-A`ZY-)m`~wBD#IK8YaAvdEooSE}>|u8R;FK-U%k`qn_V+uN zb}BC#$_BmPzeP7te!$}@(>PQ}mRx%SEsR0(Fgv?gSfzr+B7N+=P~L~V{r)o^0muLz zOHQ$c6J*)L0NB}#2^I-h1PQhqv@i}<4cQ)uvW1c1VcrZA5D$(X;^MO9j7l1dAgrjQ zCFGTFRMG>b-hpz=3U1J+VZ4QNnCp1v1Tqoiv|Sl?+7jrMs}|9yh;qf1B;z}L$>}#C zp!LIW7a#pNA#$j(vT%lca}n9G3@39P`;HtgV)uldJKeH%QsY!=h4f<*O=b#m3V*

9xpqVpj-|txfl7^VW}O&{Q9gJhEk=AQ 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 Im^bjh0Oq$q;s5{u delta 5979 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 diff --git a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json index 425401f7..9fac25c1 100644 --- a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json index 3e8c6a48..50655456 100644 --- a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json +++ b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:86d7daf0639a8879199f6f0a57acf7cb935a99fa40bd48afc652e3afcffaf304","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:d17b03810ecc53f288aa1de457a5ba295c537c4f64046f8e3777b8f98ff3fc86"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:3911de5075d3709a3ba40419e4b67f1226961f3520ba9dfbbad78278c9bb0e96"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:df62a4ff2b56f9553c80cf400728cab3717f5f442c4c2fc415d2c89c21c41dad"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:8cc385a3f287ad6ea522766d7b4e92bc5164226586eef6b3f2ac6c5253370dd3"},{"coordinate":"echo.dpo@1","digest":"sha256:95626e5be6e6b2c1c8aa1858277f1c67487ab6724b08408eb3c0054adce6b1eb"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:19901cc33bea0699334af3cb4f9889f752652e35b81a2a9c91e7e31a52b803af"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:53d9fbfaab7b8c736411f756253acb781ac1262fad7cf26e83e24a23b3a8ffdb","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/provider-manifest.echo.json b/schemas/edict-provider/package/v1/provider-manifest.echo.json index 708ab173..fcecb4e1 100644 --- a/schemas/edict-provider/package/v1/provider-manifest.echo.json +++ b/schemas/edict-provider/package/v1/provider-manifest.echo.json @@ -3,7 +3,7 @@ "providerAbi": "edict:target-provider@1.0.0", "provider": { "coordinate": "echo.edict-provider@1", - "digest": "sha256:af5be6b5670d559ba7a7bf5867ae51c0cdd7938fcaf147167640b50f1b27b688" + "digest": "sha256:18763560111cad22317a79dec57165affe148c4bb27f92707dbdf4b1cce07f2a" }, "artifacts": [ { @@ -21,7 +21,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -40,7 +40,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -59,7 +59,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -78,7 +78,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -87,13 +87,13 @@ "artifactKind": "lowerer", "resource": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + "digest": "sha256:4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e" + "digest": "sha256:4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee" } } }, @@ -102,7 +102,7 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:9c64b8526c8183f1bc82507fabf2d24627d51d048d9bf98df29cec56e8648d79" + "digest": "sha256:d7422a0d7496f2d14b5c346965c9b70c86d217ea6fbae13f34accf5b1f593be8" }, "source": { "kind": "generated", @@ -112,7 +112,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -121,7 +121,7 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:7b055bdd6f7d40c05ccca2010c3bad7012533fcc634fc207758bb7ed61e8e5d6" + "digest": "sha256:7afab7a4adcf4ad42343450002dd53eb71234df43636b8949f246474058ceec0" }, "source": { "kind": "generated", @@ -131,7 +131,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -150,7 +150,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -169,7 +169,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:2cd86cb8f547bdb8a5dd0a5862d1abf28c171181b3ee2b9de6a369a175c622c8" + "digest": "sha256:d48d245a0a743575a9bb4cf8794e1afa0611ec15cc23c02e7d84c11248af533d" } } }, @@ -178,13 +178,13 @@ "artifactKind": "verifier", "resource": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + "digest": "sha256:c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b" + "digest": "sha256:c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07" } } } diff --git a/scripts/tests/classify_changes.test.cjs b/scripts/tests/classify_changes.test.cjs index 8684577f..55ef8138 100644 --- a/scripts/tests/classify_changes.test.cjs +++ b/scripts/tests/classify_changes.test.cjs @@ -142,7 +142,7 @@ test('every workspace member has an explicit non-catch-all policy path', () => { ); assert.match( policyYaml, - /echo-edict-provider-artifacts:\n\s+class: DET_CRITICAL\n\s+owner_role: "Tooling Engineer"\n\s+paths: \[.*"crates\/echo-wesley-gen\/assets\/v1\/\*\*".*"schemas\/edict-provider\/\*\*"\]\n/, + /echo-edict-provider-artifacts:\n\s+class: DET_CRITICAL\n\s+owner_role: "Tooling Engineer"\n\s+paths: \["\.gitattributes".*"crates\/echo-wesley-gen\/assets\/v1\/\*\*".*"schemas\/edict-provider\/\*\*"\]\n/, ); assert.match(policyYaml, /echo-runtime-schema:\n\s+class: DET_CRITICAL\n/); assert.match(policyYaml, /echo-file-aperture:\n\s+class: DET_IMPORTANT\n/); diff --git a/xtask/src/provider_lowerer_component.rs b/xtask/src/provider_lowerer_component.rs index a2865174..6635b195 100644 --- a/xtask/src/provider_lowerer_component.rs +++ b/xtask/src/provider_lowerer_component.rs @@ -53,7 +53,7 @@ const PINNED_CARGO_COMMIT: &str = "840b83a10fb0e039a83f4d70ad032892c287570a"; /// Reviewed identity that the portable promotion command is permitted to install. pub(crate) const APPROVED_CHECKED_COMPONENT_SHA256: &str = - "03edee44c6bc70eb998c0c17662a214809746af3bba0740f3407c18a4016309e"; + "4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee"; pub(crate) const CHECKED_COMPONENT_REPOSITORY_PATH: &str = "schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm"; @@ -62,7 +62,7 @@ pub(crate) const VERIFIER_CHECKED_COMPONENT_REPOSITORY_PATH: &str = "schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm"; /// Approved SHA-256 identity of the checked verifier component. pub(crate) const APPROVED_CHECKED_VERIFIER_COMPONENT_SHA256: &str = - "e13eda6e02d5a46d2aecdec0546d53a7bf66f2580f8d5ec06e5d76710716a27b"; + "c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07"; #[derive(Clone, Copy, Debug, Eq, PartialEq)] struct ProviderComponentSpec { From 814010b1671eb90c9981b84a43b823dbc85c9895 Mon Sep 17 00:00:00 2001 From: James Ross Date: Thu, 16 Jul 2026 15:13:21 -0700 Subject: [PATCH 6/6] Bound nested canonical container allocations --- CHANGELOG.md | 10 +++-- crates/echo-edict-canonical/README.md | 7 ++-- crates/echo-edict-canonical/src/lib.rs | 38 +++++++++++++++++- crates/echo-edict-provider-verifier/README.md | 4 +- .../lowerer.echo-dpo.component.wasm | Bin 131156 -> 131458 bytes .../verifier.echo-dpo.component.wasm | Bin 189213 -> 189515 bytes .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../package/v1/provider-manifest.echo.json | 30 +++++++------- .../echo-edict-canonical/src/lib.rs.source | 38 +++++++++++++++++- .../tests/provider_package_corpus.rs | 4 +- .../edict-provider/components/v1/README.md | 8 ++-- .../v1/lowerer.echo-dpo.component.wasm | Bin 131156 -> 131458 bytes .../v1/verifier.echo-dpo.component.wasm | Bin 189213 -> 189515 bytes .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../lowerer.echo-dpo.component.wasm | Bin 131156 -> 131458 bytes .../verifier.echo-dpo.component.wasm | Bin 189213 -> 189515 bytes .../provenance.provider-generation.json | 2 +- .../evidence/review.provider-generation.json | 2 +- .../package/v1/provider-manifest.echo.json | 30 +++++++------- xtask/src/provider_lowerer_component.rs | 4 +- 22 files changed, 128 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b1fa85f..b7d97488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,8 +86,8 @@ predicate, input-constraint, require-failure, and Core-value shapes before separating malformed artifacts from well-formed unsupported semantics, and one admitted diagnostic-ABI identity now binds both the target profile and - every emitted report. The 189,213-byte checked component has SHA-256 - `c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07` + every emitted report. The 189,515-byte checked component has SHA-256 + `11fcaf291ffacac62800ab3fc198e29a23a591bcd30ca98828fa10a8ad1f1952` and reproduces byte-for-byte across independently provisioned designated `linux/amd64` builders. The isolated pinned Edict host preflights the exact request artifacts and declared output schema, invokes that checked component, @@ -101,8 +101,10 @@ leaf. `echo-wesley-gen` retains its existing compatibility surface through a re-export, while executable provider components use the same codec without depending on generator or Wesley APIs. Its decoder now applies a 65,536-node - host materialization ceiling, charging map keys and values separately and - rejecting oversized direct containers before reserving their storage. + host materialization ceiling, charging map keys and values separately. A + matching cumulative reservation budget rejects both oversized direct + containers and nested declarations that attempt to reuse the same capacity + allowance before reserving their storage. - `echo-wesley-gen` now checks in the first exact 22-file Edict provider artifact corpus: five canonical-CBOR primaries, fourteen canonical-CBOR resources, the self-contained CDDL, Wesley provenance JSON, and diff --git a/crates/echo-edict-canonical/README.md b/crates/echo-edict-canonical/README.md index ad218d67..9fcc652e 100644 --- a/crates/echo-edict-canonical/README.md +++ b/crates/echo-edict-canonical/README.md @@ -17,9 +17,10 @@ rejects indefinite-length, tagged, floating-point, simple, non-minimal, trailing, malformed, duplicate-key, and noncanonical inputs. Both directions enforce Edict's exact 128-container nesting boundary. Decoding additionally caps one materialized value tree at 65,536 nodes, charging map keys and values -separately and rejecting oversized direct container cardinalities before host -allocation. That node ceiling is an Echo host resource bound, not a new Edict -byte-identity claim. +separately. A matching cumulative reservation budget is charged before every +container capacity allocation, so nested declarations cannot reuse the same +budget to amplify host allocation. Those ceilings are Echo host resource +bounds, not new Edict byte-identity claims. Failures expose stable `CanonicalValueErrorKind` values rather than Rust debug spellings. The implementation is deterministic and pure: it performs no diff --git a/crates/echo-edict-canonical/src/lib.rs b/crates/echo-edict-canonical/src/lib.rs index ada72fd8..53815795 100644 --- a/crates/echo-edict-canonical/src/lib.rs +++ b/crates/echo-edict-canonical/src/lib.rs @@ -369,14 +369,20 @@ struct Decoder<'a> { bytes: &'a [u8], position: usize, remaining_nodes: usize, + remaining_reserved_nodes: usize, } impl<'a> Decoder<'a> { const fn new(bytes: &'a [u8]) -> Self { + Self::with_node_budget(bytes, MAX_CANONICAL_DECODE_NODES_V1) + } + + const fn with_node_budget(bytes: &'a [u8], node_budget: usize) -> Self { Self { bytes, position: 0, - remaining_nodes: MAX_CANONICAL_DECODE_NODES_V1, + remaining_nodes: node_budget, + remaining_reserved_nodes: node_budget, } } @@ -416,6 +422,7 @@ impl<'a> Decoder<'a> { check_container_depth(depth)?; let length = self.length(additional)?; self.ensure_nodes_available(length)?; + self.reserve_nodes(length)?; let mut values = Vec::with_capacity(length); for _ in 0..length { values.push(self.value(depth + 1)?); @@ -427,6 +434,7 @@ impl<'a> Decoder<'a> { let length = self.length(additional)?; let child_nodes = length.checked_mul(2).ok_or_else(node_budget_error)?; self.ensure_nodes_available(child_nodes)?; + self.reserve_nodes(child_nodes)?; let mut entries = Vec::with_capacity(length); let mut encoded_keys = BTreeSet::new(); for _ in 0..length { @@ -501,6 +509,14 @@ impl<'a> Decoder<'a> { Ok(()) } + fn reserve_nodes(&mut self, count: usize) -> Result<(), CanonicalValueError> { + self.remaining_reserved_nodes = self + .remaining_reserved_nodes + .checked_sub(count) + .ok_or_else(node_budget_error)?; + Ok(()) + } + fn byte(&mut self) -> Result { let Some(value) = self.bytes.get(self.position).copied() else { return Err(CanonicalValueError::new( @@ -545,7 +561,7 @@ fn node_budget_error() -> CanonicalValueError { #[cfg(test)] mod tests { - use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind}; + use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind, Decoder}; #[test] fn declared_length_bounds_precede_host_width_conversion() { @@ -557,4 +573,22 @@ mod tests { )) ); } + + #[test] + fn nested_container_reservations_are_cumulatively_bounded() { + let bytes = [0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0xf6]; + let mut decoder = Decoder::with_node_budget(&bytes, 8); + + assert_eq!( + decoder.value(0), + Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedValue, + "canonical CBOR decoded node budget exceeded" + )) + ); + assert_eq!( + decoder.position, 2, + "the second container must be refused before its capacity is reserved" + ); + } } diff --git a/crates/echo-edict-provider-verifier/README.md b/crates/echo-edict-provider-verifier/README.md index 879124d5..301bf0df 100644 --- a/crates/echo-edict-provider-verifier/README.md +++ b/crates/echo-edict-provider-verifier/README.md @@ -21,9 +21,9 @@ target profile's diagnostic ABI and every emitted report consume one shared admitted identity. The `wasm32` guest adapter vendors Edict's exact frozen `edict:target-provider/verifier@1.0.0` WIT world and performs only exhaustive -transport-to-model conversion. Its reproducibly built 189,213-byte checked +transport-to-model conversion. Its reproducibly built 189,515-byte checked component has SHA-256 -`c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07`. +`11fcaf291ffacac62800ab3fc198e29a23a591bcd30ca98828fa10a8ad1f1952`. Component identity and admitted host replay remain separate propositions: the pinned Edict host preflights the request artifacts and declared output schema, invokes the checked component, then admits and manifests each returned accepted diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm index 41259f86ea5848dc81e8d597ee1093cdfaea7491..c98bfb79829c240cbef194e896777f4e6d2cc68c 100644 GIT binary patch delta 6393 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 delta 6320 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 diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm index d9622b5a9be464fb6d8ae685be464a03385cad8a..65128439be69d0f092f77127e4bbfefd3d1f830e 100644 GIT binary patch delta 8576 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 Ezm{mdN&o-= delta 8354 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 { bytes: &'a [u8], position: usize, remaining_nodes: usize, + remaining_reserved_nodes: usize, } impl<'a> Decoder<'a> { const fn new(bytes: &'a [u8]) -> Self { + Self::with_node_budget(bytes, MAX_CANONICAL_DECODE_NODES_V1) + } + + const fn with_node_budget(bytes: &'a [u8], node_budget: usize) -> Self { Self { bytes, position: 0, - remaining_nodes: MAX_CANONICAL_DECODE_NODES_V1, + remaining_nodes: node_budget, + remaining_reserved_nodes: node_budget, } } @@ -416,6 +422,7 @@ impl<'a> Decoder<'a> { check_container_depth(depth)?; let length = self.length(additional)?; self.ensure_nodes_available(length)?; + self.reserve_nodes(length)?; let mut values = Vec::with_capacity(length); for _ in 0..length { values.push(self.value(depth + 1)?); @@ -427,6 +434,7 @@ impl<'a> Decoder<'a> { let length = self.length(additional)?; let child_nodes = length.checked_mul(2).ok_or_else(node_budget_error)?; self.ensure_nodes_available(child_nodes)?; + self.reserve_nodes(child_nodes)?; let mut entries = Vec::with_capacity(length); let mut encoded_keys = BTreeSet::new(); for _ in 0..length { @@ -501,6 +509,14 @@ impl<'a> Decoder<'a> { Ok(()) } + fn reserve_nodes(&mut self, count: usize) -> Result<(), CanonicalValueError> { + self.remaining_reserved_nodes = self + .remaining_reserved_nodes + .checked_sub(count) + .ok_or_else(node_budget_error)?; + Ok(()) + } + fn byte(&mut self) -> Result { let Some(value) = self.bytes.get(self.position).copied() else { return Err(CanonicalValueError::new( @@ -545,7 +561,7 @@ fn node_budget_error() -> CanonicalValueError { #[cfg(test)] mod tests { - use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind}; + use super::{checked_collection_length, CanonicalValueError, CanonicalValueErrorKind, Decoder}; #[test] fn declared_length_bounds_precede_host_width_conversion() { @@ -557,4 +573,22 @@ mod tests { )) ); } + + #[test] + fn nested_container_reservations_are_cumulatively_bounded() { + let bytes = [0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0xf6]; + let mut decoder = Decoder::with_node_budget(&bytes, 8); + + assert_eq!( + decoder.value(0), + Err(CanonicalValueError::new( + CanonicalValueErrorKind::UnsupportedValue, + "canonical CBOR decoded node budget exceeded" + )) + ); + assert_eq!( + decoder.position, 2, + "the second container must be refused before its capacity is reserved" + ); + } } diff --git a/crates/echo-wesley-gen/tests/provider_package_corpus.rs b/crates/echo-wesley-gen/tests/provider_package_corpus.rs index 1ed2ccb9..92b29e22 100644 --- a/crates/echo-wesley-gen/tests/provider_package_corpus.rs +++ b/crates/echo-wesley-gen/tests/provider_package_corpus.rs @@ -11,9 +11,9 @@ use std::sync::atomic::{AtomicU64, Ordering}; use sha2::{Digest as _, Sha256}; const EXPECTED_PROVIDER_DIGEST: &str = - "sha256:18763560111cad22317a79dec57165affe148c4bb27f92707dbdf4b1cce07f2a"; + "sha256:38dd0532d4353f6260e8aaeafb149457b42f8ad94bb107ecbb74bf02f0051a92"; const EXPECTED_MANIFEST_RAW_SHA256: &str = - "6ef8c85d552d7026cdbfd40681bcb14938719003277cdf5f9b37851e1a7e21b4"; + "a65771b9430edd6b6ea6de727bf7569a491cfcc8bcd636d081d3e536557bfc5c"; const PACKAGE_PATHS: [&str; 25] = [ "components/lowerer.echo-dpo.component.wasm", diff --git a/schemas/edict-provider/components/v1/README.md b/schemas/edict-provider/components/v1/README.md index d63a0dc4..6cd6b3e3 100644 --- a/schemas/edict-provider/components/v1/README.md +++ b/schemas/edict-provider/components/v1/README.md @@ -22,8 +22,8 @@ is componentized with `wit-component` 0.251.0. The source WIT is the exact 7,392-byte Edict contract with SHA-256 `2971fe44def7e51d5271dfc0f04f3088aa58754cffdc847681a587605aac749e`. -The checked component is 131,156 bytes with SHA-256 -`4cb16d6017d20c8bcdbf3ca66d03becd89239872bb7632fd57345c3057cc23ee`. +The checked component is 131,458 bytes with SHA-256 +`d58a7838df9d7e65c72063aafad91df97cb21404be556c93e864234f3f846326`. Its sole contract attestation is the top-level custom section `edict:target-provider-contract` containing `edict:target-provider/lowerer@1.0.0`. Its only imports are the frozen WIT's @@ -34,9 +34,9 @@ capability imports. `verifier.echo-dpo.component.wasm` implements `edict:target-provider/verifier@1.0.0`. It uses the same immutable builder, authenticated Rust/Cargo identities, frozen WIT bytes, path-remapping law, and -`wit-component` version recorded above. Its checked component is 189,213 bytes +`wit-component` version recorded above. Its checked component is 189,515 bytes with SHA-256 -`c013636422f56d359d80437cc39499198b201e219ba4e119db096e99a1aa4f07`. +`11fcaf291ffacac62800ab3fc198e29a23a591bcd30ca98828fa10a8ad1f1952`. Its sole contract attestation is the top-level custom section `edict:target-provider-contract` containing `edict:target-provider/verifier@1.0.0`. Its only imports are the frozen WIT's diff --git a/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm b/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm index 41259f86ea5848dc81e8d597ee1093cdfaea7491..c98bfb79829c240cbef194e896777f4e6d2cc68c 100644 GIT binary patch delta 6393 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 delta 6320 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 diff --git a/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm b/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm index d9622b5a9be464fb6d8ae685be464a03385cad8a..65128439be69d0f092f77127e4bbfefd3d1f830e 100644 GIT binary patch delta 8576 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 Ezm{mdN&o-= delta 8354 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 delta 6320 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 diff --git a/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm b/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm index d9622b5a9be464fb6d8ae685be464a03385cad8a..65128439be69d0f092f77127e4bbfefd3d1f830e 100644 GIT binary patch delta 8576 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 Ezm{mdN&o-= delta 8354 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